From 094859655961279750af444e803de21061511500 Mon Sep 17 00:00:00 2001 From: PartialVolume <22084881+PartialVolume@users.noreply.github.com> Date: Tue, 18 Jul 2023 01:58:15 +0100 Subject: [PATCH] PDFGen22 Further work completed on customer selection and deletion dialogs --- src/Makefile.am | 2 +- src/conf.c | 6 +- src/customers.c | 208 +++++++++++++++++++++++++++ src/customers.h | 38 +++++ src/gui.c | 374 +++++++++++++++++++++++++++++++++++++++++++++++- src/gui.h | 1 + 6 files changed, 620 insertions(+), 9 deletions(-) create mode 100644 src/customers.c create mode 100644 src/customers.h diff --git a/src/Makefile.am b/src/Makefile.am index c2b895b..4b6a6ba 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,5 +6,5 @@ AM_LDFLAGS = # this lists the binaries to produce, the (non-PHONY, binary) targets in # the previous manual Makefile bin_PROGRAMS = nwipe -nwipe_SOURCES = context.h logging.h options.h prng.h version.h temperature.h nwipe.c gui.c method.h pass.c device.c gui.h isaac_rand/isaac_standard.h isaac_rand/isaac_rand.h isaac_rand/isaac_rand.c isaac_rand/isaac64.h isaac_rand/isaac64.c mt19937ar-cok/mt19937ar-cok.c nwipe.h mt19937ar-cok/mt19937ar-cok.h pass.h device.h logging.c method.c options.c prng.c version.c temperature.c PDFGen/pdfgen.h PDFGen/pdfgen.c create_pdf.c create_pdf.h embedded_images/shred_db.jpg.c embedded_images/shred_db.jpg.h embedded_images/tick_erased.jpg.c embedded_images/tick_erased.jpg.h embedded_images/redcross.c embedded_images/redcross.h hpa_dco.h hpa_dco.c miscellaneous.h miscellaneous.c embedded_images/nwipe_exclamation.jpg.h embedded_images/nwipe_exclamation.jpg.c conf.h conf.c +nwipe_SOURCES = context.h logging.h options.h prng.h version.h temperature.h nwipe.c gui.c method.h pass.c device.c gui.h isaac_rand/isaac_standard.h isaac_rand/isaac_rand.h isaac_rand/isaac_rand.c isaac_rand/isaac64.h isaac_rand/isaac64.c mt19937ar-cok/mt19937ar-cok.c nwipe.h mt19937ar-cok/mt19937ar-cok.h pass.h device.h logging.c method.c options.c prng.c version.c temperature.c PDFGen/pdfgen.h PDFGen/pdfgen.c create_pdf.c create_pdf.h embedded_images/shred_db.jpg.c embedded_images/shred_db.jpg.h embedded_images/tick_erased.jpg.c embedded_images/tick_erased.jpg.h embedded_images/redcross.c embedded_images/redcross.h hpa_dco.h hpa_dco.c miscellaneous.h miscellaneous.c embedded_images/nwipe_exclamation.jpg.h embedded_images/nwipe_exclamation.jpg.c conf.h conf.c customers.h customers.c nwipe_LDADD = $(PARTED_LIBS) $(LIBCONFIG) diff --git a/src/conf.c b/src/conf.c index 395b5d2..f80a468 100644 --- a/src/conf.c +++ b/src/conf.c @@ -112,12 +112,12 @@ int nwipe_conf_init() setting = config_setting_add( group_selected_customer, "Customer_Name", CONFIG_TYPE_STRING ); config_setting_set_string( setting, "Not Applicable (CN)" ); - setting = config_setting_add( group_selected_customer, "Contact_Name", CONFIG_TYPE_STRING ); - config_setting_set_string( setting, "Not Applicable (CN)" ); - setting = config_setting_add( group_selected_customer, "Customer_Address", CONFIG_TYPE_STRING ); config_setting_set_string( setting, "Not Applicable (CA)" ); + setting = config_setting_add( group_selected_customer, "Contact_Name", CONFIG_TYPE_STRING ); + config_setting_set_string( setting, "Not Applicable (CN)" ); + setting = config_setting_add( group_selected_customer, "Contact_Phone", CONFIG_TYPE_STRING ); config_setting_set_string( setting, "Not Applicable (CP)" ); diff --git a/src/customers.c b/src/customers.c new file mode 100644 index 0000000..c193b67 --- /dev/null +++ b/src/customers.c @@ -0,0 +1,208 @@ +/* + * **************************************************************************** + * customers.c: Functions related to customer processing for the PDF erasure * + * certificate. * + * **************************************************************************** + * + * Copyright PartialVolume . + * + * 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, version 2. + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include "nwipe.h" +#include "context.h" +#include "gui.h" +#include "logging.h" +#include "customers.h" +#include + +void customer_processes( int mode ) +{ + /* This function reads the customers.csv file, counts the number of lines, + * converts line feeds to NULL and constructs a array of pointers that point + * to the variable length strings. + * + * Depending on the value of mode the pointer array is passed to either + * the select_customers() or delete_customer() functions. + */ + + int idx; + int idx2; + FILE* fptr; + + struct stat st; + intmax_t size = 0; + int lines; + int list_idx; + int current_list_size; + + size_t result_size; + + extern char nwipe_customers_file[]; + + /* Determine size of customers.csv file */ + stat( nwipe_customers_file, &st ); + size = st.st_size; + current_list_size = 0; + + nwipe_customers_buffer_t raw_buffer = (nwipe_customers_buffer_t) calloc( 1, size + 1 ); + + /* Allocate storage for the contents of customers.csv */ + nwipe_customers_buffer_t buffer = (nwipe_customers_buffer_t) calloc( 1, size + 1 ); + + /* Allocate storage for the processed version of customers.csv, + * i.e we convert the csv format to strings without the quotes + * and semi colon delimiters + */ + nwipe_customers_pointers_t list = (nwipe_customers_pointers_t) calloc( 1, sizeof( char* ) ); + current_list_size += sizeof( char* ); + + /* Open customers.csv */ + if( ( fptr = fopen( nwipe_customers_file, "rb" ) ) == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, "Unable to open %s", nwipe_customers_file ); + free( buffer ); + free( *list ); + return; + } + + /* Read the customers.csv file and populate the list array with the data */ + result_size = fread( raw_buffer, size, 1, fptr ); + + /* Validate csv contents. With the exception of line feeds, + * replace non printable characters with spaces and move + * to a secondary buffer. + */ + idx = 0; + idx2 = 0; + while( idx < size ) + { + if( ( raw_buffer[idx] > 0x20 && raw_buffer[idx] < 0x7F ) || raw_buffer[idx] == 0x0A ) + { + buffer[idx2++] = raw_buffer[idx]; + } + idx++; + } + + /* Construct a array of pointers that point to each line of the csv file + */ + idx = 0; + lines = 0; + list_idx = 0; + + while( idx < size ) + { + if( buffer[idx] == 0x0A ) + { + buffer[idx] = 0; + + /* increment the line counter, but don't count + * the first line as that is the csv header line. + */ + if( idx != 0 ) + { + lines++; + + /* Change the line feed to a NULL, string terminator */ + buffer[idx] = 0; + + /* Save the pointer to the first data line of the csv. */ + list[list_idx++] = &buffer[idx + 1]; + + current_list_size += sizeof( char* ); + + /* Expand allocated memory by the size of one pointer */ + if( ( list = realloc( list, current_list_size ) ) == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, "Unable to realloc customer list array, out of memory?" ); + break; + } + current_list_size += sizeof( char* ); + } + } + else + { + /* Replace colons with commas */ + if( buffer[idx] == ';' ) + { + buffer[idx] = ','; + } + else + { + /* Replace quotes with spaces */ + if( buffer[idx] == '\"' ) + { + buffer[idx] = ' '; + } + } + } + idx++; + } + + /* Sync lines variable to actual number of lines */ + if( lines > 0 ) + lines--; + + if( idx == size ) + { + /* makesure the very last entry is NULL terminated */ + buffer[idx] = 0; + } + + /* Select the requested mode, customer or delete customer. + */ + switch( mode ) + { + case SELECT_CUSTOMER: + select_customers( lines, list ); + break; + + case DELETE_CUSTOMER: + delete_customer( lines, list ); + break; + } +} + +void select_customers( int count, char** customer_list_array ) +{ + int selected_entry = 0; + char window_title[] = " Select Customer For PDF Report "; + + nwipe_gui_list( count, window_title, customer_list_array, &selected_entry ); + + nwipe_log( NWIPE_LOG_INFO, "Line selected = %d", selected_entry ); +} + +void add_customer() +{ + int count = 8; + char window_title[] = " Add Customer "; + int selected_entry = 0; + + // nwipe_gui_list( count, window_title, &list[8], &selected_entry ); + + nwipe_log( NWIPE_LOG_INFO, "Line selected = %d", selected_entry ); +} + +void delete_customer( int count, char** customer_list_array ) +{ + char window_title[] = " Delete Customer "; + int selected_entry = 0; + + nwipe_gui_list( count, window_title, customer_list_array, &selected_entry ); + + nwipe_log( NWIPE_LOG_INFO, "Line selected = %d", selected_entry ); +} diff --git a/src/customers.h b/src/customers.h new file mode 100644 index 0000000..7533c57 --- /dev/null +++ b/src/customers.h @@ -0,0 +1,38 @@ +/* + * **************************************************************************** + * customers.h: Functions related to customer processing for the PDF erasure * + * certificate. * + * **************************************************************************** + * + * Copyright PartialVolume . + * + * 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, version 2. + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef CUSTOMERS_H_INCLUDED +#define CUSTOMERS_H_INCLUDED + +void customer_processes( int ); +void select_customers( int, char** ); +void delete_customer(); +void add_customer(); + +typedef char* nwipe_customers_buffer_t; +typedef char** nwipe_customers_pointers_t; + +#define SELECT_CUSTOMER 1 +#define DELETE_CUSTOMER 2 + +#endif // CUSTOMERS_H_INCLUDED diff --git a/src/gui.c b/src/gui.c index 660f06b..7a8b6d4 100644 --- a/src/gui.c +++ b/src/gui.c @@ -46,6 +46,7 @@ #include "temperature.h" #include "miscellaneous.h" #include "hpa_dco.h" +#include "customers.h" #define NWIPE_GUI_PANE 8 @@ -2472,7 +2473,7 @@ void nwipe_gui_config( void ) extern int terminate_signal; /* Number of entries in the configuration menu. */ - const int count = 3; + const int count = 4; /* The first tabstop. */ const int tab1 = 2; @@ -2506,6 +2507,7 @@ void nwipe_gui_config( void ) /* Print the options. */ mvwprintw( main_window, yy++, tab1, " %s", "PDF Report - Edit Organisation" ); + mvwprintw( main_window, yy++, tab1, " %s", "PDF Report - Select Customer " ); mvwprintw( main_window, yy++, tab1, " %s", "PDF Report - Add Customer " ); mvwprintw( main_window, yy++, tab1, " %s", "PDF Report - Delete Customer " ); mvwprintw( main_window, yy++, tab1, " " ); @@ -2527,6 +2529,19 @@ void nwipe_gui_config( void ) break; case 1: + mvwprintw( main_window, 2, tab2, "PDF Report - Select Customer" ); + + mvwprintw( main_window, 4, tab2, "Allows selection of a customer as " ); + mvwprintw( main_window, 5, tab2, "displayed on the PDF report. Customer " ); + mvwprintw( main_window, 6, tab2, "information includes Name (This can be" ); + mvwprintw( main_window, 7, tab2, "a personal or business name), address " ); + mvwprintw( main_window, 8, tab2, "contact name and contact phone. " ); + mvwprintw( main_window, 9, tab2, " " ); + mvwprintw( main_window, 10, tab2, "Customer data is located in: " ); + mvwprintw( main_window, 11, tab2, "/etc/nwipe/nwipe_customers.csv " ); + break; + + case 2: mvwprintw( main_window, 2, tab2, "PDF Report - Add Customer " ); @@ -2541,7 +2556,7 @@ void nwipe_gui_config( void ) mvwprintw( main_window, 12, tab2, "/etc/nwipe/nwipe_customers.csv " ); break; - case 2: + case 3: mvwprintw( main_window, 2, tab2, "PDF Report - Delete Customer " ); @@ -2617,11 +2632,16 @@ void nwipe_gui_config( void ) break; case 1: - // nwipe_options.method = &nwipe_one; + customer_processes( SELECT_CUSTOMER ); + // select_customers(); break; case 2: - // nwipe_options.method = &nwipe_ops2; + add_customer(); + break; + + case 3: + customer_processes( DELETE_CUSTOMER ); break; } @@ -2792,7 +2812,7 @@ void nwipe_gui_edit_organisation( void ) } while( keystroke != KEY_ENTER && keystroke != ' ' && keystroke != 10 && terminate_signal != 1 ); - if( keystroke == KEY_ENTER || keystroke == 10 ) + if( keystroke == KEY_ENTER || keystroke == 10 || keystroke == ' ' ) { switch( focus ) { @@ -3528,6 +3548,350 @@ void nwipe_gui_organisation_op_tech_name( const char* op_tech_name ) } /* End of nwipe_gui_organisation_op_tech_name() */ +void nwipe_gui_list( int count, char* window_title, char** list, int* selected_entry ) +{ + /** + * Displays a selectable list in a window, return 1 -n in selected entry. + * If selected entry = 0, then user cancelled selection. + */ + + extern int terminate_signal; + + /* The number of lines available in the window. */ + int wlines; + + /* The number of columns available in the window. */ + int wcols; + + /* The number of selection elements that we can show in the window. */ + int slots; + + /* The index of the element that is visible in the first slot. */ + int offset = 0; + + /* The selection focus. */ + int focus = 0; + + /* A generic loop variable. */ + int i = 0; + + /* User input buffer. */ + int keystroke; + + /* The current working line. */ + int yy; + + /* Flag, Valid key hit = 1, anything else = 0 */ + int validkeyhit; + + /* Get the terminal size */ + getmaxyx( stdscr, stdscr_lines, stdscr_cols ); + + /* Save the terminal size so we check whether the user has resized */ + stdscr_lines_previous = stdscr_lines; + stdscr_cols_previous = stdscr_cols; + + /* Used to refresh the window every second */ + time_t check_time = time( NULL ); + + /* Used in the selection loop to trap a failure of the timeout(), getch() mechanism to block for the designated + * period */ + int iteration_counter; + + /* Used in the selection loop to trap a failure of the timeout(), getch() mechanism to block for the designated + * period */ + int expected_iterations; + + time_t previous_iteration_timestamp; + + do + { + + nwipe_gui_create_all_windows_on_terminal_resize( 0, main_window_footer ); + + /* There is one slot per line. */ + getmaxyx( main_window, wlines, wcols ); + + /* Less two lines for the box and two lines for padding. */ + slots = wlines - 4; + if( slots < 0 ) + { + slots = 0; + } + + /* The code here adjusts the offset value, required when the terminal is resized vertically */ + if( slots > count ) + { + offset = 0; + } + else + { + if( focus >= count ) + { + /* The focus is already at the last element. */ + focus = count - 1; + } + if( focus < 0 ) + { + /* The focus is already at the last element. */ + focus = 0; + } + } + + if( count >= slots && slots > 0 ) + { + offset = focus + 1 - slots; + if( offset < 0 ) + { + offset = 0; + } + } + + /* Clear the main window, necessary when switching selections such as method etc */ + werase( main_window ); + + /* Refresh main window */ + wnoutrefresh( main_window ); + + /* Set footer help text */ + /* Update the footer window. */ + werase( footer_window ); + nwipe_gui_title( footer_window, selection_footer ); + wrefresh( footer_window ); + + /* Refresh the stats window */ + wnoutrefresh( stats_window ); + + /* Refresh the options window */ + wnoutrefresh( options_window ); + + /* Update the options window. */ + nwipe_gui_options(); + + /* Initialize the line offset. */ + yy = 2; + + for( i = 0; i < slots && i < count; i++ ) + { + /* Move to the next line. */ + mvwprintw( main_window, yy++, 1, " " ); + + if( i + offset == focus ) + { + /* Print the 'enabled' cursor. */ + waddch( main_window, ACS_RARROW ); + } + + else + { + /* Print whitespace. */ + waddch( main_window, ' ' ); + } + + /* In the event for the offset value somehow becoming invalid, this if statement will prevent a segfault + * and the else part will log the out of bounds values for debugging */ + if( i + offset >= 0 && i + offset < count ) + { + /* print a entry from the list */ + wprintw( main_window, "%s ", list[i + offset] ); + } + else + { + nwipe_log( NWIPE_LOG_DEBUG, + "GUI.c,nwipe_gui_select(), scroll, array index out of bounds, i=%u, count=%u, slots=%u, " + "focus=%u, offset=%u", + i, + count, + slots, + focus, + offset ); + } + + } /* for */ + + if( offset > 0 ) + { + mvwprintw( main_window, 1, wcols - 8, " More " ); + waddch( main_window, ACS_UARROW ); + } + + if( count - offset > slots ) + { + mvwprintw( main_window, wlines - 2, wcols - 8, " More " ); + waddch( main_window, ACS_DARROW ); + } + + /* Draw a border around the menu window. */ + box( main_window, 0, 0 ); + + /* Print a title. */ + nwipe_gui_title( main_window, window_title ); + + /* Refresh the window. */ + wnoutrefresh( main_window ); + + /* Output to physical screen */ + doupdate(); + + /* Initialise the iteration counter */ + iteration_counter = 0; + + previous_iteration_timestamp = time( NULL ); + + /* Calculate Maximum allowed iterations per second */ + expected_iterations = ( 1000 / GETCH_BLOCK_MS ) * 8; + + do + { + /* Wait 250ms for input from getch, if nothing getch will then continue, + * This is necessary so that the while loop can be exited by the + * terminate_signal e.g.. the user pressing control-c to exit. + * Do not change this value, a higher value means the keys become + * sluggish, any slower and more time is spent unnecessarily looping + * which wastes CPU cycles. + */ + + validkeyhit = 0; + timeout( GETCH_BLOCK_MS ); // block getch() for ideally about 250ms. + keystroke = getch(); // Get user input. + timeout( -1 ); // Switch back to blocking mode. + + /* To avoid 100% CPU usage, check for a runaway condition caused by the "keystroke = getch(); (above), from + * immediately returning an error condition. We check for an error condition because getch() returns a ERR + * value when the timeout value "timeout( 250 );" expires as well as when a real error occurs. We can't + * differentiate from normal operation and a failure of the getch function to block for the specified period + * of timeout. So here we check the while loop hasn't exceeded the number of expected iterations per second + * ie. a timeout(250) block value of 250ms means we should not see any more than (1000/250) = 4 iterations. + * We increase this to 32 iterations to allow a little tolerance. Why is this necessary? It's been found + * that in KDE konsole and other terminals based on the QT terminal engine exiting the terminal without + * first exiting nwipe results in nwipe remaining running but detached from any interface which causes + * getch to fail and its associated timeout. So the CPU or CPU core rises to 100%. Here we detect that + * failure and exit nwipe gracefully with the appropriate error. This does not affect use of tmux for + * attaching or detaching from a running nwipe session when sitting at the selection screen. All other + * terminals correctly terminate nwipe when the terminal itself is exited. + */ + + iteration_counter++; + + if( previous_iteration_timestamp == time( NULL ) ) + { + if( iteration_counter > expected_iterations ) + { + nwipe_log( NWIPE_LOG_ERROR, + "GUI.c,nwipe_gui_select(), loop runaway, did you close the terminal without exiting " + "nwipe? Exiting nwipe now." ); + /* Issue signal to nwipe to exit immediately but gracefully */ + terminate_signal = 1; + } + } + else + { + /* new second, so reset counter */ + iteration_counter = 0; + previous_iteration_timestamp = time( NULL ); + } + + /* We don't necessarily use all of these. For future reference these are some CTRL+key values + * ^A - 1, ^B - 2, ^D - 4, ^E - 5, ^F - 6, ^G - 7, ^H - 8, ^I - 9, ^K - 11, ^L - 12, ^N - 14, + * ^O - 15, ^P - 16, ^R - 18, ^T - 20, ^U - 21, ^V - 22, ^W - 23, ^X - 24, ^Y - 25 + * Use nwipe_log( NWIPE_LOG_DEBUG, "Key Name: %s - %u", keyname(keystroke),keystroke) to + * figure out what code is returned by what ever key combination */ + + switch( keystroke ) + { + case KEY_DOWN: + case 'j': + case 'J': + + validkeyhit = 1; + + /* Increment the focus. */ + focus += 1; + + if( focus >= count ) + { + /* The focus is already at the last element. */ + focus = count - 1; + break; + } + + if( focus - offset >= slots ) + { + /* The next element is offscreen. Scroll down. */ + offset += 1; + break; + } + + break; + + case KEY_UP: + case 'k': + case 'K': + + validkeyhit = 1; + + /* Decrement the focus. */ + focus -= 1; + + if( focus < 0 ) + { + /* The focus is already at the last element. */ + focus = 0; + break; + } + + if( focus < offset ) + { + /* The next element is offscreen. Scroll up. */ + offset -= 1; + break; + } + + break; + + case KEY_BACKSPACE: + case KEY_LEFT: + case 127: + + return; + break; + + case KEY_ENTER: + case 10: + case ' ': + + validkeyhit = 1; + + /* Return the index of the selected item in the list. Values start at 1 not zero */ + *selected_entry = focus + 1; + return; + + break; + + } /* keystroke switch */ + + /* Check the terminal size, if the user has changed it the while loop checks for + * this change and exits the valid key hit loop so the windows can be updated */ + getmaxyx( stdscr, stdscr_lines, stdscr_cols ); + + /* Update the selection window every 1 second specifically + * so that the drive temperatures are updated and also the line toggle that + * occurs with the HPA status and the drive size & temperature. + */ + if( time( NULL ) > ( check_time + 1 ) ) + { + check_time = time( NULL ); + validkeyhit = 1; + } + + } /* key hit loop */ + while( validkeyhit == 0 && terminate_signal != 1 && stdscr_cols_previous == stdscr_cols + && stdscr_lines_previous == stdscr_lines ); + + } while( terminate_signal != 1 ); + +} /* nwipe_gui_list */ + void nwipe_gui_load( void ) { /** diff --git a/src/gui.h b/src/gui.h index 97a0f23..a6e2305 100644 --- a/src/gui.h +++ b/src/gui.h @@ -60,6 +60,7 @@ void nwipe_gui_organisation_business_address( const char* ); // Edit business a void nwipe_gui_organisation_contact_name( const char* ); // Edit business contact name void nwipe_gui_organisation_contact_phone( const char* ); // Edit business contact phone void nwipe_gui_organisation_op_tech_name( const char* ); // Edit the name of the operator/technician +void nwipe_gui_list( int count, char* window_title, char**, int* selected_entry ); int spinner( nwipe_context_t** ptr, int ); // Return the next spinner character void temp1_flash( nwipe_context_t* ); // toggles term1_flash_status, which flashes the temperature