1007 lines
20 KiB
C
1007 lines
20 KiB
C
/*
|
|
cgi-util.c
|
|
|
|
version 2.1.0
|
|
|
|
by Bill Kendrick <bill@newbreedsoftware.com>
|
|
and Mike Simons <msimons@moria.simons-clan.com>
|
|
|
|
New Breed Software
|
|
http://www.newbreedsoftware.com/cgi-util/
|
|
|
|
April 6, 1996 - July 26, 2000
|
|
|
|
LICENSE: GPL.
|
|
|
|
Modified for use in TinyCobol by Rildo Pragana, 2001.
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
|
|
#ifndef NO_STDLIB_H
|
|
#include <stdlib.h>
|
|
#else
|
|
char *getenv();
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include "cgi-util.h"
|
|
|
|
|
|
/* Globals: */
|
|
|
|
cgi_entry_type * cgi_entries = NULL;
|
|
int cgi_num_entries = 0;
|
|
int cgi_errno = CGIERR_NONE;
|
|
int cgi_request_method = CGIREQ_NONE;
|
|
int cgi_content_type = CGITYPE_NONE;
|
|
char * cgi_query = NULL;
|
|
|
|
|
|
/* English error strings: */
|
|
|
|
char * cgi_error_strings[CGIERR_NUM_ERRS] = {
|
|
"", "Not an integer", "Not a double", "Not a boolean",
|
|
"Unknown method", "Incorrect Content Type",
|
|
"NULL Query String", "Bad Content Length",
|
|
"Content Length Discrepancy", "No Cookies", "Cookie Not Found"
|
|
};
|
|
|
|
|
|
/* Debugging. If set, this library will attempt to append debugging
|
|
information to a file named "debug.txt" in the current directory. */
|
|
|
|
/* #define DEBUG */
|
|
|
|
|
|
/* Converts hexadecimal to decimal (character): */
|
|
|
|
char x2c(char *what)
|
|
{
|
|
register char digit;
|
|
|
|
digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
|
|
digit *= 16;
|
|
digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
|
|
return (digit);
|
|
}
|
|
|
|
|
|
/* Unescapes "%"-escaped characters in a query: */
|
|
|
|
void unescape_url(char *url)
|
|
{
|
|
register int x,y,len;
|
|
|
|
len = strlen(url);
|
|
|
|
for (x=0, y=0; url[y]; ++x, ++y)
|
|
{
|
|
if ((url[x] = url[y]) == '%'
|
|
&& y < len - 2) /* 2.0.4 - MJ Pomraning (pilcrow@mailbag.com) */
|
|
{
|
|
url[x] = x2c(&url[y+1]);
|
|
y+=2;
|
|
}
|
|
}
|
|
url[x] = '\0';
|
|
}
|
|
|
|
|
|
/* Converts pluses back to spaces in a query: */
|
|
|
|
void plustospace(char *str)
|
|
{
|
|
register int x;
|
|
|
|
for (x=0; str[x]; x++)
|
|
if (str[x] == '+')
|
|
str[x] = ' ';
|
|
}
|
|
|
|
|
|
/* Internal use: Write debugging stuff to a file */
|
|
|
|
void debug(char * str1, char * str2)
|
|
{
|
|
#ifdef DEBUG
|
|
FILE * fi;
|
|
|
|
fi = fopen("debug.txt", "a");
|
|
if (fi != NULL)
|
|
{
|
|
fprintf(fi, "%s:%s\n", str1, str2);
|
|
fclose(fi);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/* Internal use: Read a line and return its length: */
|
|
|
|
int lineread(FILE * stream, char * buf, int count)
|
|
{
|
|
fgets(buf, count, stream);
|
|
|
|
if (!feof(stream))
|
|
return(strlen(buf));
|
|
else
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the CGI. Grab data from the browser and prepare it for us. */
|
|
|
|
#define CGI_RETURN(ret) *result = (ret); return;
|
|
|
|
void
|
|
cgi_init( int *result ) {
|
|
int cl, i, in_multipart_headers, which_entry, length_gotten;
|
|
char * boundary;
|
|
|
|
|
|
/* Default, no errors, no name/value pairs ("entries"): */
|
|
|
|
cgi_errno = CGIERR_NONE;
|
|
cgi_num_entries = 0;
|
|
length_gotten = 0;
|
|
|
|
|
|
/* Check for REQUEST_METHOD (set by HTTP server): */
|
|
|
|
if (getenv("REQUEST_METHOD") == NULL)
|
|
{
|
|
/* None set? Assume the user is invoking the CGI from a shell prompt
|
|
(for debugging): */
|
|
|
|
cgi_request_method = CGIREQ_NONE;
|
|
}
|
|
else
|
|
{
|
|
/* Determine the exact request method, and grab the data (if any)
|
|
in the appropriate manner: */
|
|
|
|
if (strcmp(getenv("REQUEST_METHOD"), "POST") == 0)
|
|
{
|
|
/* Post method (data is sent to us via "stdin"): */
|
|
|
|
cgi_request_method = CGIREQ_POST;
|
|
|
|
|
|
if (getenv("CONTENT_TYPE") == NULL)
|
|
{
|
|
/* Content type is not set! */
|
|
|
|
cgi_errno = CGIERR_INCORRECT_TYPE;
|
|
cgi_content_type = CGITYPE_UNKNOWN;
|
|
|
|
CGI_RETURN(cgi_errno);
|
|
}
|
|
else if (strcmp(getenv("CONTENT_TYPE"),
|
|
"application/x-www-form-urlencoded") == 0)
|
|
{
|
|
cgi_content_type = CGITYPE_APPLICATION_X_WWW_FORM_URLENCODED;
|
|
|
|
|
|
/* How much data do we expect? */
|
|
|
|
if (getenv("CONTENT_LENGTH") == NULL ||
|
|
sscanf(getenv("CONTENT_LENGTH"), "%d", &cl) != 1)
|
|
{
|
|
cgi_errno = CGIERR_BAD_CONTENT_LENGTH;
|
|
CGI_RETURN(cgi_errno);
|
|
}
|
|
|
|
|
|
/* Create space for it: */
|
|
|
|
cgi_query = malloc(cl + 1);
|
|
/* 2.0.1 - Tadek Orlowski (orlowski@epnet.com) ... "+1" */
|
|
|
|
if (cgi_query == NULL)
|
|
{
|
|
cgi_errno = CGIERR_OUT_OF_MEMORY;
|
|
CGI_RETURN(cgi_errno);
|
|
}
|
|
|
|
|
|
/* Read it in: */
|
|
|
|
fgets(cgi_query, cl + 1, stdin);
|
|
|
|
|
|
/* Verify that we got as much data as we expected: */
|
|
|
|
if (strlen(cgi_query) != cl)
|
|
cgi_errno = CGIERR_CONTENT_LENGTH_DISCREPANCY;
|
|
}
|
|
else if (strstr(getenv("CONTENT_TYPE"),
|
|
"multipart/form-data") == getenv("CONTENT_TYPE"))
|
|
{
|
|
cgi_content_type = CGITYPE_MULTIPART_FORM_DATA;
|
|
|
|
cgi_query = malloc(2050);
|
|
if (cgi_query == NULL)
|
|
{
|
|
cgi_errno = CGIERR_OUT_OF_MEMORY;
|
|
CGI_RETURN(cgi_errno);
|
|
}
|
|
|
|
|
|
/* Determine the boundary string: */
|
|
|
|
if (strstr(getenv("CONTENT_TYPE"),
|
|
"boundary=") == NULL)
|
|
{
|
|
cgi_errno = CGIERR_NO_BOUNDARY;
|
|
CGI_RETURN(cgi_errno);
|
|
}
|
|
|
|
boundary = strdup(strstr(getenv("CONTENT_TYPE"),
|
|
"boundary=") + 9);
|
|
|
|
debug("boundary", boundary);
|
|
|
|
|
|
/* Read in until there's no more: */
|
|
|
|
in_multipart_headers = 0;
|
|
which_entry = -1;
|
|
|
|
do
|
|
{
|
|
length_gotten = lineread(stdin, cgi_query, 2048);
|
|
|
|
debug("cgi_query", cgi_query);
|
|
|
|
if (length_gotten > 0)
|
|
{
|
|
if (strstr(cgi_query, boundary) == cgi_query + 2 &&
|
|
cgi_query[0] == '-' && cgi_query[1] == '-')
|
|
{
|
|
/* We got a boundary! */
|
|
|
|
in_multipart_headers = 1;
|
|
which_entry = -1;
|
|
}
|
|
else /* (Not a boundary) */
|
|
{
|
|
if (in_multipart_headers == 1)
|
|
{
|
|
/* We had just got a boundary, read headers: */
|
|
|
|
if (cgi_query[0] == '\r' || cgi_query[0] == '\n')
|
|
{
|
|
/* Blank line, end of headers: */
|
|
|
|
in_multipart_headers = 0;
|
|
}
|
|
else /* (Not a blank line) */
|
|
{
|
|
/* What kind of header is it? */
|
|
|
|
if (strstr(cgi_query,
|
|
"Content-Disposition: ") ==
|
|
cgi_query)
|
|
{
|
|
/* Content-disposition: */
|
|
|
|
/* For now, just look for "name=": */
|
|
|
|
if (strstr(cgi_query, "name=\"") != NULL)
|
|
{
|
|
/* Add a new entry: */
|
|
|
|
which_entry = cgi_num_entries;
|
|
cgi_num_entries++;
|
|
|
|
|
|
/* Make more room: */
|
|
|
|
cgi_entries =
|
|
realloc(cgi_entries,
|
|
sizeof(cgi_entry_type) *
|
|
cgi_num_entries);
|
|
|
|
if (cgi_entries == NULL)
|
|
{
|
|
cgi_errno = CGIERR_OUT_OF_MEMORY;
|
|
CGI_RETURN(cgi_errno);
|
|
}
|
|
|
|
|
|
/* Fill in the name slot: */
|
|
|
|
cgi_entries[which_entry].name =
|
|
strdup(strstr(cgi_query,
|
|
"name=\"") +
|
|
6);
|
|
|
|
|
|
/* Truncate after quote: */
|
|
|
|
if (strchr(cgi_entries[which_entry].
|
|
name, '\"') != NULL)
|
|
{
|
|
strcpy(strchr(cgi_entries
|
|
[which_entry].name,
|
|
'\"'), "\0");
|
|
}
|
|
|
|
|
|
/* Set default content-type: */
|
|
|
|
cgi_entries[which_entry].
|
|
content_type =
|
|
"application/octet-stream";
|
|
|
|
|
|
/* Set default content-length: */
|
|
|
|
cgi_entries[which_entry].
|
|
content_length = 0;
|
|
|
|
|
|
/* Set default value: */
|
|
|
|
cgi_entries[which_entry].val =
|
|
strdup("");
|
|
|
|
|
|
debug("entry.name",
|
|
cgi_entries[which_entry].name);
|
|
}
|
|
}
|
|
else if (strstr(cgi_query,
|
|
"Content-Type: ") ==
|
|
cgi_query)
|
|
{
|
|
/* Content-type: */
|
|
|
|
cgi_entries[which_entry].content_type =
|
|
strdup(strstr(cgi_query,
|
|
"Content-Type: ") +
|
|
14);
|
|
|
|
debug("entry.content_type",
|
|
cgi_entries[which_entry].
|
|
content_type);
|
|
}
|
|
}
|
|
}
|
|
else /* in_multipart_headers == 0 */
|
|
{
|
|
/* If we're recording into a particular
|
|
entry, copy the data: */
|
|
|
|
if (which_entry != -1)
|
|
{
|
|
/* Make more room: */
|
|
|
|
cgi_entries[which_entry].val =
|
|
realloc(cgi_entries[which_entry].val,
|
|
strlen(cgi_entries[which_entry].
|
|
val) + length_gotten + 1);
|
|
|
|
if (cgi_entries[which_entry].val == NULL)
|
|
{
|
|
cgi_errno = CGIERR_OUT_OF_MEMORY;
|
|
CGI_RETURN(cgi_errno);
|
|
}
|
|
|
|
|
|
/* Append the data: */
|
|
|
|
memcpy(cgi_entries[which_entry].val +
|
|
(cgi_entries[which_entry].
|
|
content_length),
|
|
cgi_query, length_gotten);
|
|
|
|
cgi_entries[which_entry].content_length =
|
|
(cgi_entries[which_entry].content_length +
|
|
length_gotten);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (length_gotten > 0);
|
|
|
|
free(cgi_query);
|
|
}
|
|
else
|
|
{
|
|
/* Content type is unrecognized! */
|
|
|
|
cgi_errno = CGIERR_INCORRECT_TYPE;
|
|
cgi_content_type = CGITYPE_UNKNOWN;
|
|
|
|
CGI_RETURN(cgi_errno);
|
|
}
|
|
}
|
|
else if (strcmp(getenv("REQUEST_METHOD"), "GET") == 0)
|
|
{
|
|
/* For now, assume Content Type of
|
|
"application/x-www-form-urlencoded"
|
|
(Is this a bad assumption?) */
|
|
|
|
cgi_content_type = CGITYPE_APPLICATION_X_WWW_FORM_URLENCODED;
|
|
|
|
|
|
/* GET method (data sent via "QUERY_STRING" env. variable): */
|
|
|
|
cgi_request_method = CGIREQ_GET;
|
|
|
|
|
|
/* Get a pointer to the data: */
|
|
|
|
cgi_query = getenv("QUERY_STRING");
|
|
|
|
if (cgi_query == NULL)
|
|
{
|
|
/* Does the "QUERY_STRING" env. variable not exist!? */
|
|
|
|
cgi_errno = CGIERR_NULL_QUERY_STRING;
|
|
|
|
CGI_RETURN(cgi_errno);
|
|
}
|
|
else
|
|
{
|
|
/* Determine the content length by seeing how big the
|
|
string is: */
|
|
|
|
cl = strlen(cgi_query);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Something else? We can't handle it! */
|
|
|
|
cgi_request_method = CGIREQ_UNKNOWN;
|
|
cgi_errno = CGIERR_UNKNOWN_METHOD;
|
|
cgi_num_entries = 0;
|
|
|
|
CGI_RETURN(cgi_errno);
|
|
}
|
|
|
|
|
|
if (cgi_content_type != CGITYPE_MULTIPART_FORM_DATA)
|
|
{
|
|
/* How many entries (name/value pairs) do we need to
|
|
allocate space for? (They should be separated by "&"'s) */
|
|
|
|
cgi_num_entries = 0;
|
|
|
|
for (i = 0; i <= cl; i++)
|
|
if (cgi_query[i] == '&' || cgi_query[i] == '\0')
|
|
cgi_num_entries++;
|
|
|
|
|
|
/* Allocate the space for that many structures: */
|
|
|
|
cgi_entries = malloc(sizeof(cgi_entry_type) * cgi_num_entries);
|
|
if (cgi_entries == NULL)
|
|
{
|
|
cgi_errno = CGIERR_OUT_OF_MEMORY;
|
|
CGI_RETURN(cgi_errno);
|
|
}
|
|
|
|
|
|
/* Grab each name/value pair: */
|
|
|
|
cgi_num_entries = 0;
|
|
|
|
|
|
/* (Begin with the first half of the first pair): */
|
|
|
|
if (cgi_query[0] != '\0' && cgi_query[0] != '&')
|
|
{
|
|
cgi_entries[0].name = cgi_query;
|
|
cgi_entries[0].content_type = "text/html";
|
|
}
|
|
|
|
|
|
/* Go through the entire string of characters: */
|
|
|
|
for (i = 0; i <= cl; i++)
|
|
{
|
|
if (cgi_query[i] == '&')
|
|
{
|
|
/* "&" represents the end of a name/value pair: */
|
|
|
|
cgi_entries[cgi_num_entries].name = cgi_query + i + 1;
|
|
cgi_entries[cgi_num_entries].content_type = "text/html";
|
|
cgi_query[i] = '\0';
|
|
}
|
|
else if (cgi_query[i] == '=')
|
|
{
|
|
/* "=" is the end of the name half of a name/value pair: */
|
|
|
|
cgi_entries[cgi_num_entries].val = cgi_query + i + 1;
|
|
|
|
/* plustospace(cgi_entries[cgi_num_entries].val);
|
|
unescape_url(cgi_entries[cgi_num_entries].val); */
|
|
|
|
cgi_num_entries++;
|
|
|
|
cgi_query[i] = '\0';
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < cgi_num_entries; i++)
|
|
{
|
|
plustospace(cgi_entries[i].val);
|
|
unescape_url(cgi_entries[i].val);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* Fix any NULL strings to be empty strings */
|
|
/* 2.0.4 - MJ Pomraning (pilcrow@mailbag.com) */
|
|
|
|
for (i = 0; i < cgi_num_entries; i++)
|
|
{
|
|
if (cgi_entries[i].name == NULL)
|
|
cgi_entries[i].name = "";
|
|
if (cgi_entries[i].val == NULL)
|
|
cgi_entries[i].val = "";
|
|
}
|
|
}
|
|
|
|
CGI_RETURN(CGIERR_NONE);
|
|
}
|
|
|
|
|
|
/* Free up memory that was allocated when we called "cgi_init()": */
|
|
|
|
void cgi_quit(void)
|
|
{
|
|
if (cgi_request_method == CGIREQ_NONE ||
|
|
cgi_request_method == CGIREQ_UNKNOWN)
|
|
{
|
|
/* Nothing to do! */
|
|
}
|
|
else
|
|
{
|
|
if (cgi_request_method == CGIREQ_POST)
|
|
{
|
|
/* Was it POST method? Free the data we had read from "stdin" */
|
|
|
|
free(cgi_query);
|
|
}
|
|
|
|
|
|
/* Free the entry structures themselves: */
|
|
|
|
free(cgi_entries);
|
|
}
|
|
|
|
cgi_entries = NULL;
|
|
cgi_num_entries = 0;
|
|
cgi_errno = CGIERR_NONE;
|
|
cgi_request_method = CGIREQ_NONE;
|
|
cgi_query = NULL;
|
|
cgi_content_type = CGITYPE_NONE;
|
|
}
|
|
|
|
|
|
/* Grab a cookie, if it exists. Return NULL if it doesn't: */
|
|
/* (Based on code by Pete Cassidy (pcassidy@iol.ie) - May 10, 2000) */
|
|
|
|
const char * cgi_getcookie(const char * cookie_name)
|
|
{
|
|
char * cookieval, * tmpcookie, * rawcookie, * left, * right;
|
|
int done;
|
|
|
|
|
|
/* Get raw cookie data: */
|
|
|
|
rawcookie = getenv("HTTP_COOKIE");
|
|
if (rawcookie == NULL)
|
|
{
|
|
/* No cookies at all? The cookie we want can't exist! */
|
|
|
|
cgi_errno = CGIERR_NO_COOKIES;
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
/* Strtok is destructive, so make a temporary copy of the raw cookie data: */
|
|
|
|
tmpcookie = malloc(sizeof(char) * (strlen(rawcookie) + 1));
|
|
if (tmpcookie == NULL)
|
|
{
|
|
cgi_errno = CGIERR_OUT_OF_MEMORY;
|
|
return(NULL);
|
|
}
|
|
|
|
strcpy(tmpcookie, rawcookie);
|
|
|
|
|
|
/* Tokenize out all cookies and check for the one we're looking for: */
|
|
|
|
left = strtok(tmpcookie, ";");
|
|
cookieval = NULL;
|
|
done = 0;
|
|
|
|
do
|
|
{
|
|
/* Grab the righthand size of the current cookie pair's "=" sign: */
|
|
|
|
right = strchr(left, '=') + (1 * sizeof(char));
|
|
|
|
|
|
/* Change the "=" into a NULL character, to get the lefthand side: */
|
|
|
|
*strchr(left, '=') = '\0';
|
|
|
|
|
|
/* See if this is our cookie: */
|
|
|
|
if (strcmp(left, cookie_name) == 0)
|
|
{
|
|
/* If so, set our return-string to the value (righthand side): */
|
|
|
|
cookieval = malloc(sizeof(char) * (strlen(right) + 1));
|
|
if (cookieval == NULL)
|
|
{
|
|
cgi_errno = CGIERR_OUT_OF_MEMORY;
|
|
return(NULL);
|
|
}
|
|
|
|
strcpy(cookieval, right);
|
|
done = 1;
|
|
}
|
|
|
|
|
|
/* Jump to next cookie: */
|
|
|
|
if (!done)
|
|
{
|
|
left = strtok(NULL, ";");
|
|
if (left == NULL)
|
|
{
|
|
/* No more to parse? */
|
|
|
|
done = 1;
|
|
}
|
|
else
|
|
{
|
|
/* Skip the extra space: */
|
|
|
|
left++;
|
|
}
|
|
}
|
|
}
|
|
while (!done);
|
|
|
|
|
|
/* Free the temporary copy of the raw cookie data: */
|
|
|
|
free(tmpcookie);
|
|
|
|
|
|
/* Return the cookie value (which may be NULL if we never found it): */
|
|
|
|
if (cookieval == NULL)
|
|
cgi_errno = CGIERR_COOKIE_NOT_FOUND;
|
|
else
|
|
cgi_errno = CGIERR_NONE;
|
|
|
|
return(cookieval);
|
|
}
|
|
|
|
|
|
/* Grab a value and return it as a string: */
|
|
|
|
const char * cgi_getentrystr(const char *field_name)
|
|
{
|
|
int x;
|
|
|
|
if (cgi_request_method != CGIREQ_NONE)
|
|
{
|
|
/* Look for the name: */
|
|
|
|
for (x = 0; x < cgi_num_entries; x++)
|
|
{
|
|
if (strcmp(cgi_entries[x].name, field_name) == 0)
|
|
{
|
|
return (cgi_entries[x].val);
|
|
}
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
else
|
|
{
|
|
/* printf("CGI-UTIL: \"%s\" ? ", field_name);
|
|
fgets(buf, 512, stdin);
|
|
buf[strlen(buf) - 1] = '\0'; */
|
|
|
|
return("x");
|
|
}
|
|
}
|
|
|
|
|
|
/* Grab a content-type and return it as a string: */
|
|
|
|
const char * cgi_getentrytype(const char *field_name)
|
|
{
|
|
int x;
|
|
|
|
if (cgi_request_method != CGIREQ_NONE)
|
|
{
|
|
/* Look for the name: */
|
|
|
|
for (x = 0; x < cgi_num_entries; x++)
|
|
{
|
|
if (strcmp(cgi_entries[x].name, field_name) == 0)
|
|
{
|
|
return (cgi_entries[x].content_type);
|
|
}
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
else
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
/* Grab a value and return it as an integer: */
|
|
|
|
int cgi_getentryint(const char *field_name)
|
|
{
|
|
int v;
|
|
|
|
v = 0;
|
|
|
|
if (cgi_getentrystr(field_name) != NULL)
|
|
{
|
|
if (sscanf(cgi_getentrystr(field_name), "%d", &v) != 1)
|
|
cgi_errno = CGIERR_NOT_INTEGER;
|
|
}
|
|
else
|
|
cgi_errno = CGIERR_NOT_INTEGER;
|
|
|
|
return(v);
|
|
}
|
|
|
|
|
|
/* Grab a value and return it as a double: */
|
|
|
|
double cgi_getentrydouble(const char *field_name)
|
|
{
|
|
double v;
|
|
|
|
v = 0;
|
|
|
|
if (cgi_getentrystr(field_name) != NULL)
|
|
{
|
|
if (sscanf(cgi_getentrystr(field_name), "%lf", &v) != 1)
|
|
cgi_errno = CGIERR_NOT_DOUBLE;
|
|
}
|
|
else
|
|
cgi_errno = CGIERR_NOT_DOUBLE;
|
|
|
|
return(v);
|
|
}
|
|
|
|
|
|
/* Grab a value and return it as a boolean (depending on if the
|
|
value was "yes", "on" or "true", or "no", "off" or "false"): */
|
|
|
|
int cgi_getentrybool(const char *field_name, int def)
|
|
{
|
|
const char * temp;
|
|
int v;
|
|
|
|
|
|
/* Assume the default: */
|
|
|
|
v = def;
|
|
|
|
|
|
/* Get the value (if any): */
|
|
|
|
temp = cgi_getentrystr(field_name);
|
|
|
|
if (temp != NULL)
|
|
{
|
|
if (strcasecmp(temp, "yes") == 0 ||
|
|
strcasecmp(temp, "on") == 0 ||
|
|
strcasecmp(temp, "true") == 0)
|
|
{
|
|
/* A "yes" or "on" is a 1: */
|
|
|
|
v = 1;
|
|
}
|
|
else if (strcasecmp(temp, "no") == 0 ||
|
|
strcasecmp(temp, "off") == 0 ||
|
|
strcasecmp(temp, "false") == 0)
|
|
{
|
|
/* A "no" or "off" is a 0: */
|
|
|
|
v = 0;
|
|
}
|
|
else if (temp[0] != 0)
|
|
{
|
|
/* We got something, but not "yes", "on", "no" or "off": */
|
|
|
|
cgi_errno = CGIERR_NOT_BOOL;
|
|
}
|
|
}
|
|
else
|
|
cgi_errno = CGIERR_NOT_BOOL;
|
|
|
|
|
|
return(v);
|
|
}
|
|
|
|
|
|
/* Open a file and send it to "stdout" (the browser): */
|
|
/* (Returns an error if we can't open the file) */
|
|
|
|
int cgi_dump_no_abort(const char * filename)
|
|
{
|
|
FILE * fi;
|
|
int c;
|
|
|
|
|
|
cgi_errno = CGIERR_NONE;
|
|
|
|
|
|
/* Open the file: */
|
|
|
|
fi = fopen(filename, "r");
|
|
if (fi == NULL)
|
|
cgi_errno = CGIERR_CANT_OPEN;
|
|
else
|
|
{
|
|
/* Read data and push it to "stdout": */
|
|
|
|
do
|
|
{
|
|
c = fgetc(fi);
|
|
if (c != EOF)
|
|
fputc(c, stdout);
|
|
}
|
|
while (c != EOF);
|
|
|
|
fclose(fi);
|
|
}
|
|
|
|
return(CGIERR_NONE);
|
|
}
|
|
|
|
|
|
/* Open a file and send it to "stdout" (the browser): */
|
|
/* (Displays an error message and quits the CGI if we can't open the file) */
|
|
|
|
void cgi_dump(const char * filename)
|
|
{
|
|
if (cgi_dump_no_abort(filename) != CGIERR_NONE)
|
|
{
|
|
printf("Can't open %s - %s\n", filename, strerror(errno));
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
|
|
/* Display a simple error message and quit the CGI: */
|
|
|
|
void cgi_error(const char * reason)
|
|
{
|
|
printf("<h1>Error</h1>\n");
|
|
printf("%s\n", reason);
|
|
|
|
exit(0);
|
|
}
|
|
|
|
|
|
/* Returns whether or not an e-mail address appears to be in the correct
|
|
syntax ("username@host.domain"): */
|
|
|
|
int cgi_goodemailaddress(const char * addr)
|
|
{
|
|
int i;
|
|
|
|
|
|
/* No "@".. what? */
|
|
|
|
if (strchr(addr, '@') == NULL)
|
|
return 0;
|
|
|
|
|
|
/* "@" or "." at the end or beginning? */
|
|
|
|
if (addr[strlen(addr - 1)] == '@' ||
|
|
addr[strlen(addr - 1)] == '.' ||
|
|
addr[0] == '@' || addr[0] == '.')
|
|
return 0;
|
|
|
|
|
|
/* No "." after the "@"? More than one "@"? */
|
|
|
|
if (strchr(strchr(addr, '@'), '.') == NULL ||
|
|
strchr(strchr(addr, '@') + 1, '@') != NULL)
|
|
return 0;
|
|
|
|
|
|
/* Any illegal characters within the string? */
|
|
|
|
for (i = 0; i < strlen(addr); i++)
|
|
{
|
|
if (isalnum(addr[i]) == 0 &&
|
|
addr[i] != '.' && addr[i] != '@' && addr[i] != '_' &&
|
|
addr[i] != '-')
|
|
return(0);
|
|
}
|
|
|
|
|
|
/* Must be ok... */
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* Returns the English string description for a particular cgi-util error
|
|
value: */
|
|
|
|
const char * cgi_strerror(int err)
|
|
{
|
|
if (err < 0 || err > CGIERR_NUM_ERRS)
|
|
return("");
|
|
else
|
|
return(cgi_error_strings[err]);
|
|
}
|
|
|
|
/******** TinyCobol interfacing functions *************/
|
|
|
|
void
|
|
cgi_get_string( char *name, char *value ) {
|
|
char *s;
|
|
s = name;
|
|
while ( *s != ' ' || *(s+1) != ' ' ) s++;
|
|
*s=0;
|
|
s = cgi_getentrystr(name);
|
|
if (s != NULL) {
|
|
while (*s) {
|
|
*value++ = *s++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
cgi_get_integer( char *name, int *value ) {
|
|
char *s;
|
|
s = name;
|
|
while ( *s != ' ' || *(s+1) != ' ' ) s++;
|
|
*s=0;
|
|
*value = cgi_getentryint(name);
|
|
}
|
|
|
|
void
|
|
cgi_set_string( char *name, char *newvalue ) {
|
|
int x,i;
|
|
char *s;
|
|
s = name;
|
|
while ( *s != ' ' || *(s+1) != ' ' ) s++;
|
|
*s=0;
|
|
if (cgi_request_method != CGIREQ_NONE) {
|
|
for (x = 0; x < cgi_num_entries; x++) {
|
|
if (strcmp(cgi_entries[x].name, name) == 0) {
|
|
strcpy(cgi_entries[x].val,newvalue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|