/* * forms.c * * Functions for various form dialogs. * * This file is part of the ckpass project. * * Copyright (C) 2009 Heath N. Caldwell * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include #include #include #include #include #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; }