/*
**	w3-msql.c	- 
**
**
** Copyright (c) 1995-96  Hughes Technologies Pty Ltd
**
** Permission to use, copy, and distribute for non-commercial purposes,
** is hereby granted without fee, providing that the above copyright
** notice appear in all copies and that both the copyright notice and this
** permission notice appear in supporting documentation.
**
** This software is provided "as is" without any expressed or implied warranty.
**
**
*/


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <common/portability.h>
#include <msql/msql.h>

#include "y.tab.h"
#include "lite.h"
#include "version.h"


#define NUM_HANDLES	50

extern	char	*yytext;
extern	char	*contentType;
extern	int	yylineno;
static	int	headerSent = 0;

char	*scriptBuf;

void checkAuth();
char *HTUnEscape();
void sendOkHeader();



void checkContentType()
{
        static  int     sent=0;

	sendOkHeader();
        if (!sent)
        {
                if(!contentType)
                {
                        printf("Content-type: text/html\n\n");
                }
                else
                {
                        printf("Content-type: %s\n\n",contentType);
                }
                sent++;
        }
        fflush(stdout);
}

/**********************************************************************
** Error routines
**
*/

void parseError(msg)
	char	*msg;
{
	checkContentType();
	printf("</h1></h2></h3></h4></h5></h6>\n");
	printf("</select></ul></dl></ol></table>\n");
	printf("<h3><PRE>\n");
	printf("\n\nW3-mSQL Error!  -  %s\n\n",msg);
	printf("Error at line %d\n\n</PRE></H3>\n",yylineno);
	fflush(stdout);
}

void runError(msg)
	char	*msg;
{
	char	*file;

	checkContentType();
	file = (char *)simGetFileName();
	printf("</h1></h2></h3></h4></h5></h6>\n");
	printf("</select></ul></dl></ol></table>\n");
	printf("<h3><PRE>\n");
	printf("\n\nW3-mSQL Runtime Error!  -  %s\n\n",msg);
	if (!file)
		printf("Error at line %d\n\n</PRE></H3>\n",simGetLineNum());
	else
		printf("Error at line %d of %s\n\n</PRE></H3>\n",
			simGetLineNum(), file);
	fflush(stdout);
}


void yyerror(s)
	char	*s;
{
	char	errBuf[160];

	sprintf(errBuf,"%s near \"%s\"",s ,yytext?yytext:"");
	parseError(errBuf);
	fflush(stdout);
	exit(0);
}




static sym_t *castToArray(sym)
	sym_t	*sym;
{
	sym_t	*tmp,
		*new;
	char	*name;

	tmp = symCreateSymbol("",TYPE_CHAR, SCALAR);
	symStoreValue(tmp,sym->val, strlen(sym->val), TYPE_CHAR);
	tmp->length = sym->length;
	sym->val = NULL;
	name = sym->name;
	
	new = (sym_t *)symCreateSymbol(name,TYPE_CHAR,ARRAY);
	symSetArrayElement(new,0,tmp);

	symFreeSymbol(sym);
	return(new);
}



