/*********************************************************************
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;
}