/*
* 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;
}