void storeArgs(query, source)
        char    *query;
	int	source;
{
        char    *cp1,
                *cp2,
                var[50],
                val[15 * 1024],
		*tmpVal;
	int	count;
	sym_t	*sym,
		*tmp;


        if (!query)
                return;

        cp1 = query;
        cp2 = var;
        bzero(var,sizeof(var));
        bzero(val,sizeof(val));
	*cp2++ = '$';
        while(*cp1)
        {
                if (*cp1 == '=')
                {
                        cp1++;
                        cp2 = val;
                        continue;
                }
                if (*cp1 == '&')
                {
			sym = symGetSymbol(var);
			if (sym)
			{
				/* 
				** Hmmm, it's already there!  Must be
				** data from a multi-select widget.
				** Turn it into an array.
				*/
				if (sym->array == SCALAR)
				{
					sym = castToArray(sym);
				}
				count = symGetNumArrayElements(sym);
				tmp = symCreateSymbol("",TYPE_CHAR, SCALAR);
				symSetArrayElement(sym,count,tmp);
				sym = tmp;
			}
			else
			{
				sym = symCreateSymbol(var,TYPE_CHAR, SCALAR);
			}
			tmpVal = HTUnEscape(val);
			symStoreValue(sym,tmpVal,strlen(tmpVal),TYPE_CHAR);
			sym->source = source;
			sym->length = strlen(sym->val) + 1;
                        bzero(var,sizeof(var));
                        bzero(val,sizeof(val));
                        cp1++;
                        cp2 = var;
			*cp2++ = '$';
                        continue;
                }
                *cp2++ = *cp1++;
        }
	sym = symGetSymbol(var);
	if (sym)
	{
		/* 
		** Hmmm, it's already there!  Must be
		** data from a multi-select widget.
		** Turn it into an array.
		*/
		if (sym->array == SCALAR)
		{
			sym = castToArray(sym);
		}
		count = symGetNumArrayElements(sym);
		tmp = symCreateSymbol("",TYPE_CHAR, SCALAR);
		symSetArrayElement(sym,count,tmp);
		sym = tmp;
	}
	else
	{
		sym = symCreateSymbol(var,TYPE_CHAR, SCALAR);
	}
	sym->val = (char *)strdup(HTUnEscape(val));
	sym->source = source;
	sym->length = strlen(sym->val) + 1;
}


void parseArgs()
{
        char    *query,
		*method;
	int	length,
		remain;


	query = (char *)getenv("QUERY_STRING");
	if (query)
	{
		storeArgs(query,SRC_GET);
	}

	method=(char *)getenv("REQUEST_METHOD");
	if (method)
	{
		if (strcmp(method,"POST" )==0) 
		{
			length = atoi((char *)getenv("CONTENT_LENGTH"));
			query = (char *) malloc(length + 1);
			remain = length;
			while(remain)
			{
				remain -= read(fileno(stdin) , 
					query + length - remain, remain);
			}
			query[length]='\0';
			storeArgs(query,SRC_POST);
		} 
	}
}





void sendFooter()
{
	extern	char *contentType;

	if (contentType)
	{
		if (strcmp(contentType,"text/html") != 0)
			return;
	}
	checkContentType();
	if (msqlGetIntConf("w3-msql","footer") == 0)
		return;
	printf("<p><br><br><br><br>\n");
	printf("</dl></ul></ol></table>\n");
	printf("</h1></h2></h3></h4></h5></h6>\n");
	printf("<center><FONT SIZE=-2>W3-mSQL %s by ",SERVER_VERSION);
	printf("<a href=http://www.Hughes.com.au/>");
	printf("Hughes Technologies</a></FONT>\n\n");
}


void sendAuthHeader(realm, msg, file)
	char	*realm,
		*msg,
		*file;
{
	int	fd,
		len;
	char	buf[1024];

	if (headerSent)
		return;
	headerSent++;

        printf("Status: 401 Error\n");
        printf("WWW-Authenticate: Basic realm=\" '%s' \"\n",realm);
	checkContentType();

	if (!file)
	{
        	printf("<BODY BGCOLOR=#FFFFFF TEXT=#0606A0 LINK=#0000FF ");
		printf(" VLINK=#0000FF>\n");
        	printf("<P><BR><CENTER>");
		printf("<IMG SRC=/Hughes/graphics/banner.gif><P><BR>\n");
		printf("<H1><I>Access Denied</I></H1>\n");
		printf("<P><BR><H3>%s</H3></CENTER><P>\n",msg);
	}
	else
	{
		fd = open(file, O_RDONLY, 0);
		if (fd < 0)
		{
			printf("<H2>Authentication failed</H2>\n");
		}
		else
		{
			len = read(fd,buf,1024);
			while(len > 0)
			{
				write(fileno(stdout),buf,len);
				len = read(fd,buf,1024);
			}
			close(fd);
		}
	}
        sendFooter();
}


