/*
 * cgi-util.c
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "cgi-util.h"

#define LF 10
#define CR 13

static void getword (char* word, char* line, char stop);
static char* makeword (char* line, char stop);
static char* fmakeword (FILE* f, char stop, int* cl);
static char x2c (char* what);
static void unescape_url (char* url);
static void plustospace (char* str);
static int rind (char* s, char c);
static int getline (char* s, int n, FILE* f);
static void send_fd (FILE* f, FILE* fd);
static int ind (char* s, char c);
static void escape_shell_cmd (char* cmd);


static void getword(char* word, char* line, char stop)
{
int x = 0, y;

	for (x = 0; ((line[x]) && (line[x] != stop)); x++)
	{
		word[x] = line[x];
	}
	
	word[x] = '\0';
	if (line[x])
	{
		++x;
	}
	y = 0;
	
	while (line[y++] = line[x++])
	{
	}
}

static char* makeword(char* line, char stop)
{
int x = 0, y;
char* word = (char *) malloc(sizeof (char) * (strlen (line) + 1));

	for (x = 0; ((line[x]) && (line[x] != stop)); x++)
	{
		word[x] = line[x];
	}

	word[x] = '\0';
	if (line[x])
	{
		++x;
	}
	y = 0;

	while (line[y++] = line[x++])
	{
	}
		
	return word;
}

static char* fmakeword(FILE* f, char stop, int* cl)
{
int wsize;
char* word;
int ll;

	wsize = 102400;
	ll = 0;
	word = (char *) malloc(sizeof (char) * (wsize + 1));
	
	while (1)
	{
		word[ll] = (char) fgetc(f);
		if (ll == wsize)
		{
			word[ll + 1] = '\0';
			wsize += 102400;
			word = (char *) realloc(word, sizeof (char) * (wsize + 1));
		}
		--(*cl);
		if ((word[ll] == stop) || (feof (f)) || (!(*cl)))
		{
			if (word[ll] != stop)
			{
				ll++;
			}
			word[ll] = '\0';
			word = (char *) realloc (word, ll + 1);
			
			return word;
		}
		++ll;
	}
}

static 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);
}

static void unescape_url(char* url)
{
register int x, y;

	for (x = 0, y = 0; url[y]; ++x, ++y)
	{
		if ((url[x] = url[y]) == '%')
		{
			url[x] = x2c (&url[y + 1]);
			y += 2;
		}
	}
	url[x] = '\0';
}

static void plustospace(char* str)
{
register int x;

	for (x = 0; str[x]; x++)
	{
		if (str[x] == '+')
		{
	  		str[x] = ' ';
	  	}
	}
}

static int rind(char* s, char c)
{
register int x;

	for (x = strlen (s) - 1; x != -1; x--)
	{
		if (s[x] == c)
		{
			return x;
		}
	}
	  
	return -1;
}

static int getline(char* s, int n, FILE* f)
{
register int i = 0;

	while (1)
	{
		s[i] = (char) fgetc(f);
			
		if (s[i] == CR)
		{
			s[i] = fgetc (f);
		}
			
		if ((s[i] == 0x4) || (s[i] == LF) || (i == (n - 1)))
		{
			s[i] = '\0';
			
			return (feof (f) ? 1 : 0);
		}
		++i;
	}
}

static void send_fd(FILE* f, FILE* fd)
{
int num_chars = 0;
char c;

	while (1)
	{
		c = fgetc(f);
		if (feof(f))
		{
			return;
		}
		fputc(c, fd);
	}
}

static int ind(char* s, char c)
{
register int x;

	for (x = 0; s[x]; x++)
	{
		if (s[x] == c)
		{
			return x;
		}
	}

	return -1;
}

static void escape_shell_cmd(char* cmd)
{
register int x, y, l;

	l = strlen(cmd);
	for (x = 0; cmd[x]; x++)
	{
		if (ind("&;`'\"|*?~<>^()[]{}$\\", cmd[x]) != -1)
		{
			for (y = l + 1; y > x; y--)
			{
				cmd[y] = cmd[y - 1];
			}
			l++;                  /* length has been increased */
			cmd[x] = '\\';
			x++;                  /* skip the character */
		}
	}
}

void cgi_uninit(entry entries[], int n_entries)
{
register int x;
  
	for (x = 0; x < n_entries; x++)
	{
		free(entries[x].name);
		free(entries[x].val);
	}
}

int cgi_init(entry entries[], int max_entries)
{
register int x;
int cl;
  
	if (strcmp (getenv ("REQUEST_METHOD"), "POST"))
	{
		return -1;
	}
	if (strcmp (getenv ("CONTENT_TYPE"), "application/x-www-form-urlencoded"))
	{
		return -2;
	}
	cl = atoi (getenv ("CONTENT_LENGTH"));
	
	for (x = 0; x < max_entries && cl && (!feof (stdin)); x++)
	{
		entries[x].val = fmakeword (stdin, '&', &cl);
		plustospace (entries[x].val);
		unescape_url (entries[x].val);
		entries[x].name = makeword (entries[x].val, '=');
	}
	   
	return x;
}

void cgi_send_error(int err)
{
	cgi_send_header(HEADER_TYPE_TEXT_HTML);
	switch (err)
	{
	case -1:
		printf ("This script should be referenced with a METHOD of POST.\n");
		break;
	case -2:
      	printf ("This script can only be used to decode form results. \n");
      	break;
	default:
		printf("unknown error\n");
		break;
	}
}

void cgi_send_header(char* type)
{
  printf ("Content-type: %s%c%c", type, 10, 10);
}

int cgi_get_value_from_key(char* value, int max_len, 
							char* key, int pos, 
							entry entries[], int n_entries)
{
register int x;

	for (x = pos; x < n_entries; x++)
	{
		if (strcmp(key, entries[x].name) == 0)
		{
			strncpy(value, entries[x].val, max_len);
			return x+1;
		}
	}
	
	return -1;
}
