/***************************************************************** (c) Rob Hartill 1994 This program converts a HTTP POSTed FORMs request into another FORM which describes the selections made in the previous FORM, allowing the user to toggle each selection on or off. An addional toggle enables the user to select whether the listed items are to be searched for on a ANDed or ORed matching field basis. The output is a HTTP POSTed request consisting of a series of items, at most one item per field, with the following format, field_number|search_type|search_item[/search_item]*=on& ^^^ the '=on' is attached by the WWW browser -+++ search_type is a numeric description of the type of search to be performed, e.g. substrings ANDed substrings ORed numeric/numeric ranges century/century ranges Nothing in this file needs to be altered, all user (re)configurable features are accessed via the config.h file. *****************************************************************/ #include #include #include #include #include #include "config.h" char *in_lowercase(); char *space_to_plus(); char *plus_to_space(); char *slash_to_and(); char *slash_to_or(); char *decode_escape_sequences(); char *encode_escape_sequences(); char *in_lowercase(); int escaped_length(); int anded_length(); int unplussed_length(); char *plus_to_20(); char *slash_from_2F(); #define FORMAT_FOR_POSTING(LIST) \ slash_from_2F(plus_to_20(LIST)) #define FORMAT_ANDED_ITEMS_FOR_VIEWING(LIST) \ slash_to_and(decode_escape_sequences(plus_to_space(LIST))) #define FORMAT_ORED_ITEMS_FOR_VIEWING(LIST) \ slash_to_or(decode_escape_sequences(plus_to_space(LIST))) void main() { int xx, /* check the xxth field called 'xx' to tie in with s_xx r_xx etc */ query_method[FIELDS_PER_RECORD], /* Each field being searched will have a search method (AND/OR/YEAR/CENTURY) */ content_length; /* The length in bytes of the input */ char *unchecked, /* ptr to the remaining unchecked input for the xxth field */ key[5], /* s_xx, r_xx, c_xx etc */ *next_key, /* ptr to a s_xx, r_xx, c_xx in the input */ *query_string[FIELDS_PER_RECORD],/* ptr to a list of search items for a particular field. */ *next_query_string, /* ptr to a list of search items for the current field. */ *unprocessed_query, /* The input to this program, POSTed by a HTTP browser. */ *for_viewing, /* will point to a malloc'ed string holding a list of search items. */ *for_posting; /* will point to a malloc'ed string holding a list of search items. */ printf("Content-type: text/html\n\n%s",URL_TITLE); /* keeps mosaic happy */ printf(QUERY_CHECK_MESSAGE); content_length = atoi(getenv("CONTENT_LENGTH")); /* Reserve some space to hold the input */ unprocessed_query = (char *) malloc(content_length+2); /* Reserve some space to hold the output */ next_query_string = (char *) malloc(content_length+2); if (unprocessed_query == NULL || next_query_string == NULL) { printf("Unable to reserve enough memory to parse the request
\n"); return; } /* Read the input query. */ fgets(unprocessed_query, content_length+1, stdin); /* Add a '&' field delimiter for good measure. */ strcat(unprocessed_query,"&"); #ifdef DEBUGGING printf("DEBUGGING..%s %d
",unprocessed_query, strlen(unprocessed_query)); #endif printf("
\n"); /* For each possible field of the database, look to see if we want to perform a search on it. */ for (xx= 1; xx<= FIELDS_PER_RECORD; xx++) { (char *) (query_string[xx-1]) = next_query_string; *next_query_string = '\0'; /*================================================================*/ /* first look for s_xx entires */ sprintf(key, "s_%02d=", xx); /* key = 's_01=' 's_02=' 's_03=' etc */ unchecked = unprocessed_query; /* look at the start of the input */ while ( (next_key = strstr(unchecked, key)) != NULL) { /* substring searches for a list of susbstrings will be for matching records with ALL (and) or ANY (or) of the substrings. */ if (strncmp(next_key + 5, "ANDING", 6) ==0 ) { unchecked = next_key + (5 + 6); query_method[xx-1] = ANDING; continue; } if (strncmp(next_key + 5, "ORING", 5) == 0) { unchecked = next_key + (5 + 5); query_method[xx-1] = ORING; continue; } /* This item must be a substring or '/' delimited list of substrings. */ if (*(next_key + 5) != '&') { strcat(next_query_string, "/"); strcat(next_query_string, next_key + 5); } if ( strchr(next_query_string, '&') != NULL) *strchr(next_query_string, '&') = '\0'; if ( (next_key = strchr(next_key, '&')) != NULL) unchecked = next_key+1; else break; /* There are no more '&' delimited items in the input */ } /*================================================================*/ /* now look for r_xx entires */ sprintf(key, "r_%02d=", xx); /* key = 'r_01=' 'r_02=' 'r_03=' etc */ unchecked = unprocessed_query; /* go back to the start of the input */ /* There will be at most one 'r_xx' entry, so either it's there or it isn't */ if ( (next_key = strstr(unchecked, key)) != NULL) { strcat(next_query_string,"/"); strcat(next_query_string, next_key+5); if ( (next_key = strchr(next_query_string, '&')) != NULL) *next_key = '\0'; query_method[xx-1] = YEARS; } /*================================================================*/ /* NOW LOOK FOR r_xx ENTIRES */ sprintf(key, "c_%02d=", xx); /* key = 'c_01=' 'c_02=' 'c_03=' ETC */ unchecked = unprocessed_query; /* go back to the start of the input */ /* There will be at most one 'c_xx' entry, so either it's there or it isn't */ if ( (next_key = strstr(unchecked, key)) != NULL) { strcat(next_query_string,"/"); strcat(next_query_string, next_key+5); if ( (next_key = strchr(next_query_string, '&')) != NULL) *next_key = '\0'; query_method[xx-1] = CENTURIES; } next_query_string += strlen(next_query_string) +1; } /*================================================================*/ printf("
\n"); for (xx= 1; xx<= FIELDS_PER_RECORD; xx++) { next_query_string = query_string[xx-1]; if ( strlen(next_query_string) > 1 ) { for_viewing = (char *) malloc(anded_length(next_query_string) + 1); if (for_viewing == NULL) {printf("Not enough memory "); return;} for_posting = (char *) malloc(escaped_length(next_query_string) + 1); if (for_posting == NULL) {printf("Not enough memory "); return;} strcpy(for_posting, next_query_string+1); FORMAT_FOR_POSTING(for_posting); strcpy(for_viewing, next_query_string+1); if (query_method[xx-1] == ANDING) FORMAT_ANDED_ITEMS_FOR_VIEWING(for_viewing); else FORMAT_ORED_ITEMS_FOR_VIEWING(for_viewing); if (query_method[xx-1] == ANDING) printf("
The %s must contain:\n
%s\n", xx, ANDING, for_posting, field_names[xx-1], for_viewing); if (query_method[xx-1] == ORING) printf("
The %s must contain:\n
%s\n", xx, ORING, for_posting, field_names[xx-1], for_viewing); if (query_method[xx-1] == YEARS) printf("
The %s must be a year equal to or in the range... %s\n", xx, YEARS, for_posting, field_names[xx-1], for_viewing); if (query_method[xx-1] == CENTURIES) printf("
The %s must be a century equal to or in the range... %s\n", xx, CENTURIES, for_posting, field_names[xx-1], for_viewing); free(for_viewing); free(for_posting); } } printf("

