/*
    cgi.c - Some simple routines for cgi programming
    Copyright (c) 1996-8  Martin Schulze <joey@infodrom.north.de>

    This program 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 2 of the License, or
    (at your option) any later version.

    This program 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 this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
 */

#include <stdio.h>
#if HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_CTYPE_H
# include <ctype.h>
#endif
/* Unnecessary on FreeBSD; malloc.h included in stdlib.h */
/*
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
*/

#include <cgi.h>

int cgiDebugLevel = 0;
int cgiDebugStderr = 1;

void cgiHeader ()
{
    printf ("Content-type: text/html\n\n");
}

void cgiDebug (int level, int where)
{
    if (level > 0)
	cgiDebugLevel = level;
    else
	cgiDebugLevel = 0;
    if (where)
	cgiDebugStderr = 0;
    else
	cgiDebugStderr = 1;
}

char *cgiDecodeString (char *text)
{
    char *cp, *xp;

    for (cp=text,xp=text; *cp; cp++) {
	if (*cp == '%') {
	    if (strchr("0123456789ABCDEFabcdef", *(cp+1))
		&& strchr("0123456789ABCDEFabcdef", *(cp+2))) {
		if (islower(*(cp+1)))
		    *(cp+1) = toupper(*(cp+1));
		if (islower(*(cp+2)))
		    *(cp+2) = toupper(*(cp+2));
		*(xp) = (*(cp+1) >= 'A' ? *(cp+1) - 'A' + 10 : *(cp+1) - '0' ) * 16
		    + (*(cp+2) >= 'A' ? *(cp+2) - 'A' + 10 : *(cp+2) - '0');
		xp++;cp+=2;
	    }
	} else {
	    *(xp++) = *cp;
	}
    }
    bzero(xp, cp-xp);
    return text;
}

/*  cgiInit()
 *
 *  Read from stdin if no string is provided via CGI.  Variables that
 *  doesn't have a value associated with it doesn't get stored.
 */
