aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortoni <matzeton@googlemail.com>2015-11-08 20:28:30 +0100
committertoni <matzeton@googlemail.com>2015-11-11 22:53:07 +0100
commitf2f6ea5029c6c43dc43d714978daca38c03a8a83 (patch)
tree745932f072a5c0246a3a3fb19ad341dcba401eed /src
parent5b73c45d46f33610fa1d99c6467e24fa7861075d (diff)
- changed dir structure
- fixed ipc semaphore/mq stuff
Diffstat (limited to 'src')
-rw-r--r--src/config.h21
-rw-r--r--src/main.c176
-rw-r--r--src/opt.c46
-rw-r--r--src/opt.h35
-rw-r--r--src/status.c29
-rw-r--r--src/status.h7
-rw-r--r--src/ui.c270
-rw-r--r--src/ui.h66
-rw-r--r--src/ui_ani.c105
-rw-r--r--src/ui_ani.h43
-rw-r--r--src/ui_elements.c151
-rw-r--r--src/ui_elements.h13
-rw-r--r--src/ui_input.c201
-rw-r--r--src/ui_input.h46
-rw-r--r--src/ui_ipc.c130
-rw-r--r--src/ui_ipc.h52
-rw-r--r--src/ui_nwindow.c157
-rw-r--r--src/ui_nwindow.h44
-rw-r--r--src/ui_statusbar.c78
-rw-r--r--src/ui_statusbar.h32
20 files changed, 1702 insertions, 0 deletions
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..a7fddc0
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,21 @@
+#define AUTHOR "Toni Uhlig"
+#define AUTHOR_EMAIL "matzeton@googlemail.com"
+#define PKGNAME "naskpass"
+#define PKGDESC "A NCurses replacement for cryptsetup's askpass."
+#define DEFAULT_FIFO "/lib/cryptsetup/passfifo"
+#define SHTDWN_CMD "echo 'o' >/proc/sysrq-trigger"
+
+#define SEM_GUI "/naskpass-gui"
+#define SEM_INP "/naskpass-input"
+#define SEM_BSY "/naskpass-busy"
+#define SEM_RDY "/naskpass-initialized"
+#define MSQ_PWD "/naskpass-passwd"
+#define MSQ_INF "/naskpass-info"
+
+#define IPC_MQSIZ 128
+
+#ifdef _VERSION
+#define VERSION _VERSION
+#else
+#define VERSION "unknown"
+#endif
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..5f0d6e9
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,176 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <semaphore.h>
+#include <time.h>
+#include <mqueue.h>
+
+#include "config.h"
+#include "opt.h"
+
+#include "ui.h"
+#include "ui_ipc.h"
+#include "ui_ani.h"
+#include "ui_input.h"
+#include "ui_statusbar.h"
+
+#define MSG(msg_idx) msg_arr[msg_idx]
+
+
+enum msg_index {
+ MSG_BUSY_FD = 0,
+ MSG_BUSY,
+ MSG_NO_FIFO,
+ MSG_FIFO_ERR,
+ MSG_FIFO_BUSY,
+ MSG_CRYPTCMD_ERR,
+ MSG_NUM
+};
+static const char *msg_arr[] = { "Please wait, got a piped password ..",
+ "Please wait, busy ..",
+ "check_fifo: %s is not a FIFO\n",
+ "check_fifo: %s error(%d): %s\n",
+ "fifo: cryptcreate busy",
+ "cryptcreate error"
+ };
+
+
+static bool
+check_fifo(char *fifo_path)
+{
+ struct stat st;
+
+ if (mkfifo(fifo_path, S_IRUSR | S_IWUSR) == 0) {
+ return (true);
+ } else {
+ if (errno == EEXIST) {
+ if (stat(fifo_path, &st) == 0) {
+ if (S_ISFIFO(st.st_mode) == 1) {
+ return (true);
+ } else {
+ fprintf(stderr, MSG(MSG_NO_FIFO), fifo_path);
+ return (false);
+ }
+ }
+ }
+ }
+ fprintf(stderr, MSG(MSG_FIFO_ERR), fifo_path, errno, strerror(errno));
+ return (false);
+}
+
+int
+run_cryptcreate(char *pass, char *crypt_cmd)
+{
+ int retval;
+ char *cmd;
+
+ if (crypt_cmd == NULL || pass == NULL) return (-1);
+ asprintf(&cmd, "echo '%s' | %s", pass, crypt_cmd);
+ retval = system(cmd);
+ free(cmd);
+ return (retval);
+}
+
+void sigfunc(int signal)
+{
+ switch (signal) {
+ case SIGTERM:
+ case SIGINT:
+ ui_ipc_semtrywait(SEM_UI);
+ ui_ipc_semtrywait(SEM_IN);
+ break;
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int ret = EXIT_FAILURE, ffd = -1, c_status;
+ pid_t child;
+ char pbuf[IPC_MQSIZ+1];
+ struct timespec ts_sem_input;
+
+ signal(SIGINT, sigfunc);
+ signal(SIGTERM, sigfunc);
+
+ if ( clock_gettime(CLOCK_REALTIME, &ts_sem_input) == -1 ) {
+ fprintf(stderr, "%s: clock get time error: %d (%s)\n", argv[0], errno, strerror(errno));
+ goto error;
+ }
+
+ if (ui_ipc_init(1) != 0) {
+ fprintf(stderr, "%s: can not create semaphore/message queue: %d (%s)\n", argv[0], errno, strerror(errno));
+ goto error;
+ }
+
+ memset(pbuf, '\0', IPC_MQSIZ+1);
+ parse_cmd(argc, argv);
+ if (check_fifo(GETOPT(FIFO_PATH).str) == false) {
+ usage(argv[0]);
+ goto error;
+ }
+ if ((ffd = open(GETOPT(FIFO_PATH).str, O_NONBLOCK | O_RDWR)) < 0) {
+ fprintf(stderr, "%s: fifo '%s' error: %d (%s)\n", argv[0], GETOPT(FIFO_PATH).str, errno, strerror(errno));
+ goto error;
+ }
+
+ ui_ipc_sempost(SEM_UI);
+ if ((child = fork()) == 0) {
+ /* child */
+ if (ffd >= 0) close(ffd);
+ fclose(stderr);
+ /* Slave process: TUI */
+ if (ui_ipc_init(0) == 0) {
+ ui_ipc_semwait(SEM_BS);
+ do_ui();
+ }
+ exit(0);
+ } else if (child > 0) {
+ /* parent */
+ fclose(stdin);
+ fclose(stdout);
+ ui_ipc_sempost(SEM_BS);
+ ui_ipc_sempost(SEM_UI);
+ /* Master process: mainloop (read passwd from message queue or fifo and exec cryptcreate */
+ while ( ui_ipc_getvalue(SEM_UI) > 0 || ui_ipc_getvalue(SEM_IN) > 0 ) {
+ ui_ipc_sempost(SEM_BS);
+ if (read(ffd, pbuf, IPC_MQSIZ) >= 0) {
+ ui_ipc_msgsend(MQ_IF, MSG(MSG_BUSY_FD), strlen(MSG(MSG_BUSY_FD)));
+ if (run_cryptcreate(pbuf, GETOPT(CRYPT_CMD).str) != 0) {
+ ui_ipc_msgsend(MQ_IF, MSG(MSG_CRYPTCMD_ERR), strlen(MSG(MSG_CRYPTCMD_ERR)));
+ }
+ } else if ( ui_ipc_msgrecv(MQ_PW, pbuf, IPC_MQSIZ) != (int)-1 ) {
+ ui_ipc_msgsend(MQ_IF, MSG(MSG_BUSY), strlen(MSG(MSG_BUSY)));
+ if (run_cryptcreate(pbuf, GETOPT(CRYPT_CMD).str) != 0) {
+ ui_ipc_msgsend(MQ_IF, MSG(MSG_CRYPTCMD_ERR), strlen(MSG(MSG_CRYPTCMD_ERR)));
+ }
+ ui_ipc_semwait(SEM_IN);
+ }
+ ui_ipc_semwait(SEM_BS);
+ usleep(100000);
+ waitpid(child, &c_status, WNOHANG);
+ if ( WIFSIGNALED(c_status) != 0 ) {
+ break;
+ }
+ }
+ wait(&c_status);
+ memset(pbuf, '\0', IPC_MQSIZ+1);
+ } else {
+ /* fork error */
+ perror("fork");
+ goto error;
+ }
+
+ ret = EXIT_SUCCESS;
+error:
+ if (ffd >= 0) close(ffd);
+ ui_ipc_free(1);
+ exit(ret);
+}
diff --git a/src/opt.c b/src/opt.c
new file mode 100644
index 0000000..7b6d083
--- /dev/null
+++ b/src/opt.c
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "config.h"
+#include "opt.h"
+
+#define CONFIG_OPT(default_val) { {0},0,{default_val} }
+
+struct opt config_opts[] = { CONFIG_OPT(DEFAULT_FIFO), CONFIG_OPT(NULL) };
+const int opt_siz = ( sizeof(config_opts)/sizeof(config_opts[0]) );
+
+
+void
+usage(char *arg0)
+{
+ fprintf(stderr, "\n%s (%s)\n %s\n", PKGNAME, VERSION, PKGDESC);
+ fprintf(stderr, " Written by %s (%s).\n", AUTHOR, AUTHOR_EMAIL);
+ fprintf(stderr, " License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n\n");
+ fprintf(stderr, " Command:\n\t%s [args]\n", arg0);
+ fprintf(stderr, " Arguments:\n\t-h this\n\t-f [passfifo] default: %s\n\t-c [cryptcreate]\n", DEFAULT_FIFO);
+}
+
+int
+parse_cmd(int argc, char **argv)
+{
+ int opt;
+
+ while ((opt = getopt(argc, argv, "hf:c:")) != -1) {
+ switch (opt) {
+ case 'h':
+ usage(argv[0]);
+ return 1;
+ case 'f':
+ s_OPT(FIFO_PATH, strdup(optarg));
+ break;
+ case 'c':
+ s_OPT(CRYPT_CMD, strdup(optarg));
+ break;
+ }
+ }
+ return 0;
+}
+
diff --git a/src/opt.h b/src/opt.h
new file mode 100644
index 0000000..6d66101
--- /dev/null
+++ b/src/opt.h
@@ -0,0 +1,35 @@
+#ifndef OPT_H
+#define OPT_H 1
+
+#define OPT(opt_index) config_opts[opt_index]
+#define GETOPT(opt_index) OPT(opt_index).opt
+#define OPT_USED(opt_index, uvalue) OPT(opt_index).found = uvalue;
+#define d_OPT(opt_index, rvalue) OPT(opt_index).opt.dec = rvalue; OPT_USED(opt_index, 1);
+#define s_OPT(opt_index, rvalue) OPT(opt_index).opt.str = rvalue; OPT_USED(opt_index, 1);
+
+union opt_entry {
+ char *str;
+ int *dec;
+};
+
+struct opt {
+ union opt_entry opt;
+ unsigned char found;
+ const union opt_entry def;
+};
+
+enum opt_index {
+ FIFO_PATH = 0,
+ CRYPT_CMD
+};
+
+
+extern struct opt config_opts[];
+
+void
+usage(char *arg0);
+
+int
+parse_cmd(int argc, char **argv);
+
+#endif
diff --git a/src/status.c b/src/status.c
new file mode 100644
index 0000000..5286ddf
--- /dev/null
+++ b/src/status.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/sysinfo.h>
+
+#include "status.h"
+
+
+char *
+get_system_stat(void)
+{
+ char *retstr = NULL;
+ int ncpu;
+ struct sysinfo inf;
+
+ if (sysinfo(&inf) == EFAULT) {
+ return ("[SYSINFO ERROR]");
+ }
+ ncpu = get_nprocs();
+
+ if (asprintf(&retstr, "u:%04ld - l:%3.2f,%3.2f,%3.2f - %dcore%s - mem:%lu/%lumb - procs:%02d",
+ inf.uptime, ((float)inf.loads[0]/10000), ((float)inf.loads[1]/10000), ((float)inf.loads[2]/10000),
+ ncpu, (ncpu > 1 ? "s" : ""),
+ (unsigned long)((inf.freeram/1024)/1024), (unsigned long)((inf.totalram/1024)/1024), inf.procs) == -1) {
+ return ("[ASPRINTF ERROR]");
+ }
+ return (retstr);
+}
diff --git a/src/status.h b/src/status.h
new file mode 100644
index 0000000..995d08a
--- /dev/null
+++ b/src/status.h
@@ -0,0 +1,7 @@
+#ifndef STATUS_H
+#define STATUS_H 1
+
+char *
+get_system_stat(void);
+
+#endif
diff --git a/src/ui.c b/src/ui.c
new file mode 100644
index 0000000..2fb5a1f
--- /dev/null
+++ b/src/ui.c
@@ -0,0 +1,270 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <string.h>
+#include <ncurses.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <signal.h>
+
+#include "ui.h"
+#include "ui_ipc.h"
+#include "ui_elements.h"
+#include "ui_ani.h"
+#include "ui_input.h"
+#include "ui_statusbar.h"
+#include "ui_nwindow.h"
+
+#include "status.h"
+#include "config.h"
+
+#define APP_TIMEOUT 60
+#define APP_TIMEOUT_FMT "%02d"
+#define PASSWD_WIDTH 35
+#define PASSWD_HEIGHT 5
+#define PASSWD_XRELPOS (unsigned int)(PASSWD_WIDTH / 2) - (PASSWD_WIDTH / 6)
+#define PASSWD_YRELPOS (unsigned int)(PASSWD_HEIGHT / 2) + 1
+#define INFOWND_WIDTH 25
+#define INFOWND_HEIGHT 3
+#define INFOWND_XRELPOS (unsigned int)(INFOWND_WIDTH / 2) - (INFOWND_WIDTH / 6)
+#define INFOWND_YRELPOS (unsigned int)(INFOWND_HEIGHT / 2) + 1
+
+#define STRLEN(s) (sizeof(s)/sizeof(s[0]))
+
+
+static unsigned int max_x, max_y;
+static WINDOW *wnd_main;
+static struct nask_ui /* simple linked list to all UI objects */ *nui = NULL,
+ /* current active input */ *active = NULL;
+static pthread_t thrd;
+static unsigned int atmout = APP_TIMEOUT;
+static pthread_cond_t cnd_update = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mtx_update = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t mtx_busy = PTHREAD_MUTEX_INITIALIZER;
+
+
+void
+register_ui_elt(struct ui_callbacks *cbs, void *data, WINDOW *wnd)
+{
+ struct nask_ui *tmp, *new;
+
+ new = calloc(1, sizeof(struct nask_ui));
+ new->cbs = *cbs;
+ new->wnd = wnd;
+ new->data = data;
+ new->next = NULL;
+ if (nui == NULL) {
+ nui = new;
+ nui->next = NULL;
+ } else {
+ tmp = nui;
+ while (tmp->next != NULL) {
+ tmp = tmp->next;
+ }
+ tmp->next = new;
+ }
+}
+
+void
+unregister_ui_elt(void *data)
+{
+ struct nask_ui *cur, *next, *before = NULL;
+
+ cur = nui;
+ while (cur != NULL) {
+ next = cur->next;
+ if (cur->data != NULL && cur->data == data) {
+ free(cur);
+ if (before != NULL) {
+ before->next = next;
+ } else {
+ nui = next;
+ }
+ }
+ before = cur;
+ cur = next;
+ }
+}
+
+int
+activate_ui_input(void *data)
+{
+ struct nask_ui *cur = nui;
+
+ if (cur == NULL || data == NULL) return DOUI_NINIT;
+ while ( cur->data != NULL ) {
+ if ( cur->data == data ) {
+ if ( cur->cbs.ui_input != NULL && cur->cbs.ui_input(cur->wnd, data, UIKEY_ACTIVATE) == DOUI_OK ) {
+ active = cur;
+ return DOUI_OK;
+ }
+ }
+ cur = cur->next;
+ }
+ return DOUI_ERR;
+}
+
+int
+reactivate_ui_input(void)
+{
+ if (active) {
+ if (active->cbs.ui_element) {
+ }
+ return ( active->cbs.ui_input(active->wnd, active->data, UIKEY_ACTIVATE) );
+ } else return DOUI_ERR;
+}
+
+static bool
+process_key(char key)
+{
+ atmout = APP_TIMEOUT;
+ if ( active != NULL ) {
+ return ( active->cbs.ui_input(active->wnd, active->data, key) == DOUI_OK ? true : false );
+ }
+ return false;
+}
+
+static int
+do_ui_update(bool timed_out)
+{
+ int retval = UICB_OK;
+ int curx = getcurx(wnd_main);
+ int cury = getcury(wnd_main);
+ struct nask_ui *cur = nui;
+
+ /* call all draw callback's */
+ erase();
+ while (cur != NULL) {
+ if (cur->cbs.ui_element != NULL) {
+ cur->cbs.ui_element(cur->wnd, cur->data, timed_out);
+ doupdate();
+ } else {
+ retval = UICB_ERR_CB;
+ }
+ cur = cur->next;
+ }
+ /* TODO: Maybe export to an extra module? */
+ attron(COLOR_PAIR(1));
+ mvprintw(0, max_x - STRLEN(APP_TIMEOUT_FMT), "[" APP_TIMEOUT_FMT "]", atmout);
+ attroff(COLOR_PAIR(1));
+ /* EoT (End of Todo) */
+ wmove(wnd_main, cury, curx);
+ wrefresh(wnd_main);
+ return (retval);
+}
+
+static void *
+ui_thrd(void *arg)
+{
+ int cnd_ret;
+ struct timeval now;
+ struct timespec wait;
+
+ gettimeofday(&now, NULL);
+ wait.tv_sec = now.tv_sec + UILOOP_TIMEOUT;
+ wait.tv_nsec = now.tv_usec * 1000;
+ do_ui_update(true);
+ ui_ipc_sempost(SEM_RD);
+ pthread_mutex_lock(&mtx_update);
+ while ( ui_ipc_getvalue(SEM_UI) > 0 ) {
+ pthread_mutex_unlock(&mtx_busy);
+ cnd_ret = pthread_cond_timedwait(&cnd_update, &mtx_update, &wait);
+ pthread_mutex_lock(&mtx_busy);
+ if (--atmout == 0) ui_ipc_semtrywait(SEM_UI);
+ do_ui_update( (cnd_ret == ETIMEDOUT ? true : false) );
+ if (cnd_ret == ETIMEDOUT) {
+ wait.tv_sec += UILOOP_TIMEOUT;
+ }
+ }
+ pthread_mutex_unlock(&mtx_update);
+ return (NULL);
+}
+
+void
+ui_thrd_force_update(void)
+{
+ pthread_mutex_lock(&mtx_busy);
+ pthread_cond_signal(&cnd_update);
+ pthread_mutex_unlock(&mtx_busy);
+}
+
+WINDOW *
+init_ui(void)
+{
+ wnd_main = initscr();
+ max_x = getmaxx(wnd_main);
+ max_y = getmaxy(wnd_main);
+ start_color();
+ init_pair(1, COLOR_RED, COLOR_WHITE);
+ init_pair(2, COLOR_WHITE, COLOR_BLACK);
+ init_pair(3, COLOR_BLACK, COLOR_WHITE);
+ init_pair(4, COLOR_YELLOW, COLOR_RED);
+ raw();
+ keypad(stdscr, TRUE);
+ noecho();
+ cbreak();
+ return (wnd_main);
+}
+
+void
+free_ui(void)
+{
+ delwin(wnd_main);
+ endwin();
+ clear();
+ printf(" \033[2J\n");
+}
+
+static int
+run_ui_thrd(void) {
+ return (pthread_create(&thrd, NULL, &ui_thrd, NULL));
+}
+
+static int
+stop_ui_thrd(void)
+{
+ return (pthread_join(thrd, NULL));
+}
+
+int
+do_ui(void)
+{
+ char key = '\0';
+ int ret = DOUI_ERR;
+
+ /* init TUI and UI Elements (input field, status bar, etc) */
+ init_ui();
+ init_ui_elements(wnd_main, max_x, max_y);
+
+ pthread_mutex_lock(&mtx_update);
+ if (run_ui_thrd() != 0) {
+ return ret;
+ }
+ ui_ipc_semwait(SEM_RD);
+ wtimeout(wnd_main, 1000);
+ pthread_mutex_unlock(&mtx_update);
+ while ( ui_ipc_getvalue(SEM_UI) > 0 ) {
+ if ((key = wgetch(wnd_main)) == '\0') {
+ break;
+ }
+ if (key == -1) {
+ continue;
+ }
+ if ( process_key(key) != true ) {
+ ui_ipc_semtrywait(SEM_UI);
+ ui_thrd_force_update();
+ }
+ }
+ stop_ui_thrd();
+ free_ui_elements();
+
+ return DOUI_OK;
+}
+
diff --git a/src/ui.h b/src/ui.h
new file mode 100644
index 0000000..91d5403
--- /dev/null
+++ b/src/ui.h
@@ -0,0 +1,66 @@
+#ifndef UI_H
+#define UI_H 1
+
+#include <ncurses.h>
+#include <stdint.h>
+
+#define UICB_OK 0
+#define UICB_ERR_UNDEF 1
+#define UICB_ERR_CB 2
+#define UICB_ERR_BUF 3
+
+#define DOUI_OK 0
+#define DOUI_ERR 1
+#define DOUI_TMOUT 2
+#define DOUI_NINIT 3
+
+#define UILOOP_TIMEOUT 1
+
+#define UIKEY_ACTIVATE 0
+#define UIKEY_ENTER 10
+#define UIKEY_BACKSPACE 7
+#define UIKEY_ESC 27
+#define UIKEY_DOWN 2
+#define UIKEY_UP 3
+#define UIKEY_LEFT 4
+#define UIKEY_RIGHT 5
+
+
+typedef int (*uicb_base)(WINDOW *, void *, bool);
+typedef int (*uicb_input)(WINDOW *, void *, int);
+
+
+struct ui_callbacks {
+ uicb_base ui_element;
+ uicb_input ui_input;
+};
+
+struct nask_ui {
+ struct ui_callbacks cbs;
+ WINDOW *wnd;
+ void *data;
+ struct nask_ui *next;
+};
+
+void
+register_ui_elt(struct ui_callbacks *cbs, void *data, WINDOW *wnd);
+
+void
+unregister_ui_elt(void *data);
+
+int
+activate_ui_input(void *data);
+
+void
+ui_thrd_force_update(void);
+
+WINDOW *
+init_ui(void);
+
+void
+free_ui(void);
+
+int
+do_ui(void);
+
+#endif
diff --git a/src/ui_ani.c b/src/ui_ani.c
new file mode 100644
index 0000000..d1f1073
--- /dev/null
+++ b/src/ui_ani.c
@@ -0,0 +1,105 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "ui.h"
+#include "ui_ani.h"
+
+#define ANIC_INITSTATE '|'
+
+
+struct anic *
+init_anic_default(unsigned int x, unsigned int y, chtype attrs, char *fmt)
+{
+ struct anic *a = init_anic(x, y, attrs, anic_cb);
+ struct anic_default *b = calloc(1, sizeof(struct anic_default));
+
+ a->data = (void *) b;
+ b->state = ANIC_INITSTATE;
+ if (fmt != NULL) {
+ b->fmt = strdup(fmt);
+ }
+ return (a);
+}
+
+struct anic *
+init_anic(unsigned int x, unsigned int y, chtype attrs, uicb_anic uicb)
+{
+ struct anic *a = calloc(1, sizeof(struct anic));
+
+ a->x = x;
+ a->y = y;
+ a->uicb = uicb;
+ a->attrs = attrs;
+ return (a);
+}
+
+void
+free_anic(struct anic *a)
+{
+ free(a);
+}
+
+void
+free_anic_default(struct anic *a)
+{
+ struct anic_default *b;
+
+ if (a->data != NULL) {
+ b = (struct anic_default *) a->data;
+ free(b->fmt);
+ free(b);
+ }
+ free_anic(a);
+}
+
+int
+anic_cb(WINDOW *win, void *data, bool timed_out)
+{
+ struct anic *a = (struct anic *) data;
+ struct anic_default *b;
+ char *tmp;
+ int retval = UICB_OK;
+
+ if (a == NULL) return (UICB_ERR_UNDEF);
+ b = (struct anic_default *) a->data;
+ if (timed_out == true) {
+ switch (b->state) {
+ default:
+ case '|': b->state = '/'; break;
+ case '/': b->state = '-'; break;
+ case '-': b->state = '\\'; break;
+ case '\\': b->state = '|'; break;
+ }
+ }
+ attron(a->attrs);
+ if (b->fmt != NULL) {
+ if (asprintf(&tmp, b->fmt, b->state) <= 0) {
+ retval = UICB_ERR_BUF;
+ }
+ } else {
+ asprintf(&tmp, "%c", b->state);
+ }
+ if (win != NULL) {
+ mvwprintw(win, a->y, a->x, tmp);
+ } else {
+ mvprintw(a->y, a->x, tmp);
+ }
+ free(tmp);
+ attroff(a->attrs);
+ return (retval);
+}
+
+void
+register_anic(struct anic *a, uicb_anic uicb)
+{
+ struct ui_callbacks cbs;
+ cbs.ui_element = uicb;
+ cbs.ui_input = NULL;
+ register_ui_elt(&cbs, (void *) a, NULL);
+}
+
+void
+register_anic_default(struct anic *a)
+{
+ register_anic(a, anic_cb);
+}
diff --git a/src/ui_ani.h b/src/ui_ani.h
new file mode 100644
index 0000000..3d6ece2
--- /dev/null
+++ b/src/ui_ani.h
@@ -0,0 +1,43 @@
+#ifndef UI_ANIC_H
+#define UI_ANIC_H 1
+
+#include <ncurses.h>
+
+
+typedef int (*uicb_anic)(WINDOW *, void *, bool);
+
+struct anic_default {
+ char state;
+ char *fmt;
+};
+
+struct anic {
+ unsigned int x;
+ unsigned int y;
+ uicb_anic uicb;
+ void *data;
+ chtype attrs;
+};
+
+struct anic *
+init_anic_default(unsigned int x, unsigned int y, chtype attrs, char *fmt);
+
+struct anic *
+init_anic(unsigned int x, unsigned int y, chtype attrs, uicb_anic uicb);
+
+void
+free_anic_default(struct anic *a);
+
+void
+free_anic(struct anic *a);
+
+int
+anic_cb(WINDOW *win, void *data, bool timed_out);
+
+void
+register_anic(struct anic *a, uicb_anic uicb);
+
+void
+register_anic_default(struct anic *a);
+
+#endif
diff --git a/src/ui_elements.c b/src/ui_elements.c
new file mode 100644
index 0000000..29c2e32
--- /dev/null
+++ b/src/ui_elements.c
@@ -0,0 +1,151 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ui.h"
+#include "ui_ipc.h"
+#include "ui_ani.h"
+#include "ui_input.h"
+#include "ui_statusbar.h"
+#include "ui_nwindow.h"
+#include "ui_elements.h"
+
+#include "status.h"
+
+#define PASSWD_WIDTH 35
+#define PASSWD_HEIGHT 5
+#define PASSWD_XRELPOS (unsigned int)(PASSWD_WIDTH / 2) - (PASSWD_WIDTH / 6)
+#define PASSWD_YRELPOS (unsigned int)(PASSWD_HEIGHT / 2) + 1
+#define INFOWND_WIDTH 25
+#define INFOWND_HEIGHT 3
+#define INFOWND_XRELPOS (unsigned int)(INFOWND_WIDTH / 2) - (INFOWND_WIDTH / 6)
+#define INFOWND_YRELPOS (unsigned int)(INFOWND_HEIGHT / 2) + 1
+
+static struct input *pw_input;
+static struct anic *heartbeat;
+static struct statusbar *higher, *lower;
+static struct txtwindow *infownd;
+static char *title = NULL;
+
+
+static int
+lower_statusbar_update(WINDOW *win, struct statusbar *bar)
+{
+ char *tmp = get_system_stat();
+ set_statusbar_text(bar, tmp);
+ free(tmp);
+ return 0;
+}
+
+static int
+higher_statusbar_update(WINDOW *win, struct statusbar *bar)
+{
+ return 0;
+}
+
+static int
+infownd_update(WINDOW *win, struct txtwindow *tw)
+{
+ char *tmp = (char*)(tw->userptr);
+ size_t len = strlen(tmp);
+
+ if (tw->active) {
+ if ( len == 3 ) {
+ memset(tmp+1, '\0', 2);
+ } else strcat(tmp, ".");
+ } else (*tmp) = '.';
+ return 0;
+}
+
+static int
+mq_passwd_send(char *passwd, size_t len)
+{
+ int ret;
+
+ ui_ipc_sempost(SEM_IN);
+ ret = ui_ipc_msgsend(MQ_PW, passwd, len);
+ return ret;
+}
+
+static int
+passwd_input_cb(WINDOW *wnd, void *data, int key)
+{
+ struct input *a = (struct input *) data;
+/*
+ * if ( process_key(key, pw_input, wnd_main) == false ) {
+ * curs_set(0);
+ * memset(mq_msg, '\0', IPC_MQSIZ+1);
+ * mq_receive(mq_info, mq_msg, IPC_MQSIZ+1, 0);
+ * set_txtwindow_text(infownd, mq_msg);
+ * set_txtwindow_active(infownd, true);
+ * sleep(3);
+ * sem_trywait(sp_ui);
+ * }
+ * activate_input(wnd_main, pw_input);
+ */
+ switch (key) {
+ case UIKEY_ENTER:
+ mq_passwd_send(a->input, a->input_len);
+ clear_input(wnd, a);
+ set_txtwindow_text(infownd, "BLA");
+ set_txtwindow_active(infownd, true);
+ break;
+ case UIKEY_BACKSPACE:
+ del_input(wnd, a);
+ break;
+ case UIKEY_ESC:
+ return DOUI_ERR;
+ case UIKEY_DOWN:
+ case UIKEY_UP:
+ case UIKEY_LEFT:
+ case UIKEY_RIGHT:
+ break;
+ case UIKEY_ACTIVATE:
+ break;
+ default:
+ add_input(wnd, a, key);
+ }
+ return DOUI_OK;
+}
+
+void
+init_ui_elements(WINDOW *wnd_main, unsigned int max_x, unsigned int max_y)
+{
+ asprintf(&title, "/* %s-%s */", PKGNAME, VERSION);
+ pw_input = init_input((unsigned int)(max_x / 2)-PASSWD_XRELPOS, (unsigned int)(max_y / 2)-PASSWD_YRELPOS, PASSWD_WIDTH, "PASSWORD: ", IPC_MQSIZ, COLOR_PAIR(3), COLOR_PAIR(2));
+ heartbeat = init_anic_default(0, 0, A_BOLD | COLOR_PAIR(1), "[%c]");
+ higher = init_statusbar(0, max_x, A_BOLD | COLOR_PAIR(3), higher_statusbar_update);
+ lower = init_statusbar(max_y - 1, max_x, COLOR_PAIR(3), lower_statusbar_update);
+ infownd = init_txtwindow((unsigned int)(max_x / 2)-INFOWND_XRELPOS, (unsigned int)(max_y / 2)-INFOWND_YRELPOS, INFOWND_WIDTH, INFOWND_HEIGHT, COLOR_PAIR(4), COLOR_PAIR(4) | A_BOLD, infownd_update);
+ infownd->userptr = calloc(4, sizeof(char));
+ (*(char*)(infownd->userptr)) = '.';
+
+ register_input(NULL, pw_input, passwd_input_cb);
+ register_statusbar(higher);
+ register_statusbar(lower);
+ register_anic_default(heartbeat);
+ register_txtwindow(infownd);
+ set_txtwindow_title(infownd, "WARNING");
+ activate_input(wnd_main, pw_input);
+ set_statusbar_text(higher, title);
+}
+
+void
+free_ui_elements(void)
+{
+ unregister_ui_elt(lower);
+ unregister_ui_elt(higher);
+ unregister_ui_elt(heartbeat);
+ unregister_ui_elt(pw_input);
+ free_input(pw_input);
+ free_anic_default(heartbeat);
+ free_statusbar(higher);
+ free_statusbar(lower);
+ free(infownd->userptr);
+ free_txtwindow(infownd);
+ free_ui();
+ if (title) {
+ free(title);
+ title = NULL;
+ }
+}
diff --git a/src/ui_elements.h b/src/ui_elements.h
new file mode 100644
index 0000000..0cf8826
--- /dev/null
+++ b/src/ui_elements.h
@@ -0,0 +1,13 @@
+#ifndef UI_ELEMENTS_H
+#define UI_ELEMENTS_H 1
+
+#include "config.h"
+
+
+void
+init_ui_elements(WINDOW *wnd_main, unsigned int max_x, unsigned int max_y);
+
+void
+free_ui_elements(void);
+
+#endif
diff --git a/src/ui_input.c b/src/ui_input.c
new file mode 100644
index 0000000..5f9a679
--- /dev/null
+++ b/src/ui_input.c
@@ -0,0 +1,201 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "ui.h"
+#include "ui_input.h"
+
+
+struct input *
+init_input(unsigned int x, unsigned int y, unsigned int width, char *prompt, size_t input_len, chtype attrs, chtype shadow)
+{
+ struct input *a = calloc(1, sizeof(struct input));
+
+ a->x = x;
+ a->y = y;
+ a->width = width;
+ a->cur_pos = 0;
+ a->input = calloc(input_len+1, sizeof(char));
+ a->input_max = input_len;
+ a->input_len = 0;
+ a->input_pos = 0;
+ a->prompt = strdup(prompt);
+ a->attrs = attrs;
+ a->shadow = shadow;
+ return (a);
+}
+
+void
+free_input(struct input *a)
+{
+ if (a->input != NULL) {
+ free(a->input);
+ }
+ free(a->prompt);
+ free(a);
+}
+
+static void
+print_wnd(size_t addwidth, struct input *a)
+{
+ int i, x = a->x, y = a->y;
+ size_t relwidth = addwidth*2, len = strlen(a->prompt) + a->width;
+ char tmp[len+relwidth+1];
+
+ attron(a->attrs);
+ memset(tmp, ' ', len+relwidth);
+ tmp[len+relwidth] = '\0';
+ for (i = -1; i <= 1; i++)
+ mvprintw(y+i, x-addwidth, tmp);
+
+ mvhline(y-2, x-addwidth, 0, len+relwidth);
+ mvhline(y+2, x-addwidth, 0, len+relwidth);
+ mvvline(y-1, x-addwidth-1, 0, 3);
+ mvvline(y-1, x+len+addwidth, 0, 3);
+ mvaddch(y-2, x-addwidth-1, ACS_ULCORNER);
+ mvaddch(y+2, x-addwidth-1, ACS_LLCORNER);
+ mvaddch(y-2, x+len+addwidth, ACS_URCORNER);
+ mvaddch(y+2, x+len+addwidth, ACS_LRCORNER);
+ attroff(a->attrs);
+
+ attron(a->shadow);
+ for (i = x-addwidth+1; i < x+len+relwidth; i++)
+ mvaddch(y+3, i, ACS_CKBOARD);
+ for (i = -1; i < 3; i++) {
+ mvaddch(y+i, x+len+relwidth-2, ACS_CKBOARD);
+ mvaddch(y+i, x+len+relwidth-1, ACS_CKBOARD);
+ }
+ attroff(a->shadow);
+}
+
+static void
+print_input_text(WINDOW *win, struct input *a)
+{
+ size_t start = 0;
+ size_t p_len = strlen(a->prompt);
+
+ char tmp[a->width + 1];
+ memset(tmp, '\0', a->width + 1);
+ if (a->input_pos >= a->width) {
+ start = a->input_pos - a->width;
+ }
+
+ strncpy(tmp, (char *)(a->input + start), a->width);
+ int i;
+ for (i = 0; i < strlen(tmp); i++) {
+ tmp[i] = '*';
+ }
+
+ if (win == NULL) {
+ mvprintw(a->y, a->x + p_len, "%s", tmp);
+ } else {
+ mvwprintw(win, a->y, a->x + p_len, "%s", tmp);
+ }
+}
+
+static void
+print_input(WINDOW *win, struct input *a)
+{
+ char *tmp;
+ int i;
+ size_t p_len = strlen(a->prompt);
+
+ print_wnd(3, a);
+ attron(a->attrs);
+ if (win) {
+ mvwprintw(win, a->y, a->x, a->prompt);
+ } else {
+ mvprintw(a->y, a->x, a->prompt);
+ }
+ tmp = calloc(a->width+1, sizeof(char));
+ for (i = 0; i < a->width; i++) {
+ *(tmp + i) = '_';
+ }
+ if (win) {
+ mvwprintw(win, a->y, a->x + p_len, tmp);
+ } else {
+ mvprintw(a->y, a->x + p_len, tmp);
+ }
+ free(tmp);
+ print_input_text(win, a);
+ attroff(a->attrs);
+}
+
+int
+activate_input(WINDOW *win, struct input *a)
+{
+ if (a == NULL) return (UICB_ERR_UNDEF);
+ size_t p_len = strlen(a->prompt);
+ if (win == NULL) {
+ move(a->y, a->x + p_len + a->cur_pos);
+ } else {
+ wmove(win, a->y, a->x + p_len + a->cur_pos);
+ }
+ return (activate_ui_input( (void *) a ));
+}
+
+int
+add_input(WINDOW *win, struct input *a, int key)
+{
+ if (a == NULL) return (UICB_ERR_UNDEF);
+ if (a->input_len >= a->input_max) return (UICB_ERR_BUF);
+ *(a->input + a->input_pos) = (char) key;
+ ++a->input_pos;
+ ++a->input_len;
+ a->cur_pos = (a->cur_pos+1 < a->width ? a->cur_pos+1 : a->cur_pos);
+ print_input(win, a);
+ return (UICB_OK);
+}
+
+int
+del_input(WINDOW *win, struct input *a)
+{
+ if (a == NULL) return (UICB_ERR_UNDEF);
+ if (a->input_len == 0) return (UICB_ERR_BUF);
+ memmove((a->input + a->input_pos - 1), (a->input + a->input_pos), a->input_max - a->input_pos);
+ --a->input_len;
+ *(a->input + a->input_len) = '\0';
+ if (a->input_pos-1 == a->input_len) {
+ --a->input_pos;
+ }
+ if (a->cur_pos+1 < a->width && a->cur_pos > 0) {
+ --a->cur_pos;
+ } else if (a->cur_pos-1 == a->input_pos) {
+ --a->cur_pos;
+ }
+ mvwprintw(win, a->y, a->x + a->cur_pos + strlen(a->prompt), "_");
+ print_input(win, a);
+ return (UICB_OK);
+}
+
+int
+clear_input(WINDOW *win, struct input *a)
+{
+ if (a == NULL) return (UICB_ERR_UNDEF);
+ memset(a->input, '\0', a->input_max);
+ a->input_len = 0;
+ a->input_pos = 0;
+ a->cur_pos = 0;
+ print_input(win, a);
+ return (UICB_OK);
+}
+
+static int
+input_cb(WINDOW *win, void *data, bool timed_out)
+{
+ struct input *a = (struct input *) data;
+
+ if (a == NULL) return (UICB_ERR_UNDEF);
+ if (win != NULL && is_wintouched(win) == false) return (UICB_OK);
+ print_input(win, a);
+ return (UICB_OK);
+}
+
+void
+register_input(WINDOW *win, struct input *a, uicb_input ipcb)
+{
+ struct ui_callbacks cbs;
+ cbs.ui_element = input_cb;
+ cbs.ui_input = ipcb;
+ register_ui_elt(&cbs, (void *) a, win);
+}
+
diff --git a/src/ui_input.h b/src/ui_input.h
new file mode 100644
index 0000000..657c926
--- /dev/null
+++ b/src/ui_input.h
@@ -0,0 +1,46 @@
+#ifndef UI_INPUT_H
+#define UI_INPUT_H 1
+
+#include <ncurses.h>
+
+
+struct input {
+ unsigned int x;
+ unsigned int y;
+ unsigned int width;
+ unsigned int cur_pos;
+ char *input;
+ size_t input_max;
+ size_t input_len;
+ size_t input_pos;
+ char *prompt;
+ chtype attrs;
+ chtype shadow;
+ uicb_input cb_input;
+};
+
+struct input *
+init_input(unsigned int x, unsigned int y, unsigned int width, char *prompt, size_t input_len, chtype attrs, chtype shadow);
+
+void
+free_input(struct input *a);
+
+int
+activate_input(WINDOW *win, struct input *a);
+
+int
+add_input(WINDOW *win, struct input *a, int key);
+
+int
+del_input(WINDOW *win, struct input *a);
+
+int
+clear_input(WINDOW *win, struct input *a);
+
+void
+register_input(WINDOW *win, struct input *a, uicb_input ipcb);
+
+void
+unregister_input(struct input *a);
+
+#endif
diff --git a/src/ui_ipc.c b/src/ui_ipc.c
new file mode 100644
index 0000000..9eac79e
--- /dev/null
+++ b/src/ui_ipc.c
@@ -0,0 +1,130 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#ifdef SEM_TIMEDWAIT
+#include <time.h>
+#endif
+#include <semaphore.h>
+#include <mqueue.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "ui_ipc.h"
+
+#define JMP_IF(cmd, retval, jmplabel) if ( (cmd) == retval ) { printf("(%s) == %p\n", #cmd, (void*)retval); goto jmplabel; }
+
+
+static sem_t *sems[SEM_NUM];
+static mqd_t msqs[MSQ_NUM];
+
+
+int
+ui_ipc_init(int is_master)
+{
+ volatile int sp_oflags, mq_oflags;
+ mode_t crt_flags;
+ struct mq_attr m_attr;
+
+ bzero(sems, sizeof(sem_t*)*SEM_NUM);
+ bzero(msqs, sizeof(mqd_t)*MSQ_NUM);
+ m_attr.mq_flags = 0;
+ m_attr.mq_msgsize = IPC_MQSIZ;
+ m_attr.mq_maxmsg = 3;
+ m_attr.mq_curmsgs = 0;
+ if (is_master) {
+ sp_oflags = O_CREAT | O_EXCL;
+ mq_oflags = O_NONBLOCK | O_CREAT | O_EXCL;
+ crt_flags = S_IRUSR | S_IWUSR;
+ JMP_IF( msqs[MQ_PW] = mq_open(MSQ_PWD, mq_oflags | O_RDONLY, crt_flags, &m_attr), (mqd_t)-1, error );
+ JMP_IF( msqs[MQ_IF] = mq_open(MSQ_INF, mq_oflags | O_WRONLY, crt_flags, &m_attr), (mqd_t)-1, error );
+ } else {
+ sp_oflags = 0;
+ mq_oflags = 0;
+ crt_flags = 0;
+ JMP_IF( msqs[MQ_PW] = mq_open(MSQ_PWD, mq_oflags | O_WRONLY, crt_flags, &m_attr), (mqd_t)-1, error );
+ JMP_IF( msqs[MQ_IF] = mq_open(MSQ_INF, mq_oflags | O_RDONLY, crt_flags, &m_attr), (mqd_t)-1, error );
+ }
+ JMP_IF( sems[SEM_UI] = sem_open(SEM_GUI, sp_oflags, crt_flags, 0), SEM_FAILED, error );
+ JMP_IF( sems[SEM_IN] = sem_open(SEM_INP, sp_oflags, crt_flags, 0), SEM_FAILED, error );
+ JMP_IF( sems[SEM_BS] = sem_open(SEM_BSY, sp_oflags, crt_flags, 0), SEM_FAILED, error );
+ JMP_IF( sems[SEM_RD] = sem_open(SEM_RDY, sp_oflags, crt_flags, 0), SEM_FAILED, error );
+ return 0;
+error:
+ return errno;
+}
+
+void
+ui_ipc_free(int is_master)
+{
+ int i;
+
+ for (i = 0; i < SEM_NUM; i++) {
+ if (sems[i]) sem_close(sems[i]);
+ }
+ for (i = 0; i < MSQ_NUM; i++) {
+ if (msqs[i]) mq_close(msqs[i]);
+ }
+ if (is_master > 0) {
+ sem_unlink(SEM_BSY);
+ sem_unlink(SEM_GUI);
+ sem_unlink(SEM_INP);
+ sem_unlink(SEM_RDY);
+ mq_unlink(MSQ_PWD);
+ mq_unlink(MSQ_INF);
+ }
+}
+
+int
+ui_ipc_sempost(enum UI_IPC_SEM e_sp)
+{
+ return ( sem_post(sems[e_sp]) );
+}
+
+int
+ui_ipc_semwait(enum UI_IPC_SEM e_sp)
+{
+ return ( sem_wait(sems[e_sp]) );
+}
+
+int
+ui_ipc_semtrywait(enum UI_IPC_SEM e_sp)
+{
+ return ( sem_trywait(sems[e_sp]) );
+}
+
+int
+ui_ipc_getvalue(enum UI_IPC_SEM e_sp)
+{
+ int sp_val = 0;
+
+ if (sem_getvalue(sems[e_sp], &sp_val) != 0) {
+ return -1;
+ }
+ return sp_val;
+}
+
+#ifdef SEM_TIMEDWAIT
+int
+ui_ipc_semtimedwait(enum UI_IPC_SEM e_sp, int timeout)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
+ return -1;
+ }
+ ts.tc_sec += timeout;
+ return ( sem_timedwait(sems[q_mq], &ts) );
+}
+#endif
+
+int
+ui_ipc_msgsend(enum UI_IPC_MSQ e_mq, const char *msg_ptr, size_t msg_len)
+{
+ return ( mq_send(msqs[e_mq], msg_ptr, msg_len, 0) );
+}
+
+ssize_t
+ui_ipc_msgrecv(enum UI_IPC_MSQ e_mq, char *msg_ptr, size_t msg_len)
+{
+ return ( mq_receive(msqs[e_mq], msg_ptr, msg_len, NULL) );
+}
+
diff --git a/src/ui_ipc.h b/src/ui_ipc.h
new file mode 100644
index 0000000..2c5bcb5
--- /dev/null
+++ b/src/ui_ipc.h
@@ -0,0 +1,52 @@
+#ifndef UI_IPC_H
+#define UI_IPC_H 1
+
+#include "status.h"
+#include "config.h"
+
+
+enum UI_IPC_SEM {
+ SEM_RD = 0, /* UI Init done? */
+ SEM_UI, /* TUI active? */
+ SEM_IN, /* Textfield has input avail */
+ SEM_BS, /* Master process busy */
+ SEM_NUM
+};
+
+enum UI_IPC_MSQ {
+ MQ_PW = 0,
+ MQ_IF,
+ MSQ_NUM
+};
+
+
+int
+ui_ipc_init(int is_master);
+
+void
+ui_ipc_free(int is_master);
+
+int
+ui_ipc_sempost(enum UI_IPC_SEM e_sp);
+
+int
+ui_ipc_semwait(enum UI_IPC_SEM e_sp);
+
+int
+ui_ipc_semtrywait(enum UI_IPC_SEM e_sp);
+
+int
+ui_ipc_getvalue(enum UI_IPC_SEM e_sp);
+
+#ifdef SEM_TIMEDWAIT
+int
+ui_ipc_semtimedwait(enum UI_IPC_MSQ e_sp, int timeout);
+#endif
+
+int
+ui_ipc_msgsend(enum UI_IPC_MSQ e_mq, const char *msg_ptr, size_t msg_len);
+
+ssize_t
+ui_ipc_msgrecv(enum UI_IPC_MSQ e_mq, char *msg_ptr, size_t msg_len);
+
+#endif
diff --git a/src/ui_nwindow.c b/src/ui_nwindow.c
new file mode 100644
index 0000000..aa1812d
--- /dev/null
+++ b/src/ui_nwindow.c
@@ -0,0 +1,157 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "ui_nwindow.h"
+
+
+struct txtwindow *
+init_txtwindow(unsigned int x, unsigned int y, unsigned int width, unsigned int height, chtype attrs, chtype text_attrs, window_func cb_update)
+{
+ struct txtwindow *a = calloc(1, sizeof(struct txtwindow));
+
+ a->x = x;
+ a->y = y;
+ a->width = width;
+ a->height = height;
+ a->active = false;
+ a->title_len = INITIAL_TITLE_LEN;
+ a->title = calloc(a->title_len+1, sizeof(char));
+ a->text = NULL;
+ a->attrs = attrs;
+ a->text_attrs = text_attrs;
+ a->window_func = cb_update;
+ return (a);
+}
+
+static void
+__free_text(struct txtwindow *a)
+{
+ if (a->text) {
+ if (a->text[0]) {
+ free(a->text[0]);
+ }
+ free(a->text);
+ a->text = NULL;
+ }
+}
+
+void
+free_txtwindow(struct txtwindow *a)
+{
+ __free_text(a);
+ if (a->title) {
+ free(a->title);
+ }
+ free(a);
+}
+
+static void
+print_wnd(struct txtwindow *a)
+{
+ int i, x = a->x, y = a->y, w = a->width, h = a->height;
+ char tmp[a->width+1];
+
+ attron(a->attrs);
+ /* print window surface */
+ memset(tmp, ' ', a->width);
+ tmp[a->width] = '\0';
+ for (i = y-1; i < y+h+2; i++)
+ mvprintw(i, x, tmp);
+ /* print window border */
+ mvhline(y-2, x, 0, w);
+ mvhline(y+h+2, x, 0, w);
+ mvvline(y-1, x-1, 0, h+3);
+ mvvline(y-1, x+w, 0, h+3);
+ /* print window border edges */
+ mvaddch(y-2, x-1, ACS_ULCORNER);
+ mvaddch(y+2+h, x-1, ACS_LLCORNER);
+ mvaddch(y-2, x+w, ACS_URCORNER);
+ mvaddch(y+2+h, x+w, ACS_LRCORNER);
+ /* print window title */
+ attroff(a->attrs);
+ attron(a->text_attrs);
+ mvprintw(y-2, (float)x+(float)(w/2)-(float)(a->title_len*2/3), "[ %s ]", a->title);
+ /* print windows text */
+ i = 0;
+ while ( a->text && a->text[i] ) {
+ mvprintw(y+i, x, a->text[i]);
+ i++;
+ }
+ attroff(a->text_attrs);
+}
+
+static int
+txtwindow_cb(WINDOW *win, void *data, bool timedout)
+{
+ struct txtwindow *a = (struct txtwindow *) data;
+
+ if (a->active == true) {
+ print_wnd(a);
+ }
+ return (UICB_OK);
+}
+
+void inline
+register_txtwindow(struct txtwindow *a)
+{
+ struct ui_callbacks cbs;
+ cbs.ui_element = txtwindow_cb;
+ cbs.ui_input = NULL;
+ register_ui_elt(&cbs, (void *) a, NULL);
+}
+
+static size_t
+__do_textcpy(char **p_dest, size_t sz_dest, const char *p_src, size_t sz_src)
+{
+ size_t cursiz = sz_dest;
+
+ if (sz_src > sz_dest) {
+ *p_dest = (char *) realloc(*p_dest, (sz_src+1) * sizeof(char));
+ cursiz = sz_src;
+ }
+ memset(*p_dest, '\0', (cursiz+1) * sizeof(char));
+ memcpy(*p_dest, p_src, (cursiz+1) * sizeof(char));
+ return sz_src;
+}
+
+/* seperate a String with NEWLINES into an array */
+static char **
+__do_textadjust(struct txtwindow *a, char *text)
+{
+ int i = 0, rows = (int)(strlen(text) / a->width)+1;
+ char **adj_text = calloc(rows+1, sizeof(char *));
+ char *p_strtok, *tok;
+ const char sep[] = "\n";
+
+ if (rows > a->height) goto error;
+ p_strtok = strdup(text);
+ while ( (tok = strsep(&p_strtok, sep)) && rows-- >= 0 ) {
+ if (strlen(tok) > a->width) {
+ strcpy(tok+a->width-3, "...");
+ *(tok+a->width) = '\0';
+ }
+ adj_text[i] = tok;
+ i++;
+ }
+ return adj_text;
+error:
+ free(adj_text);
+ return NULL;
+}
+
+void
+set_txtwindow_text(struct txtwindow *a, char *text)
+{
+ char **fmt_text = __do_textadjust(a, text);
+
+ if (fmt_text) {
+ __free_text(a);
+ a->text = fmt_text;
+ }
+}
+
+void
+set_txtwindow_title(struct txtwindow *a, const char *title)
+{
+ a->title_len = __do_textcpy(&a->title, a->title_len, title, strlen(title));
+}
diff --git a/src/ui_nwindow.h b/src/ui_nwindow.h
new file mode 100644
index 0000000..198481b
--- /dev/null
+++ b/src/ui_nwindow.h
@@ -0,0 +1,44 @@
+#ifndef UI_TXTWINDOW_H
+#define UI_TXTWINDOW_H 1
+
+#include <ncurses.h>
+
+#include "ui.h"
+
+#define INITIAL_TITLE_LEN 32
+
+#define set_txtwindow_active(wnd, activate) wnd->active = activate; ui_thrd_force_update()
+
+struct txtwindow {
+ unsigned int y;
+ unsigned int x;
+ unsigned int width;
+ unsigned int height;
+ bool active;
+ char *title;
+ size_t title_len;
+ char **text;
+ int (*window_func)(WINDOW *, struct txtwindow *);
+ chtype attrs;
+ chtype text_attrs;
+ void *userptr;
+};
+
+typedef int (*window_func)(WINDOW *, struct txtwindow *);
+
+struct txtwindow *
+init_txtwindow(unsigned int, unsigned int y, unsigned int width, unsigned int height, chtype attrs, chtype text_attrs, window_func cb_update);
+
+void
+free_txtwindow(struct txtwindow *a);
+
+void
+register_txtwindow(struct txtwindow *a);
+
+void
+set_txtwindow_text(struct txtwindow *a, char *text);
+
+void
+set_txtwindow_title(struct txtwindow *a, const char *title);
+
+#endif
diff --git a/src/ui_statusbar.c b/src/ui_statusbar.c
new file mode 100644
index 0000000..8fcfeb4
--- /dev/null
+++ b/src/ui_statusbar.c
@@ -0,0 +1,78 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "ui.h"
+#include "ui_statusbar.h"
+
+
+struct statusbar *
+init_statusbar(unsigned int y, unsigned int width, chtype attrs, status_func cb_update)
+{
+ struct statusbar *a = calloc(1, sizeof(struct statusbar));
+
+ a->y = y;
+ a->width = width;
+ a->text = calloc(a->width, sizeof(char));
+ a->attrs = attrs;
+ a->status_func = cb_update;
+ return (a);
+}
+
+void
+free_statusbar(struct statusbar *a)
+{
+ if (a->text) {
+ free(a->text);
+ }
+ free(a);
+}
+
+int
+statusbar_cb(WINDOW *win, void *data, bool timed_out)
+{
+ struct statusbar *a = (struct statusbar *) data;
+ char *tmp;
+ unsigned int diff_pos = 0;
+ size_t len;
+
+ if (a == NULL) return (UICB_ERR_UNDEF);
+ if (timed_out == true) {
+ if (a->status_func != NULL) {
+ a->status_func(win, a);
+ }
+ }
+ attron(a->attrs);
+ len = strnlen(a->text, a->width);
+ if (len < a->width) {
+ diff_pos = (unsigned int) (a->width - len)/2;
+ }
+ tmp = (char *) malloc(a->width + 1);
+ memset(tmp, ' ', a->width);
+ tmp[a->width] = '\0';
+ strncpy((tmp + diff_pos), a->text, len);
+ if (win != NULL) {
+ mvwprintw(win, a->y, 0, tmp);
+ } else {
+ mvprintw(a->y, 0, tmp);
+ }
+ free(tmp);
+ attroff(a->attrs);
+ return (UICB_OK);
+}
+
+void
+register_statusbar(struct statusbar *a)
+{
+ struct ui_callbacks cbs;
+ cbs.ui_element = statusbar_cb;
+ cbs.ui_input = NULL;
+ register_ui_elt(&cbs, (void *) a, NULL);
+}
+
+inline void
+set_statusbar_text(struct statusbar *a, const char *text)
+{
+ size_t len = strlen(text);
+
+ strncpy(a->text, text, (len > a->width ? a->width : len));
+}
diff --git a/src/ui_statusbar.h b/src/ui_statusbar.h
new file mode 100644
index 0000000..5139c14
--- /dev/null
+++ b/src/ui_statusbar.h
@@ -0,0 +1,32 @@
+#ifndef UI_STATUSBAR_H
+#define UI_STATUSBAR_H 1
+
+#include <ncurses.h>
+
+
+struct statusbar {
+ unsigned int y;
+ unsigned int width;
+ char *text;
+ int (*status_func)(WINDOW *, struct statusbar *);
+ chtype attrs;
+};
+
+typedef int (*status_func)(WINDOW *, struct statusbar *);
+
+struct statusbar *
+init_statusbar(unsigned int y, unsigned int width, chtype attrs, status_func cb_update);
+
+void
+free_statusbar(struct statusbar *a);
+
+int
+statusbar_cb(WINDOW *win, void *data, bool timed_out);
+
+void
+register_statusbar(struct statusbar *a);
+
+void
+set_statusbar_text(struct statusbar *a, const char *text);
+
+#endif