// This is the main controlling file for the operation of the program. #include #include #include #include #include #include #include "unique_id.h" #include "time_slot.h" #include "reservations.h" #include "aircraft.h" #include "fleet.h" #include "html.h" #include "data_file.h" #include "cgi_data.h" #include "errors.h" #include "main_private.h" #include "main.h" // This is the main controlling function for the program. After the program // variables are initialized, the request from the client is read in, parsed, // and acted upon. The results are stored in a .dat file, and also returned // to the client via a html page. The html commands are initially written to // a storage space called big_buffer. If a fatal error is encountered, the // error will be returned via a html web page. If no errors are encountered, // the contents of big_buffer are returned to the client. int main() { fleet the_fleet; // only want 1 of these per program int action; int finished = 0; new_aircraft aircraft_data; int res_id; cgi_data *cgi_array = NULL; int cgi_array_length = 0; char new_ac_name[AC_NAME_LEN]; char *new_ac_desc; time_slot_info slot_info; int slot_id; int outcome; initialize(the_fleet); // get the client request parse_input_data(cgi_array, cgi_array_length); // wow, even MORE debug stuff! // int i, j; // for (i = 0; i < cgi_array_length; ++i) // { // cerr << "key = " << cgi_array[i].key << endl; // for (j = 0; j < cgi_array[i].count; ++j) // cerr << "value " << j << " = " << cgi_array[i].value[j] << endl; // } // examine the client request to see what actions will be necessary action = get_request(cgi_array, cgi_array_length, the_fleet, aircraft_data, slot_info, slot_id); // update our aircraft and reservation data, and // create the proper html page switch (action) { case ACTION_SEND_ADD_AC: // return a list of all aircraft to the client create_add_ac_page(); break; case ACTION_SEND_MODIFY_AC: // return a page to let the user change the info for 1 aircraft create_modify_ac_page(aircraft_data); break; case ACTION_REMOVE_THIS_AC: // return a list of all aircraft to the client outcome = the_fleet.remove_ac(aircraft_data.ac_unique_id); if (outcome != SUCCESSFUL) { strcpy(fatal_err_function, "main"); sprintf(fatal_err_msg, "remove_ac() failed for id=%d outcome=%d", aircraft_data.ac_unique_id, outcome); fatal_error(); } create_main_page(the_fleet); break; case ACTION_ADD_THIS_AC: // add the new aircraft to the_fleet the_fleet.add_new_ac(aircraft_data); create_main_page(the_fleet); break; case ACTION_UPDATE_THIS_AC: // update this aircraft name, then the description outcome = the_fleet.update_ac_name(aircraft_data.ac_unique_id, aircraft_data.name); if ( outcome != SUCCESSFUL ) { strcpy(fatal_err_function, "main"); sprintf(fatal_err_msg, "update_ac_name() failed for ac_id=%d name=%s outcome=%d", aircraft_data.ac_unique_id, aircraft_data.name, outcome); fatal_error(); } outcome = the_fleet.update_ac_description(aircraft_data.ac_unique_id, aircraft_data.description); if ( outcome != SUCCESSFUL ) { strcpy(fatal_err_function, "main"); sprintf(fatal_err_msg, "update_ac_desc() failed for ac_id=%d desc=%s outcome=%d", aircraft_data.ac_unique_id, aircraft_data.description, outcome); fatal_error(); } create_main_page(the_fleet); break; case ACTION_SEND_ADD_RES: // return a list of all reservations for a single aircraft to the client create_add_res_page(the_fleet, aircraft_data.ac_unique_id); break; case ACTION_ADD_RES: // add a reservation for a single aircraft, then return a list of // all reservations for that single aircraft to the client outcome = the_fleet.add_ac_reservation(aircraft_data.ac_unique_id, slot_info); switch (outcome) { case SUCCESSFUL: break; case RES_ERR_START_FINISH: strcpy(warning_msg, "reservation finish was earlier than start\n"); break; case RES_ERR_CONFLICT: strcpy(warning_msg, "requested reservation conflicts with existing reservation\n"); break; default: strcpy(fatal_err_function, "main"); sprintf(fatal_err_msg, "add_ac_reservation() failed for ac_id=%d outcome=%d", aircraft_data.ac_unique_id, outcome); fatal_error(); } create_add_res_page(the_fleet, aircraft_data.ac_unique_id); break; case ACTION_DELETE_RES: // delete a reservation for a single aircraft, then return a list of // all reservations for that single aircraft to the client outcome = the_fleet.remove_ac_reservation(aircraft_data.ac_unique_id, slot_id); if (outcome != SUCCESSFUL) { strcpy(fatal_err_function, "main"); sprintf(fatal_err_msg, "remove_ac_reservation() failed for ac_id=%d slot_id=%d outcome=%d", aircraft_data.ac_unique_id, slot_id, outcome); fatal_error(); } create_add_res_page(the_fleet, aircraft_data.ac_unique_id); break; case ACTION_DEFAULT: create_main_page(the_fleet); break; default: strcpy(fatal_err_function, "main"); sprintf(fatal_err_msg, "unexpected action value = %d", action); fatal_error(); } // send the html to stdout and clean up memory cout << big_buffer; nuke_cgi_array(cgi_array, cgi_array_length); cleanup(the_fleet); exit(0); } // Just your basic program initializations. void initialize(fleet & the_fleet) { read_data_file(data_filename, the_fleet); warning_msg[0] = '\0'; } // Final program clean-up operations before shutting down. void cleanup(fleet & the_fleet) { write_data_file(data_filename, the_fleet); } // Look through the cgi_array and find the array member with a key of // 'request'. Read and return the associated value. int get_request(const cgi_data* cgi_array, const int cgi_array_length, fleet & the_fleet, new_aircraft & aircraft_data, time_slot_info & slot_info, int & slot_id) { int request; int found = 0; int finished = 0; int i = 0; char buffer[64]; // initializations slot_info.slot_unique_id = 0; slot_info.name[0] = '\0'; slot_info.start = 0; slot_info.finish = 0; slot_id = 0; // if there is no "request" key in the cgi_array, just send back // the default main html page if ( find_corresponding_single_value(cgi_array, cgi_array_length, "request", buffer) == 0 ) { request = ACTION_DEFAULT; } else if ( strcmp(buffer, "send_update") == 0 ) { // could be a send-airplane-update or a send-reservation-update request = get_send_update_request(cgi_array, cgi_array_length, the_fleet, aircraft_data); } else if ( strcmp(buffer, "res_update") == 0 ) { // could be a reservation delete or a new reservation request = get_res_update_request(cgi_array, cgi_array_length, the_fleet, aircraft_data.ac_unique_id, slot_info, slot_id); } else if ( strcmp(buffer, "ac_add") == 0 ) { // This should have all the data necessary for adding a new aircraft request = get_ac_add_request(cgi_array, cgi_array_length, the_fleet, aircraft_data); } else if ( strcmp(buffer, "ac_update") == 0 ) { // This should have all the data necessary for updating an // existing aircraft request = get_ac_update_request(cgi_array, cgi_array_length, the_fleet, aircraft_data); } else { strcpy(fatal_err_function, "get_request"); sprintf(fatal_err_msg, "unexpected buffer value = %s", buffer); fatal_error(); } return request; } // Figure out if the user wants to update the aircraft or the reservations // for a particular aircraft. Calling function should include this code: // // // get rid of un-needed memory // delete [] aircraft_data.description; int get_send_update_request(const cgi_data* cgi_array, const int cgi_array_length, fleet & the_fleet, new_aircraft & aircraft_data) { int request; char buffer[64]; int outcome; // get the aircraft unique_id (unless the fleet is empty) if ( find_corresponding_single_value(cgi_array, cgi_array_length, "ac", buffer) != 0 ) { aircraft_data = the_fleet.find_one_ac(0, buffer, outcome); if (outcome != SUCCESSFUL) { strcpy(fatal_err_function, "get_send_update_request"); sprintf(fatal_err_msg, "call to find_one_ac failed using name = %s", buffer); fatal_error(); } } // figure out what the user wants to do if ( find_corresponding_single_value(cgi_array, cgi_array_length, "action", buffer) == 0 ) { strcpy(fatal_err_function, "get_send_update_request"); sprintf(fatal_err_msg, "unable to find key=action"); fatal_error(); } // is this an update-aircraft request or a update-reservation request? if ( strstr(buffer, "reserve") != NULL ) { // its a reservation for a particular aircraft request = ACTION_SEND_ADD_RES; if (aircraft_data.ac_unique_id == 0) { strcpy(fatal_err_function, "get_send_update_request"); sprintf(fatal_err_msg, "reservation request had aircraft_data.ac_unique_id value 0"); fatal_error(); } } else if ( strstr(buffer, "add") != NULL ) { // the user wants to add a new aircraft request = ACTION_SEND_ADD_AC; } else if ( strstr(buffer, "modify") != NULL ) { // the user wants to modify an existing aircraft request = ACTION_SEND_MODIFY_AC; if (aircraft_data.ac_unique_id == 0) { strcpy(fatal_err_function, "get_send_update_request"); sprintf(fatal_err_msg, "aircraft modify request had aircraft_data.ac_unique_id value 0"); fatal_error(); } } else // assume it's a "delete" request { // the user wants to delete an existing request = ACTION_REMOVE_THIS_AC; if (aircraft_data.ac_unique_id == 0) { strcpy(fatal_err_function, "get_send_update_request"); sprintf(fatal_err_msg, "aircraft delete request had aircraft_data.ac_unique_id value 0"); fatal_error(); } } return request; } // Find out exactly what kind of aircraft update the user wants to do. int get_res_update_request(const cgi_data* cgi_array, const int cgi_array_length, fleet & the_fleet, int & ac_id, time_slot_info & res_info, int & slot_id) { int request = ACTION_ADD_RES; int finished = 0; int i = 0; char buffer[64]; ac_id = 0; // the "submit_button" should either be "cancel" or "GO" if ( find_corresponding_single_value(cgi_array, cgi_array_length, "submit_button", buffer) == 0 ) { strcpy(fatal_err_function, "get_res_update_request"); sprintf(fatal_err_msg, "unable to find key=submit_button"); fatal_error(); } // if the user hit the cancel button, go back to the main html page if ( strcmp(buffer, "cancel") == 0 ) { request = ACTION_DEFAULT; } else { // grab the aircraft unique_id if ( find_corresponding_single_value(cgi_array, cgi_array_length, "ac_id", buffer) == 0 ) { strcpy(fatal_err_function, "get_res_update_request"); sprintf(fatal_err_msg, "unable to find key=ac_id"); fatal_error(); } ac_id = atoi(buffer); // grab the value from the "action" pop-up list if ( find_corresponding_single_value(cgi_array, cgi_array_length, "action", buffer) == 0 ) { strcpy(fatal_err_function, "get_res_update_request"); sprintf(fatal_err_msg, "unable to find key=action"); fatal_error(); } // if the user selected the "add new reservation" action, process the // new-reservation fields if ( strcmp(buffer, "add new reservation") == 0 ) { if ( get_new_reservation_info(cgi_array, cgi_array_length, res_info) != SUCCESSFUL ) { request = ACTION_SEND_ADD_RES; } else { request = ACTION_ADD_RES; } } // if the user selected the "delete old reservation" action, process the // delete-reservation fields else if ( strcmp(buffer, "delete old reservation") == 0 ) { slot_id = get_old_reservation_id(cgi_array, cgi_array_length, ac_id, the_fleet); request = ACTION_DELETE_RES; } else { strcpy(fatal_err_function, "get_res_update_request"); sprintf(fatal_err_msg, "unexpected value in buffer = %s", buffer); fatal_error(); } } return request; } // This function takes as input a "key", and searches the // cgi_array for the corresponding "value". The calling function should pass // in a char* value buffer large enough to hold the value string. // Returned value will be 1 if found, and 0 if not found. This function // will only work if the key is associated with a single value. So, this // function would not work for a multiple selection scrolled list. int find_corresponding_single_value(const cgi_data* cgi_array, const int cgi_array_length, const char* key, char *value) { int found = 0; int finished = 0; int i = 0; while ( (!found) && (!finished) ) { if (i == cgi_array_length) finished = 1; else if ( strcmp(cgi_array[i].key, key) == 0 ) { found = 1; strcpy(value, cgi_array[i].value[0]); } else { ++i; } } return found; } // Fill a time_slot_info structure with new reservation data from the // cgi_array. Function returns SUCCESSFUL or an error code. int get_new_reservation_info(const cgi_data* & cgi_array, const int & cgi_array_length, time_slot_info & res_info) { int outcome = SUCCESSFUL; struct tm t; char name[MAX_NAME_LEN]; char month[4]; char date[3]; char year[5]; char hour[3]; char min[3]; // these values are for the "start" time if ( ( find_corresponding_single_value(cgi_array, cgi_array_length, "user", name) == 0 ) || ( find_corresponding_single_value(cgi_array, cgi_array_length, "from_month", month) == 0 ) || ( find_corresponding_single_value(cgi_array, cgi_array_length, "from_date", date) == 0 ) || ( find_corresponding_single_value(cgi_array, cgi_array_length, "from_year", year) == 0 ) || ( find_corresponding_single_value(cgi_array, cgi_array_length, "from_hour", hour) == 0 ) || ( find_corresponding_single_value(cgi_array, cgi_array_length, "from_min", min) == 0 ) ) { strcpy(fatal_err_function, "get_new_reservation_info"); sprintf(fatal_err_msg, "bad values in start time or user name"); fatal_error(); } if (name[0] == '\0') { strcpy(warning_msg, "Reservation name was blank."); strcat(warning_msg, "Reservation name is a required value."); outcome = RES_ERR_NO_NAME; } else { res_info.slot_unique_id = get_unique_id(); strcpy(res_info.name, name); // convert the struct tm time into time_t time t.tm_mon = month_string_to_int(month) - 1; t.tm_mday = atoi(date); t.tm_year = atoi(year) - 1900; t.tm_hour = atoi(hour); t.tm_min = atoi(min); t.tm_sec = 0; res_info.start = mktime(&t); if (res_info.start == BAD_TIME) { strcpy(fatal_err_function, "get_new_reservation_info"); sprintf(fatal_err_msg, "start mktime() failed, t=%d", t); fatal_error(); } // these values are for the "finish" time if ( ( find_corresponding_single_value(cgi_array, cgi_array_length, "to_month", month) == 0 ) || ( find_corresponding_single_value(cgi_array, cgi_array_length, "to_date", date) == 0 ) || ( find_corresponding_single_value(cgi_array, cgi_array_length, "to_year", year) == 0 ) || ( find_corresponding_single_value(cgi_array, cgi_array_length, "to_hour", hour) == 0 ) || ( find_corresponding_single_value(cgi_array, cgi_array_length, "to_min", min) == 0 ) ) { strcpy(fatal_err_function, "get_new_reservation_info"); sprintf(fatal_err_msg, "bad values in finish time"); fatal_error(); } // convert struct tm time to time_t time t.tm_mon = month_string_to_int(month) - 1; t.tm_mday = atoi(date); t.tm_year = atoi(year) - 1900; t.tm_hour = atoi(hour); t.tm_min = atoi(min); t.tm_sec = 0; res_info.finish = mktime(&t); if (res_info.finish == BAD_TIME) { strcpy(fatal_err_function, "get_new_reservation_info"); sprintf(fatal_err_msg, "finish mktime() failed, t=%d", t); fatal_error(); } } return outcome; } // Convert a month string like "Sep" to a digit like 9. int month_string_to_int(const char* month_string) { int month_int; if ( strncmp(month_string, "Jan", 3) == 0 ) { month_int = 1; } else if ( strncmp(month_string, "Feb", 3) == 0 ) { month_int = 2; } else if ( strncmp(month_string, "Mar", 3) == 0 ) { month_int = 3; } else if ( strncmp(month_string, "Apr", 3) == 0 ) { month_int = 4; } else if ( strncmp(month_string, "May", 3) == 0 ) { month_int = 5; } else if ( strncmp(month_string, "Jun", 3) == 0 ) { month_int = 6; } else if ( strncmp(month_string, "Jul", 3) == 0 ) { month_int = 7; } else if ( strncmp(month_string, "Aug", 3) == 0 ) { month_int = 8; } else if ( strncmp(month_string, "Sep", 3) == 0 ) { month_int = 9; } else if ( strncmp(month_string, "Oct", 3) == 0 ) { month_int = 10; } else if ( strncmp(month_string, "Nov", 3) == 0 ) { month_int = 11; } else if ( strncmp(month_string, "Dec", 3) == 0 ) { month_int = 12; } else { strcpy(fatal_err_function, "month_string_to_int"); sprintf(fatal_err_msg, "unexpected month string = %s", month_string); fatal_error(); } return month_int; } // Find the unique id of the reservation specified in cgi_data. int get_old_reservation_id(const cgi_data* & cgi_array, const int cgi_array_length, const int ac_id, fleet & the_fleet) { int res_id = 0; struct tm t; time_t start_time; char *hr_min_ptr; char *month_ptr; char *date_ptr; char *year_ptr; all_ac_data all_data; int i; int found = 0; int finished = 0; char buffer[64]; int outcome; if ( find_corresponding_single_value(cgi_array, cgi_array_length, "res", buffer) == 0 ) { strcpy(fatal_err_function, "get_old_reservation_id"); sprintf(fatal_err_msg, "unable to find key=res"); fatal_error(); } // buffer now contains a string like "Sanderson 0900 9/20/02". Turn the // date and time into a time_t value and find this value in the // linked list of reservations associated with this aircraft. hr_min_ptr = strtok(buffer, " "); // skip over the name hr_min_ptr = strtok(NULL, " "); month_ptr = strtok(NULL, "/"); date_ptr = strtok(NULL, "/"); year_ptr = strtok(NULL, "\0"); if ( (hr_min_ptr == NULL) || (month_ptr == NULL) || (date_ptr == NULL) || (year_ptr == NULL) ) { strcpy(fatal_err_function, "get_old_reservation_id"); sprintf(fatal_err_msg, "strtok() returned some NULL values"); fatal_error(); } // load values into the struct tm and then use mktime() to convert the // values to time_t t.tm_mon = atoi(month_ptr) - 1; t.tm_mday = atoi(date_ptr); t.tm_year = atoi(year_ptr) + 100; t.tm_hour = atoi(hr_min_ptr) / 100; t.tm_min = atoi(hr_min_ptr) % 100; t.tm_sec = 0; start_time = mktime(&t); if (start_time == BAD_TIME) { strcpy(fatal_err_function, "get_old_reservation_id"); sprintf(fatal_err_msg, "mktime() failed"); fatal_error(); } // get a list of all reservations for this aircraft all_data = the_fleet.find_all_ac_data(ac_id, outcome); if (outcome != SUCCESSFUL) { strcpy(fatal_err_function, "get_old_reservation_id"); sprintf(fatal_err_msg, "find_all_ac_data() failed to find id=%d", ac_id); fatal_error(); } // look for the start_time in each reservation i = 0; while ( (!found) && (!finished) ) { if (i == all_data.res_count) { finished = 1; } else if (all_data.all_res[i].start == start_time) { res_id = all_data.all_res[i].slot_unique_id; found = 1; } else { ++i; } } if (!found) { strcpy(fatal_err_function, "get_old_reservation_id"); sprintf(fatal_err_msg, "unable to find start time %d", start_time); fatal_error(); } // return un-needed memory delete [] all_data.spec.description; delete [] all_data.all_res; return res_id; } // This should have all the data necessary to add a new aircraft int get_ac_add_request(const cgi_data* cgi_array, const int cgi_array_length, fleet & the_fleet, new_aircraft & aircraft_data) { int request; int finished = 0; int i = 0; char buffer[64]; new_aircraft new_ac; int outcome; if ( find_corresponding_single_value(cgi_array, cgi_array_length, "submit_button", buffer) == 0 ) { strcpy(fatal_err_function, "get_ac_add_request"); sprintf(fatal_err_msg, "unable to find key=submit_button"); fatal_error(); } // if the user hit the cancel button, go back to the main html page if ( strcmp(buffer, "cancel") == 0 ) { request = ACTION_DEFAULT; } else { outcome = get_ac_text_fields(cgi_array, cgi_array_length, aircraft_data); if (outcome != SUCCESSFUL) { request = ACTION_SEND_ADD_AC; } else { // don't allow duplicate aircraft names new_ac = the_fleet.find_one_ac(0, aircraft_data.name, outcome); if (outcome == SUCCESSFUL) { strcpy(warning_msg, "The aircraft name "); strcat(warning_msg, aircraft_data.name); strcat(warning_msg, " is already in the fleet."); strcat(warning_msg, "Duplicate aircraft names are not allowed."); request = ACTION_SEND_ADD_AC; } else { aircraft_data.ac_unique_id = get_unique_id(); request = ACTION_ADD_THIS_AC; } } } return request; } // This should have all the data necessary to update an existing aircraft int get_ac_update_request(const cgi_data* cgi_array, const int cgi_array_length, fleet & the_fleet, new_aircraft & aircraft_data) { int request = ACTION_SEND_ADD_AC; int finished = 0; int i = 0; char buffer[64]; new_aircraft new_ac; int outcome; if ( find_corresponding_single_value(cgi_array, cgi_array_length, "submit_button", buffer) == 0 ) { strcpy(fatal_err_function, "get_ac_update_request"); sprintf(fatal_err_msg, "unable to find key=submit_button"); fatal_error(); } // if the user hit the cancel button, go back to the main html page if ( strcmp(buffer, "cancel") == 0 ) { request = ACTION_DEFAULT; } else { // grab the unique id for the aircraft if ( find_corresponding_single_value(cgi_array, cgi_array_length, "ac_id", buffer) == 0 ) { strcpy(fatal_err_function, "get_ac_update_request"); sprintf(fatal_err_msg, "unable to find key=ac_id"); fatal_error(); } aircraft_data.ac_unique_id = atoi(buffer); outcome = get_ac_text_fields(cgi_array, cgi_array_length, aircraft_data); if (outcome != SUCCESSFUL) { request = ACTION_SEND_MODIFY_AC; } else { new_ac = the_fleet.find_one_ac(aircraft_data.ac_unique_id, NULL, outcome); if (outcome != SUCCESSFUL) { strcpy(fatal_err_function, "get_ac_update_request"); sprintf(fatal_err_msg, "ac_id %d not found in database", aircraft_data.ac_unique_id); fatal_error(); } request = ACTION_UPDATE_THIS_AC; } } return request; } // Grab the aircraft name and description fields from cgi_data. int get_ac_text_fields(const cgi_data* cgi_array, const int cgi_array_length, new_aircraft & aircraft_data) { int outcome = SUCCESSFUL; aircraft_data.description = new char[1280]; if ( find_corresponding_single_value(cgi_array, cgi_array_length, "ac_name", aircraft_data.name) == 0 ) { strcpy(fatal_err_function, "get_ac_text_fields"); sprintf(fatal_err_msg, "ac_name not found"); fatal_error(); } if (aircraft_data.name[0] == '\0') { strcpy(warning_msg, "No aircraft name entered.\n"); strcat(warning_msg, "Aircraft name is a required field.\n"); outcome = AC_ERR_NO_NAME; } if ( find_corresponding_single_value(cgi_array, cgi_array_length, "ac_desc", aircraft_data.description) == 0 ) { strcpy(fatal_err_function, "get_ac_text_fields"); sprintf(fatal_err_msg, "ac_desc not found"); fatal_error(); } if (aircraft_data.description[0] == '\0') { strcpy(warning_msg, "No aircraft description entered.\n"); strcat(warning_msg, "Aircraft description is a required field.\n"); outcome = AC_ERR_NO_DESC; } else { // make sure there is a '\n' character at the end of the description if ( ( aircraft_data.description[ strlen(aircraft_data.description) - 1 ] ) != '\n' ) { strcat(aircraft_data.description, "\n"); } } return outcome; } // Find the unique id of the aircraft referenced in the cgi_array. int get_old_ac_id(const cgi_data* cgi_array, const int cgi_array_length, fleet & the_fleet) { new_aircraft old_ac; char ac_name[AC_NAME_LEN]; int outcome; if ( find_corresponding_single_value(cgi_array, cgi_array_length, "ac", ac_name) == 0 ) { strcpy(fatal_err_function, "get_old_ac_id"); sprintf(fatal_err_msg, "ac not found"); fatal_error(); } old_ac = the_fleet.find_one_ac(0, ac_name, outcome); if (outcome != SUCCESSFUL) { old_ac.ac_unique_id = 0; } return old_ac.ac_unique_id; }