\n"); printf(" See the records in which all the selected conditions apply.
or
\n"); printf(" See the records in which any of selected conditions apply.
\n"); printf("
\n"); printf(END_CHECK_MESSAGE); free(unprocessed_query); free(query_string[0]); } /****************************************************************** in_lowercase returns a pointer to it's input which will have had it's uppercase characters converted to lowercase *******************************************************************/ char *in_lowercase(to_convert) char *to_convert; { int indx = 0; while (to_convert[indx] != '\0') { to_convert[indx] = tolower(to_convert[indx]); indx++; } return to_convert; } /****************************************************************** plus_to_space returns a pointer to it's input which will have had it's pluses converted to spaces *******************************************************************/ char *plus_to_space(string) char *string; { int indx; indx = 0; while( string[indx] != '\0' ) { if (string[indx] == '+') string[indx] = ' '; indx++; } return string; } /************************************************************** decode_escape_sequences takes a string as input, and translates HTTP escape sequences, format %hh, into plain ASCII ***************************************************************/ char *decode_escape_sequences(request) char *request; { int indx,indx2; long hex_char; char hex_num[3]; indx = indx2 = 0; while ( request[indx] != '\0' ) { if ( request[indx] == '%') { if ((request[indx+1] >='0' && request[indx+1] <= '9') || (request[indx+1] >='A' && request[indx+1] <= 'F')) { if ((request[indx+2] >='0' && request[indx+2] <= '9') || (request[indx+2] >='A' && request[indx+2] <= 'F')) { hex_num[0] = request[indx+1]; hex_num[1] = request[indx+2]; hex_num[2] = '\0'; hex_char = strtol(hex_num,(char **)NULL,16); request[indx2++] = (char) hex_char; indx += 3; } else request[indx2++] = request[indx++]; } else request[indx2++] = request[indx++]; } else request[indx2++] = request[indx++]; } request[indx2] = '\0'; return request; } /************************************************************** encode_escape_sequences takes a string as input, and translates ASCII into HTTP escape sequences, format %hh ***************************************************************/ char *encode_escape_sequences(request) char *request; { char *tmp_string; int indx,indx2; long hex_char; char hex_num[3]; tmp_string = (char *) malloc(escaped_length(request)+1); if (tmp_string == NULL) { printf("Error. Not enough memory\n
") ; exit(-1); } indx = indx2 = 0; while ( request[indx] != '\0' ) { if ( /*request[indx] != '+' &&*/ request[indx] != '/' && ((request[indx] < 'a' || request[indx] > 'z') && (request[indx] < 'A' || request[indx] > 'Z')) ) { sprintf(tmp_string+indx2,"%%%2X", (char) request[indx]); indx2 += 3; indx++; } else tmp_string[indx2++] = request[indx++]; } tmp_string[indx2] = '\0'; strcpy(request, tmp_string); free(tmp_string); return request; } /****************************************************************** slash_to_and returns a pointer to it's input which will have had it's /s converted to " and "s *******************************************************************/ char *slash_to_and(request) char *request; { char *tmp_string; int indx,indx2; tmp_string = (char *) malloc(anded_length(request)+1); if (tmp_string == NULL) {printf("Error. Not enough memory\n
") ; exit(-1);} strcpy(tmp_string,""); indx = indx2 = 0; while ( request[indx] != '\0' ) { if ( request[indx] == '/' ) { strcat(tmp_string," and "); indx2 += 12; } else sprintf(tmp_string+(indx2++),"%c\0", request[indx]); indx++; } strcpy(request, tmp_string); free(tmp_string); return request; } /****************************************************************** slash_to_and returns a pointer to it's input which will have had it's /s converted to " or "s *******************************************************************/ char *slash_to_or(request) char *request; { char *tmp_string; int indx,indx2; tmp_string = (char *) malloc(anded_length(request)); if (tmp_string == NULL) {printf("Error. Not enough memory\n
") ; exit(-1);} strcpy(tmp_string,""); indx = indx2 = 0; while ( request[indx] != '\0' ) { if ( request[indx] == '/' ) { strcat(tmp_string," or "); indx2 += 11; } else sprintf(tmp_string+(indx2++),"%c\0", request[indx]); indx++; } strcpy(request, tmp_string); free(tmp_string); return request; } /****************************************************************** escaped_length returns the length of its input string, after it would have replaced characters with escape sequences. *******************************************************************/ int escaped_length(request) char *request; { int indx, indx2; indx = indx2 = 0; while ( request[indx] != '\0' ) { if ( /*request[indx] != '+' &&*/ ((request[indx] < 'a' || request[indx] > 'z') && (request[indx] < 'A' || request[indx] > 'Z')) ) { indx2 += 3; indx++; } else {indx2++; indx++;} } return indx2; } /****************************************************************** andedd_length returns the length of its input string, after it would have replaced /s with " and "s. *******************************************************************/ int anded_length(request) char *request; { int indx, indx2; indx = indx2 = 0; while ( request[indx] != '\0' ) { if ( request[indx] == '/' ) { indx2 += 12; indx++; } else {indx2++; indx++;} } return indx2; } /************************************************************** plus_to_20 takes a string as input, and translates + into %20 ***************************************************************/ char *plus_to_20(request) char *request; { char *tmp_string; int indx,indx2; long hex_char; char hex_num[3]; tmp_string = (char *) malloc(unplussed_length(request)+1); if (tmp_string == NULL) { printf("Error. Not enough memory\n
") ; exit(-1); } indx = indx2 = 0; while ( request[indx] != '\0' ) { if ( request[indx] == '+' ) { sprintf(tmp_string+indx2,"%%20"); indx2 += 3; indx++; } else tmp_string[indx2++] = request[indx++]; } tmp_string[indx2] = '\0'; strcpy(request, tmp_string); free(tmp_string); return request; } /************************************************************** unplussed_length takes a string as input, and returns its length if it were to translates + into %20 ***************************************************************/ int unplussed_length(request) char *request; { int indx,indx2; long hex_char; char hex_num[3]; indx = indx2 = 0; while ( request[indx] != '\0' ) { if ( request[indx] == '+' ) { indx2 += 3; indx++; } {indx2++; indx++;} } return indx2; } /************************************************************** slash_from_2F takes a string as input, and translates %2F into '/' ***************************************************************/ char *slash_from_2F(request) char *request; { int indx,indx2; long hex_char; char hex_num[3]; indx = indx2 = 0; while ( request[indx] != '\0' ) { if ( strncmp(request+indx,"%2F",3) == 0) { request[indx2++] = '/'; indx += 3; } else request[indx2++] = request[indx++]; } request[indx2] = '\0'; return request; }