ckpass Code
Status: Alpha
Brought to you by:
hnc
--- a +++ b/forms.c @@ -0,0 +1,431 @@ +/* + * forms.c + * + * Heath Caldwell + * hncaldwell@gmail.com + */ + +#include <ncurses.h> +#include <form.h> +#include <string.h> +#include <kpass.h> +#include <time.h> + +#include "forms.h" + +int password_form(char *buffer, int length) { + FIELD *fields[5]; + FORM *form; + WINDOW *win; + int press; + int rows, cols; + int ret_val; + int i; + int max_x, max_y; + + char *labels[] = {"Password:", "[OK]", "[CANCEL]"}; + + fields[0] = new_field(1, strlen(labels[0]), 0, 0, 0 , 0); + fields[1] = new_field(1, 16, 0, 1 + strlen(labels[0]), 0 , 0); + fields[2] = new_field(1, strlen(labels[1]), 2, 4, 0 , 0); + fields[3] = new_field(1, strlen(labels[2]), 2, 6 + strlen(labels[2]), 0 , 0); + fields[4] = 0; + + field_opts_off(fields[0], O_ACTIVE); + + set_field_back(fields[1], A_UNDERLINE); + field_opts_off(fields[1], O_PUBLIC); + field_opts_off(fields[1], O_STATIC); + field_opts_off(fields[1], O_AUTOSKIP); + set_max_field(fields[1], length); + + field_opts_off(fields[2], O_EDIT); + field_opts_off(fields[3], O_EDIT); + + form = new_form(fields); + form_opts_off(form, O_BS_OVERLOAD); + scale_form(form, &rows, &cols); + + getmaxyx(stdscr, max_y, max_x); + + win = newwin(rows + 4, cols + 4, (max_y - (rows + 4)) / 2, (max_x - (cols + 4)) / 2); + keypad(win, TRUE); + set_form_win(form, win); + set_form_sub(form, derwin(win, rows, cols, 2, 2)); + box(win, 0, 0); + + post_form(form); + curs_set(1); + wrefresh(win); + + set_field_just(fields[0], JUSTIFY_LEFT); + set_field_buffer(fields[0], 0, labels[0]); + set_field_buffer(fields[2], 0, labels[1]); + set_field_buffer(fields[3], 0, labels[2]); + + while(1) { + press = wgetch(win); + + if(press == KEY_RESIZE) { + // This might be a mess to deal with. + continue; + } else if(press == '\t') { + if(current_field(form) != fields[1]) { + set_field_fore(current_field(form), A_NORMAL); + curs_set(1); + } + form_driver(form, REQ_NEXT_FIELD); + form_driver(form, REQ_END_LINE); + if(current_field(form) != fields[1]) { + set_field_fore(current_field(form), A_REVERSE); + curs_set(0); + } + } else if(press == KEY_LEFT) { + form_driver(form, REQ_PREV_CHAR); + } else if(press == KEY_RIGHT) { + form_driver(form, REQ_NEXT_CHAR); + } else if(press == KEY_BACKSPACE) { + form_driver(form, REQ_DEL_PREV); + } else if(press == '\n') { + if(current_field(form) == fields[3]) { + ret_val = 1; + break; + } + + /* Force the field buffer to be written. */ + if(current_field(form) == fields[1]) form_driver(form, REQ_NEXT_FIELD); + + strncpy(buffer, field_buffer(fields[1], 0), length); + + /* Trim trailing spaces (should probably be revisited). */ + i = strlen(buffer) - 2; + for(; buffer[i] == ' ' && i > 0; i--) ; + buffer[i + 1] = '\0'; + + ret_val = 0; + break; + } else { + form_driver(form, press); + set_field_status(fields[1], true); + } + } + + unpost_form(form); + free_form(form); + + for(i = 0; fields[i]; i++) { + free_field(fields[i]); + } + + delwin(win); + + curs_set(0); + return ret_val; +} + +int open_database_form(char *buffer, int length) { + FIELD *fields[5]; + FORM *form; + WINDOW *win; + int press; + int rows, cols; + int ret_val; + int i; + int max_x, max_y; + + char *labels[] = {"Database File:", "[OK]", "[CANCEL]"}; + + fields[0] = new_field(1, strlen(labels[0]), 0, 0, 0 , 0); + fields[1] = new_field(1, 32, 0, 1 + strlen(labels[0]), 0 , 0); + fields[2] = new_field(1, strlen(labels[1]), 2, 16, 0 , 0); + fields[3] = new_field(1, strlen(labels[2]), 2, 18 + strlen(labels[2]), 0 , 0); + fields[4] = 0; + + field_opts_off(fields[0], O_ACTIVE); + + set_field_back(fields[1], A_UNDERLINE); + field_opts_off(fields[1], O_STATIC); + field_opts_off(fields[1], O_AUTOSKIP); + set_max_field(fields[1], length); + + field_opts_off(fields[2], O_EDIT); + field_opts_off(fields[3], O_EDIT); + + form = new_form(fields); + form_opts_off(form, O_BS_OVERLOAD); + scale_form(form, &rows, &cols); + + getmaxyx(stdscr, max_y, max_x); + + win = newwin(rows + 4, cols + 4, (max_y - (rows + 4)) / 2, (max_x - (cols + 4)) / 2); + keypad(win, TRUE); + set_form_win(form, win); + set_form_sub(form, derwin(win, rows, cols, 2, 2)); + box(win, 0, 0); + + post_form(form); + curs_set(1); + wrefresh(win); + + set_field_just(fields[0], JUSTIFY_LEFT); + set_field_buffer(fields[0], 0, labels[0]); + set_field_buffer(fields[2], 0, labels[1]); + set_field_buffer(fields[3], 0, labels[2]); + + while(1) { + press = wgetch(win); + + if(press == KEY_RESIZE) { + // This might be a mess to deal with. + continue; + } else if(press == '\t') { + if(current_field(form) != fields[1]) { + set_field_fore(current_field(form), A_NORMAL); + curs_set(1); + } + form_driver(form, REQ_NEXT_FIELD); + form_driver(form, REQ_END_LINE); + if(current_field(form) != fields[1]) { + set_field_fore(current_field(form), A_REVERSE); + curs_set(0); + } + } else if(press == KEY_LEFT) { + form_driver(form, REQ_PREV_CHAR); + } else if(press == KEY_RIGHT) { + form_driver(form, REQ_NEXT_CHAR); + } else if(press == KEY_BACKSPACE) { + form_driver(form, REQ_DEL_PREV); + } else if(press == '\n') { + if(current_field(form) == fields[3]) { + ret_val = 1; + break; + } + + /* Force the field buffer to be written. */ + if(current_field(form) == fields[1]) form_driver(form, REQ_NEXT_FIELD); + + strncpy(buffer, field_buffer(fields[1], 0), length); + + /* Trim trailing spaces (should probably be revisited). */ + i = strlen(buffer) - 2; + for(; buffer[i] == ' ' && i > 0; i--) ; + buffer[i + 1] = '\0'; + + ret_val = 0; + break; + } else { + form_driver(form, press); + set_field_status(fields[1], true); + } + } + + unpost_form(form); + free_form(form); + + for(i = 0; fields[i]; i++) { + free_field(fields[i]); + } + + delwin(win); + + curs_set(0); + return ret_val; +} + +int entry_form(struct kpass_db *db, struct kpass_entry *entry) { + enum {f_uuid, f_group, f_image, f_title, f_url, f_username, f_password, + f_desc, f_ctime, f_mtime, f_atime, f_etime, f_notes, f_last}; + + FIELD *fields[2*f_last + 3]; + FORM *form; + WINDOW *win; + int press; + int rows, cols; + int ret_val; + int i, j; + int max_x, max_y; + int init_length = 40; + int max_length = 256; + char buffer[max_length]; + struct tm tms; + + char *labels[] = {"uuid:", "Group:", "Image:", "Title:", "URL:", "Username:", "Password:", + "Description:", "ctime:", "mtime:", "atime:", "etime:", "Notes:"}; + char *buttons[] = {"[OK]", "[CANCEL]"}; + + for(i = 0; i < f_last; i++) { + fields[2*i] = new_field(1, strlen(labels[i]), i, 0, 0 , 0); + fields[2*i + 1] = new_field(1, init_length, i, 14, 0 , 0); + + set_field_fore(fields[2*i], A_NORMAL); + field_opts_off(fields[2*i], O_ACTIVE); + set_field_just(fields[2*i], JUSTIFY_LEFT); + set_field_buffer(fields[2*i], 0, labels[i]); + + set_field_fore(fields[2*i + 1], A_NORMAL); + set_field_back(fields[2*i + 1], A_UNDERLINE); + field_opts_off(fields[2*i + 1], O_STATIC); + field_opts_off(fields[2*i + 1], O_AUTOSKIP); + set_max_field(fields[2*i + 1], max_length); + + switch(i) { + case f_uuid: + field_opts_off(fields[2*i + 1], O_ACTIVE); + set_field_back(fields[2*i + 1], A_NORMAL); + + for(j=0; j<16; j++) { + sprintf(buffer + (j*2), "%02x", entry->uuid[j]); + } + buffer[j] = 0; + set_field_buffer(fields[2*i + 1], 0, buffer); + break; + case f_group: + field_opts_off(fields[2*i + 1], O_ACTIVE); + set_field_back(fields[2*i + 1], A_NORMAL); + + for(j=0; j < db->groups_len && db->groups[j]->id != entry->group_id; j++); + set_field_buffer(fields[2*i + 1], 0, db->groups[j]->name); + break; + case f_image: + field_opts_off(fields[2*i + 1], O_ACTIVE); + set_field_back(fields[2*i + 1], A_NORMAL); + + snprintf(buffer, max_length, "%d", entry->image_id); + + set_field_buffer(fields[2*i + 1], 0, buffer); + break; + case f_title: + set_field_buffer(fields[2*i + 1], 0, entry->title); + break; + case f_url: + set_field_buffer(fields[2*i + 1], 0, entry->url); + break; + case f_username: + set_field_buffer(fields[2*i + 1], 0, entry->username); + break; + case f_password: + set_field_buffer(fields[2*i + 1], 0, entry->password); + break; + case f_desc: + set_field_buffer(fields[2*i + 1], 0, entry->desc); + break; + case f_ctime: + kpass_unpack_time(entry->ctime, &tms); + strftime(buffer, max_length, "%Y-%m-%d %H:%M:%S", &tms); + set_field_buffer(fields[2*i + 1], 0, buffer); + break; + case f_mtime: + kpass_unpack_time(entry->mtime, &tms); + strftime(buffer, max_length, "%Y-%m-%d %H:%M:%S", &tms); + set_field_buffer(fields[2*i + 1], 0, buffer); + break; + case f_atime: + kpass_unpack_time(entry->atime, &tms); + strftime(buffer, max_length, "%Y-%m-%d %H:%M:%S", &tms); + set_field_buffer(fields[2*i + 1], 0, buffer); + break; + case f_etime: + kpass_unpack_time(entry->etime, &tms); + strftime(buffer, max_length, "%Y-%m-%d %H:%M:%S", &tms); + + if(!strcmp(buffer, "2999-12-28 23:59:59")) { + strcpy(buffer, "Never"); + } + + set_field_buffer(fields[2*i + 1], 0, buffer); + break; + case f_notes: + set_field_buffer(fields[2*i + 1], 0, entry->notes); + break; + } + } + + fields[2*f_last] = new_field(1, strlen(buttons[0]), f_last + 1, 19, 0 , 0); + set_field_buffer(fields[2*i], 0, buttons[0]); + fields[2*f_last + 1] = new_field(1, strlen(buttons[1]), f_last + 1, 27, 0 , 0); + set_field_buffer(fields[2*i + 1], 0, buttons[1]); + fields[2*f_last + 2] = 0; /* terminating field */ + + field_opts_off(fields[2*f_last], O_EDIT); + field_opts_off(fields[2*f_last + 1], O_EDIT); + + form = new_form(fields); + form_opts_off(form, O_BS_OVERLOAD); + scale_form(form, &rows, &cols); + + getmaxyx(stdscr, max_y, max_x); + + win = newwin(rows + 4, cols + 4, (max_y - (rows + 4)) / 2, (max_x - (cols + 4)) / 2); + keypad(win, TRUE); + set_form_win(form, win); + set_form_sub(form, derwin(win, rows, cols, 2, 2)); + box(win, 0, 0); + + post_form(form); + curs_set(1); + wrefresh(win); + + while(1) { + press = wgetch(win); + + if(press == KEY_RESIZE) { + // This might be a mess to deal with. + continue; + } else if(press == '\t' || press == KEY_DOWN || (press == '\n' && current_field(form) < fields[2*f_last])) { + if(current_field(form) == fields[2*f_last] || current_field(form) == fields[2*f_last + 1]) { + set_field_fore(current_field(form), A_NORMAL); + curs_set(1); + } + form_driver(form, REQ_NEXT_FIELD); + form_driver(form, REQ_END_LINE); + if(current_field(form) == fields[2*f_last] || current_field(form) == fields[2*f_last + 1]) { + set_field_fore(current_field(form), A_REVERSE); + curs_set(0); + } + } else if(press == KEY_UP) { + if(current_field(form) == fields[2*f_last] || current_field(form) == fields[2*f_last + 1]) { + set_field_fore(current_field(form), A_NORMAL); + curs_set(1); + } + form_driver(form, REQ_PREV_FIELD); + form_driver(form, REQ_END_LINE); + if(current_field(form) == fields[2*f_last] || current_field(form) == fields[2*f_last + 1]) { + set_field_fore(current_field(form), A_REVERSE); + curs_set(0); + } + } else if(press == KEY_LEFT) { + form_driver(form, REQ_PREV_CHAR); + } else if(press == KEY_RIGHT) { + form_driver(form, REQ_NEXT_CHAR); + } else if(press == KEY_BACKSPACE) { + form_driver(form, REQ_DEL_PREV); + } else if(press == '\n') { + if(current_field(form) == fields[2*f_last]) { + /* OK button. */ + + /* STORE THE STUFF */ + ret_val = 0; + break; + } else if(current_field(form) == fields[2*f_last + 1]) { + /* Cancel button. */ + ret_val = 1; + break; + } + } else { + form_driver(form, press); + } + } + + unpost_form(form); + free_form(form); + + for(i = 0; fields[i]; i++) { + free_field(fields[i]); + } + + delwin(win); + + curs_set(0); + return ret_val; +} +