diff --git a/src/conf.c b/src/conf.c index 8c6c3ad..929e1c2 100644 --- a/src/conf.c +++ b/src/conf.c @@ -39,6 +39,8 @@ const char* nwipe_conf_str; char nwipe_config_directory[] = "/etc/nwipe"; char nwipe_config_file[] = "/etc/nwipe/nwipe.conf"; char nwipe_customers_file[] = "/etc/nwipe/nwipe_customers.csv"; +char nwipe_customers_file_backup[] = "/etc/nwipe/nwipe_customers.csv.backup"; +char nwipe_customers_file_backup_tmp[] = "/etc/nwipe/nwipe_customers.csv.backup.tmp"; /* * Checks for the existence of nwipe.conf and nwipe_customers.csv diff --git a/src/customers.c b/src/customers.c index 74b8d22..4d522c8 100644 --- a/src/customers.c +++ b/src/customers.c @@ -83,6 +83,8 @@ void customer_processes( int mode ) /* Read the customers.csv file and populate the list array with the data */ result_size = fread( raw_buffer, size, 1, fptr ); + fclose( fptr ); + /* Validate csv contents. With the exception of line feeds, * remove non printable characters and move to a secondary buffer. */ @@ -179,8 +181,6 @@ void select_customers( int count, char** customer_list_array ) /* Display the customer selection window */ nwipe_gui_list( count, window_title, customer_list_array, &selected_entry ); - nwipe_log( NWIPE_LOG_INFO, "Line selected = %d", selected_entry ); - /* Save the selected customer details to nwipe's config file /etc/nwipe/nwipe.conf * If selected entry equals 0, then the customer did not select an entry so skip save. */ @@ -210,16 +210,25 @@ void write_customer_csv_entry( char* customer_name, * line after the header (line 2 of file) */ - FILE* fptr; + FILE* fptr = 0; + FILE* fptr2 = 0; size_t result_size; + /* General index variables */ + int idx1, idx2, idx3; + /* Length of the new customer line */ int csv_line_length; + /* Size of the new buffer that holds old contents plus new entry */ + int new_customers_buffer_size; + struct stat st; extern char nwipe_customers_file[]; + extern char nwipe_customers_file_backup[]; + extern char nwipe_customers_file_backup_tmp[]; intmax_t existing_file_size = 0; @@ -232,6 +241,8 @@ void write_customer_csv_entry( char* customer_name, /* pointer to the buffer containing the existing customer file plus the new entry */ char* new_customers_buffer = 0; + size_t new_customers_buffer_length; + /* Determine length of all four strings and malloc sufficient storage + 12 = 8 quotes + three colons + null */ csv_line_length = strlen( customer_name ) + strlen( customer_address ) + strlen( customer_contact_name ) + strlen( customer_contact_phone ) + 12; @@ -254,7 +265,9 @@ void write_customer_csv_entry( char* customer_name, { /* create a third buffer which is the combined size of the previous two, i.e existing file size, plus the * new customer entry + 1 (NULL) */ - if( !( new_customers_buffer = calloc( 1, existing_file_size + csv_line_length + 1 == 0 ) ) ) + new_customers_buffer_size = existing_file_size + csv_line_length + 1; + + if( !( new_customers_buffer = calloc( 1, new_customers_buffer_size ) ) ) { nwipe_log( NWIPE_LOG_ERROR, "func:nwipe_gui_add_customer:customers_buffer, calloc returned NULL " ); } @@ -265,23 +278,212 @@ void write_customer_csv_entry( char* customer_name, { nwipe_log( NWIPE_LOG_ERROR, "Unable to open %s", nwipe_customers_file ); } - - /* Read the customers.csv file and populate the list array with the data */ - if( ( result_size = fread( customers_buffer, existing_file_size, 1, fptr ) ) != 1 ) - { - nwipe_log( NWIPE_LOG_ERROR, - "func:nwipe_gui_add_customer:Error reading customers file, # bytes read not as expected " - "%i bytes", - result_size ); - } else { - /* Read the first line of the existing customer buffer & write to the new buffer */ + /* Read the customers.csv file and populate the list array with the data */ + if( ( result_size = fread( customers_buffer, existing_file_size, 1, fptr ) ) != 1 ) + { + nwipe_log( + NWIPE_LOG_ERROR, + "func:nwipe_gui_add_customer:Error reading customers file, # bytes read not as expected " + "%i bytes", + result_size ); + } + else + { + /* -------------------------------------------------------------------- + * Read the first line which is the csv header from the existing customer + * buffer & write to the new buffer. + */ + + idx1 = 0; // Index for the current csv buffer + idx2 = 0; // Index for the new csv buffer + idx3 = 0; // Index for new customer fields + + while( idx1 < existing_file_size && idx2 < new_customers_buffer_size ) + { + if( customers_buffer[idx1] != LINEFEED ) + { + new_customers_buffer[idx2++] = customers_buffer[idx1++]; + } + else + { + new_customers_buffer[idx2++] = LINEFEED; + break; + } + } + + /* -------------------------------------------------------------------------- + * Copy the new customer name entry so it is immediately after the csv header + */ + + /* Start with first entries opening quote */ + new_customers_buffer[idx2++] = '"'; + + /* Copy the customer_name string */ + while( idx3 < FIELD_LENGTH && idx2 < new_customers_buffer_size && customer_name[idx3] != 0 ) + { + new_customers_buffer[idx2++] = customer_name[idx3++]; + } + + /* Close customer name field with a quote */ + new_customers_buffer[idx2++] = '"'; + + /* Insert field delimiters, we use a semi-colon, not a comma ';' */ + new_customers_buffer[idx2++] = ';'; + + /* ----------------------------------------------------------------------------- + * Copy the new customer address entry so it is immediately after the csv header + */ + + idx3 = 0; + + /* Start with first entries opening quote */ + new_customers_buffer[idx2++] = '\"'; + + /* Copy the customer_name string */ + while( idx3 < FIELD_LENGTH && idx2 < new_customers_buffer_size && customer_address[idx3] != 0 ) + { + new_customers_buffer[idx2++] = customer_address[idx3++]; + } + + /* Close customer name field with a quote */ + new_customers_buffer[idx2++] = '\"'; + + /* Insert field delimiters, we use a semi-colon, not a comma ';' */ + new_customers_buffer[idx2++] = ';'; + + /* ----------------------------------------------------------------------------- + * Copy the new customer contact name entry so it is immediately after the csv header + */ + + idx3 = 0; + + /* Start with first entries opening quote */ + new_customers_buffer[idx2++] = '\"'; + + /* Copy the customer_name string */ + while( idx3 < FIELD_LENGTH && idx2 < new_customers_buffer_size + && customer_contact_name[idx3] != 0 ) + { + new_customers_buffer[idx2++] = customer_contact_name[idx3++]; + } + + /* Close customer name field with a quote */ + new_customers_buffer[idx2++] = '\"'; + + /* Insert field delimiters, we use a semi-colon, not a comma ';' */ + new_customers_buffer[idx2++] = ';'; + + /* ----------------------------------------------------------------------------- + * Copy the new customer contact phone entry so it is immediately after the csv header + */ + + idx3 = 0; + + /* Start with first entries opening quote */ + new_customers_buffer[idx2++] = '\"'; + + /* Copy the customer_name string */ + while( idx3 < FIELD_LENGTH && idx2 < new_customers_buffer_size + && customer_contact_phone[idx3] != 0 ) + { + new_customers_buffer[idx2++] = customer_contact_phone[idx3++]; + } + + /* Close customer name field with a quote */ + new_customers_buffer[idx2++] = '\"'; + + /* Insert a line feed to finish the new entry */ + new_customers_buffer[idx2++] = LINEFEED; + + /* skip any LINEFEEDS in the existing customer entry as we just inserted one */ + while( customers_buffer[idx1] != 0 && customers_buffer[idx1] == LINEFEED ) + { + idx1++; + } + + /* ------------------------------------------------------------------------------- + * Now copy the existing customer entries, if any, immediately after the new entry + */ + + while( idx1 < existing_file_size && idx2 < new_customers_buffer_size ) + { + /* Removes any nulls when copying and pasting, which would break this process? */ + if( customers_buffer[idx1] == 0 ) + { + while( idx1 < existing_file_size && customers_buffer[idx1] == 0 ) + { + idx1++; + } + } + new_customers_buffer[idx2++] = customers_buffer[idx1++]; + } + + /* Rename the customers.csv file to customers.csv.backup */ + if( rename( nwipe_customers_file, nwipe_customers_file_backup_tmp ) != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Unable to rename %s to %s", + nwipe_customers_file, + nwipe_customers_file_backup_tmp ); + } + else + { + /* Create/open the customers.csv file */ + if( ( fptr2 = fopen( nwipe_customers_file, "wb" ) ) == NULL ) + { + nwipe_log( NWIPE_LOG_ERROR, "Unable to open %s", nwipe_customers_file ); + } + else + { + /* write the new customers.csv file */ + new_customers_buffer_length = strlen( new_customers_buffer ); + + if( ( result_size = fwrite( + new_customers_buffer, sizeof( char ), new_customers_buffer_length, fptr2 ) ) + != new_customers_buffer_length ) + { + nwipe_log( + NWIPE_LOG_ERROR, + "func:write_customer_csv_entry:fwrite: Error result_size = %i not as expected", + result_size ); + } + else + { + /* Remove the customer.csv.backup file if it exists */ + if( remove( nwipe_customers_file_backup ) != 0 ) + { + nwipe_log( + NWIPE_LOG_ERROR, "Unable to remove %s", nwipe_customers_file_backup_tmp ); + } + else + { + /* Rename the customers.csv.backup.tmp file to customers.csv.backup */ + if( rename( nwipe_customers_file_backup_tmp, nwipe_customers_file_backup ) + != 0 ) + { + nwipe_log( NWIPE_LOG_ERROR, + "Unable to rename %s to %s", + nwipe_customers_file, + nwipe_customers_file_backup_tmp ); + } + nwipe_log( NWIPE_LOG_INFO, + "Succesfully write new customer entry to %s", + nwipe_customers_file ); + } + nwipe_log( NWIPE_LOG_INFO, "p_csv_buffer = %li", csv_buffer ); + } + fclose( fptr2 ); + } + } + fclose( fptr ); + } } + free( new_customers_buffer ); } + free( customers_buffer ); } + free( csv_buffer ); } - free( csv_buffer ); - free( customers_buffer ); - free( new_customers_buffer ); } diff --git a/src/customers.h b/src/customers.h index 226daa4..f8fc5bb 100644 --- a/src/customers.h +++ b/src/customers.h @@ -36,4 +36,6 @@ typedef char** nwipe_customers_pointers_t; #define SELECT_CUSTOMER 1 #define DELETE_CUSTOMER 2 +#define LINEFEED 0x0A + #endif // CUSTOMERS_H_INCLUDED diff --git a/src/gui.c b/src/gui.c index 9757db8..f366d8d 100644 --- a/src/gui.c +++ b/src/gui.c @@ -1237,6 +1237,7 @@ void nwipe_gui_select( int count, nwipe_context_t** c ) break; case 'c': + case 'C': /* main configuration menu */ validkeyhit = 1;