/********************************************************************* This file is used as part of Siworin. Copyright © 2014,2015,2021 by Ruud Harmsen. Siworin is a simple word indexer and local search engine. See https://rudhar.com/sfreview/siworin/#siw04 and https://rudhar.com/sfreview/siworin/toolsrc/siworin . Siworin 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. Siworin 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 Siworin. If not, see . ********************************************************************/ /* Copyright 2014-2015, R.Harmsen. This source file is made available under the Creative Commons License Attribution-ShareAlike 4.0 International, see https://creativecommons.org/licenses/by-sa/4.0/ . See also: https://rudhar.com/lingtics/intrlnga/cgi-grep/derautia.htm and https://rudhar.com/lingtics/intrlnga/cgi-grep/modempia.htm for clarifications. */ #include #include #include #include #include "../cgitools/cgitools.h" static char **intern_CgiConvVars (char *Input, int *NumVars, int Delim); /*********************************************************************** For use with Forms with METHOD=POST. Returns zero when first displaying the form, when the user did not have a chance to enter anything yet. In the other situation, it returns the number of bytes to be read from stdin, to get the user's encoded input. **********************************************************************/ int userinput (void) { int l; char *ContentLength = "CONTENT_LENGTH"; if (getenv(ContentLength) && (l = atoi(getenv(ContentLength))) > 0) { return l; } else return 0; } /*********************************************************************** Translate strings like "An+equal+sign%3A+%3D%0D%0AA+procent+sign%3A+%25%0D%0A" into: "An equal sign: =\r\nA procent sign: %\r\n" **********************************************************************/ char *decode_cgi_string (char *in) { char *p, *q; int dig1, dig0; for (p = in, q = in; *p; p++, q++) { if (*p == '+') { *q = ' '; } else if ( dig1 = p[1], dig0 = p[2], *p == '%' && isxdigit(dig1) && isxdigit(dig0)) { if (isdigit(dig0)) dig0 = dig0 - '0'; else dig0 = tolower(dig0) - 'a' + 10; if (isdigit(dig1)) dig1 = dig1 - '0'; else dig1 = tolower(dig1) - 'a' + 10; *q = (dig1 << 4) | dig0; p += 2; } else *q = *p; } *q = '\0'; return in; } /*********************************************************************** Compare two multi-line texts, and display only lines that don't have the same length, one above the other. **********************************************************************/ int repdiff (char *t1, char *t2) { char *p1, *p2; char *n1, *n2; p1 = t1, p2 = t2; while (p1 && p2 && (n1 = strchr(p1, '\n')) != NULL && (n2 = strchr(p2, '\n')) != NULL) { if (n1 - p1 != n2 - p2) { printf("%.*s\n", (int)(n1 - p1), p1); printf("%.*s\n", (int)(n2 - p2), p2); printf("\n"); } p1 = n1 + 1; p2 = n2 + 1; } if (p1 && p2 && (strlen(p1) || strlen(p2)) && strlen(p1) != strlen(p2)) { printf("%s\n", p1); printf("%s\n", p2); printf("\n"); } return 0; } /*********************************************************************** Input is a string like: var1=value1&var2=value2 Output is a malloc'ed array of character pointers. Each pair of pointers points into input, the first of the pair points to the variable name, the other to the value. Function decode_cgi_string is run on the value. There is an extra pair of pointers which are both NULL, to signal the end of the array. In addition, if numvars is not NULL, the integer it points to is set to the number of pairs (not counting the closing pair). The function returns a pointer to the first pointer of the returned array. Note that delimiters = and & are replaced by null bytes, so Input must point to writable memory, not a constant string. **********************************************************************/ char **CgiConvVars (char *Input, int *NumVars) { return intern_CgiConvVars (Input, NumVars, '&'); } /*********************************************************************** Same as CgiConvVars, but for a string that contains cookies, seperated by semicolons (;). **********************************************************************/ char **CgiConvCookies (char *Input, int *NumVars) { return intern_CgiConvVars (Input, NumVars, ';'); } /*********************************************************************** **********************************************************************/ static char **intern_CgiConvVars (char *Input, int *NumVars, int Delim) { char **VarValues; char **Var; int numvars = 0; char *equ, *amp; char *In = Input; VarValues = malloc(sizeof (char *) * 2 * (numvars + 2)); if (!VarValues) return VarValues; Var = VarValues; while ((equ = strchr(In, '=')) != NULL) { int last = 0; if (Var - VarValues < numvars * 2) { char **NewP; NewP = realloc(VarValues, sizeof (char *) * 2 * (numvars + 2)); if (!NewP) { break; } else { VarValues = NewP; Var = VarValues + numvars * 2; } } if ((amp = strchr(equ + 1, Delim)) == NULL) { amp = equ + strlen(equ); last = 1; } *amp = '\0'; *equ = '\0'; /* Skip any spaces after ; and before the start of the 'variable name'. This happens when decoding cookie strings. */ for ( ; isspace(*In); In++) ; Var[0] = In; Var[1] = equ + 1; In = amp + 1; decode_cgi_string(equ + 1); numvars++; if (last) break; } VarValues[numvars * 2 ] = NULL; VarValues[numvars * 2 + 1] = NULL; if (NumVars) *NumVars = numvars; return VarValues; } /************************************************************************** *************************************************************************/ char *logfile_name = "cgidebug"; #include void killroy_log (char *format, ...) { va_list ap; FILE *logfp; va_start(ap, format); logfp = fopen(logfile_name, "ab"); vfprintf(logfp, format, ap); fclose(logfp); va_end(ap); } /************************************************************************** *************************************************************************/ char *CgiToolsExpandit (char *string_to_expand) { char to_escape[] = "^$+*,[](){}\\|\"\'&#"; char *expansbuf; char *srchpnt; size_t currlen; expansbuf = malloc(currlen = strlen(string_to_expand) + 1); if (!expansbuf) return NULL; strcpy(expansbuf, string_to_expand); for (srchpnt = expansbuf; srchpnt += strcspn(srchpnt, to_escape), *srchpnt; srchpnt += 3 /* Skip the %2B (etc.) just inserted. */ ) { char hex[3+1]; int offset; /* Realloc CAN move the buffer to a different address (but often doesn't), so to be safe, pointer adjustment IS required! */ offset = srchpnt - expansbuf; expansbuf = realloc(expansbuf, currlen += 2); if (!expansbuf) return NULL; srchpnt = expansbuf + offset; sprintf(hex, "%%%02X", *srchpnt); memmove(srchpnt + 3, srchpnt + 1, strlen(srchpnt)); strncpy(srchpnt, hex, 3); } /* Spaces in a URL are encoded as plus signs */ for (srchpnt = expansbuf; (srchpnt = strchr(srchpnt, ' ')); srchpnt++) { *srchpnt = '+'; } return expansbuf; }