void sendOkHeader()
{
	if (headerSent)
		return;
	headerSent++;
        printf("Status: 200 Output follows\n");
	printf("Server: w3-mSQL/2\n");
}



void checkMimeTypes(file, buf, len)
	char	*file,
		*buf;
	int	len;
{
	extern	char *contentType;
	char	*cp,
		*type;

	type = NULL;
	cp = (char *)rindex(file, '.');
	if (cp)
	{
		if (strcmp(cp,".html") == 0 ||
	    	    strcmp(cp,".htm") == 0 ||
	    	    strcmp(cp,".shtml") == 0 ||
	    	    strcmp(cp,".msql") == 0)
		{
			return;
		}
		if (strcmp(cp,".gif") == 0)
		{
			type = "image/gif";
		}
		if (strcmp(cp,".jpg") == 0)
		{
			type = "image/jpeg";
		}
		if (strcmp(cp,".xbm") == 0)
		{
			type = "image/xbm";
		}
		if (strcmp(cp,".png") == 0)
		{
			type = "image/png";
		}
	}
	else
	{
		/*
		** There's no . so it's probably a directory name
		*/
		return;
	}
	if (!type)
	{
		type = "application/octet-stream";
	}

	printf("Status: 200 Output follows\n");
	printf("Server: w3-mSQL/2\n");
	printf("Content-Type: %s\n\n", type);
	fflush(stdout);
	write(fileno(stdout),buf,len);
	exit(0);
}


int main(argc,argv)
	int	argc;
	char	*argv[];
{
	int	fd,
		dFlag,
		tFlag;
	char	*filename = NULL,
		privateScript[255],
		*cp;
	struct	stat	sbuf;

#ifdef DEBUG
	yydebug++;
#endif

	tFlag = dFlag = 0;
	if (argc > 1)
	{
		if (strcmp(argv[1], "-d") == 0)
		{
			dFlag++;
		}
		if (strcmp(argv[1], "-t") == 0)
		{
			tFlag++;
		}
	}



	msqlLoadConfigFile(NULL);
	filename = (char *)getenv("PATH_TRANSLATED");
	if (!filename)
	{
		sendOkHeader();
		parseError("Input file name missing!");
		exit(1);
	}

	if (stat(filename,&sbuf) < 0)
	{
		/* is it a private script? */
		sprintf(privateScript,"%s/www%s",
			(char *)msqlGetCharConf("general","inst_dir"),
			getenv("PATH_INFO"));
		filename = privateScript;
		if (stat(filename,&sbuf) < 0)
		{
			sendOkHeader();
			sprintf(privateScript, "Can't stat script file (%s)",
				getenv("PATH_INFO"));
			parseError(privateScript);
			perror("stat");
			printf("\n\n");
			exit(1);
		}
	}
	scriptBuf = (char *)malloc(sbuf.st_size + 1);
	if (!scriptBuf)
	{
		sendOkHeader();
		parseError("Out of memory");
		printf("\n\n");
		exit(1);
	}
	fd = open(filename,O_RDONLY);
	if (fd < 0)
	{
		sendOkHeader();
		parseError("Can't open input file");
		perror("open");
		printf("\n\n");
		exit(1);
	}
	if (read(fd,scriptBuf,sbuf.st_size) != sbuf.st_size)
	{
		sendOkHeader();
		parseError("Load of script file failed (short read)");
		printf("\n\n");
		exit(1);
	}
	*(scriptBuf+sbuf.st_size) = 0;
	checkMimeTypes(filename, scriptBuf, sbuf.st_size);

        lexInitScanner((u_char *)scriptBuf);
        initSymbolTables();
	initModules();

	/*
	** Change directory to the source of the script
	*/
	cp = (char *)rindex(filename,'/');
	if (cp)
	{
		*cp = 0;
		chdir(filename);
	}
	if (!dFlag && !tFlag)
		checkAuth();

	lseek(fd,0,0);
	yyparse();
	parseArgs();

	if (dFlag)
	{
		dumpCode();
	}
	else
	{
		runCode("main");
		sendFooter();
	}
	exit(0);
}