s_cgi **cgiInit ()
{
    int length;
    char *line = NULL;
    int numargs;
    char *cp, *ip, *esp, *sptr;
    s_cgi **result;
    int i, k;
    char tmp[101];

    cp = getenv("REQUEST_METHOD");
    ip = getenv("CONTENT_LENGTH");

    if (cp && !strcmp(cp, "POST")) {
	if (ip) {
	    length = atoi(ip);
	    if ((line = (char *)malloc (length+2)) == NULL)
		return NULL;
	    fgets(line, length+1, stdin);
	} else
	    return NULL;
    } else if (cp && !strcmp(cp, "GET")) {
	esp = getenv("QUERY_STRING");
	if (esp && strlen(esp)) {
	    if ((line = (char *)malloc (strlen(esp)+2)) == NULL)
		return NULL;
	    snprintf (line, strlen(esp)+2, "%s", esp);
	} else
	    return NULL;
    } else {
	length = 0;
	printf ("(offline mode: enter name=value pairs on standard input)\n");
	for (cp = fgets(tmp, 100, stdin); cp != NULL;
	     cp = fgets(tmp, 100, stdin) ) {
	    if (strlen(tmp)) {
		length += strlen(tmp);
		if ((ip = (char *)malloc (length * sizeof(char))) == NULL)
		    return NULL;
		bzero(ip, length);
		if (line) {
		    if (line[strlen(line)-1] == '\n')
			line[strlen(line)-1] = '&';
		    strncpy(ip, line, length * sizeof(char));
		}
		ip = strncat(ip, tmp, length * sizeof(char));
		if (line)
		    free (line);
		line = ip;
	    }
	}
	if (!line)
	    return NULL;
	if (line[strlen(line)-1] == '\n')
	    line[strlen(line)-1] = '\0';
    }

    /*
     *  From now on all cgi variables are stored in the variable line
     *  and look like  foo=bar&foobar=barfoo&foofoo=
     */

    if (cgiDebugLevel > 0)
	if (cgiDebugStderr)
	    fprintf (stderr, "Received cgi input: %s\n", line);
	else
	    printf ("<b>Received cgi input</b><br>\n<pre>\n--\n%s\n--\n</pre>\n\n", line);

    for (cp=line; *cp; cp++)
	if (*cp == '+')
	    *cp = ' ';

    if (strlen(line)) {
	for (numargs=1,cp=line; *cp; cp++)
	    if (*cp == '&') numargs++;
    } else
	numargs = 0;
    if (cgiDebugLevel > 0)
	if (cgiDebugStderr)
	    fprintf (stderr, "%d cgi variables found.\n", numargs);
	else
	    printf ("%d cgi variables found.<br>\n", numargs);

    if ((result = (s_cgi **)malloc((numargs+1) * sizeof(s_cgi *))) == NULL)
	return NULL;
    bzero (result, (numargs+1) * sizeof(s_cgi *));

    cp = line;
    i=0;
    while (*cp) {
	if ((ip = (char *)index(cp, '&')) != NULL) {
	    *ip = '\0';
	}else
	    ip = cp + strlen(cp);

	if ((esp=(char *)index(cp, '=')) == NULL) {
	    cp = ++ip;
	    continue;
	}

	if (!strlen(esp)) {
	    cp = ++ip;
	    continue;
	}

	if (i<numargs) {

	    for (k=0; k<i && (strncmp(result[k]->name,cp, esp-cp)); k++);
	    /* try to find out if there's already such a variable */
	    if (k == i) {	/* No such variable yet */
		if ((result[i] = (s_cgi *)malloc(sizeof(s_cgi))) == NULL)
		    return NULL;
		if ((result[i]->name = (char *)malloc((esp-cp+1) * sizeof(char))) == NULL)
		    return NULL;
		bzero (result[i]->name, esp-cp+1);
		strncpy(result[i]->name, cp, esp-cp);
		cp = ++esp;
		if ((result[i]->value = (char *)malloc((ip-esp+1) * sizeof(char))) == NULL)
		    return NULL;
		bzero (result[i]->value, ip-esp+1);
		strncpy(result[i]->value, cp, ip-esp);
		result[i]->value = cgiDecodeString(result[i]->value);
		if (cgiDebugLevel) {
		    if (cgiDebugStderr)
			fprintf (stderr, "%s: %s\n", result[i]->name, result[i]->value);
		    else
			printf ("<h3>Variable %s</h3>\n<pre>\n%s\n</pre>\n\n", result[i]->name, result[i]->value);
		}
		i++;
	    } else {	/* There is already such a name, suppose a mutiple field */
		if ((sptr = (char *)malloc((strlen(result[k]->value)+(ip-esp)+2)* sizeof(char))) == NULL)
		    return NULL;
		bzero (sptr, strlen(result[k]->value)+(ip-esp)+2);
		snprintf (sptr, (strlen(result[k]->value)+(ip-esp)+2)*sizeof(char), "%s\n", result[k]->value);
		cp = ++esp;
		strncat(sptr, cp, ip-esp);
		free(result[k]->value);
		result[k]->value = sptr;
	    }
	}
	cp = ++ip;
    }
    return result;
}

char *cgiGetValue(s_cgi **parms, const char *var)
{
    int i;

    if (parms)
	for (i=0;parms[i]; i++)
	    if (!strcmp(var,parms[i]->name)) {
		if (cgiDebugLevel > 0)
		    if (cgiDebugStderr)
			fprintf (stderr, "%s found as %s\n", var, parms[i]->value);
		    else
			printf ("%s found as %s<br>\n", var, parms[i]->value);
		return parms[i]->value;
	    }
    if (cgiDebugLevel)
	if (cgiDebugStderr)
	    fprintf (stderr, "%s not found\n", var);
	else
	    printf ("%s not found<br>\n", var);

    return NULL;
}

void cgiRedirect (const char *url)
{
    if (url && strlen(url)) {
	printf ("Content-type: text/html\nContent-length: %d\n", 77+(strlen(url)*2));
	printf ("Status: 302 Temporal Relocation\n");
	printf ("Location: %s\n\n", url);
	printf ("<html>\n<body>\nThe page has been moved to <a href=\"%s\">%s</a>\n</body>\n</html>\n", url, url);
    }
}

/*
 * Local variables:
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 8
 * End:
 */


syntax highlighted by Code2HTML, v. 0.9.1