/*
 * HSML inside screws core module
 *  :: pancake :: Copyleft@2004
 */

extern char **environ;
/* CORE */
#include <unistd.h>
#include <fcntl.h>
/* IO */
#include <stdio.h>
#include <stdlib.h>
/* SYS */
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
/* VARS */

char *wwwroot;
char *http1;
char *wwwindex;
char *mime;
char *b;

#include "../Hsml/Cache.h"
#include "modskel.h" /* Module skel */
#include "../Hsml/SubLang.h" /* include SubLang (hsml2) parser */

// Use standard macros
MODULE_TYPE(MTYPE_EXEC);
MODULE_NAME("HsmlExec");
MODULE_VERS("0.3");

bool init() /* Init function */
{
	struct stat sb;
	int err;

	cache_init();
	hsml_init();
	donotexec=0;

	MODULE_INIT();

	wwwroot=getenv("WWWROOT");
	if (!wwwroot)
		MODULE_ERROR("WWWROOT environ not defined.");

	mime=getenv("MIME");
	if (!mime)
		MODULE_ERROR("MIME not defined. Please insmod 'Mime' module.\n");

	wwwindex=getenv("INDEX");
	if (!wwwindex)
		{
		MODULE_MESSG("INDEX not defined. Using 'index.html'");
		wwwindex=strdup("index.html");
		}

	err=stat(wwwroot,&sb);
	if (err)
		MODULE_ERROR("WWWROOT '%s' doesn't exists."); // ,wwwroot

	if (!S_ISDIR(sb.st_mode))
	{
		printf("WWWROOT '%s' isn't a valid directory entry.\n",wwwroot);
		return false;
	}
	printf("   (i) WWWROOT is: %s\n",wwwroot);

	return true;
}

void printMyCode(int code)
{
	if (http1)
	{
		printf("HTTP/1.1 %d ",code);
		switch(code)
		{
		case 200: printf("OK"); break;
		case 204: printf("No Content"); break;
		case 302: printf("Found"); break;
		case 400: printf("Bad Request"); break;
		case 403: printf("Forbidden"); break;
		case 404: printf("File not found"); break;
		case 405: printf("Method not allowed"); break;
		case 500: printf("Internal Server Error"); break;
		case 501: printf("Method Not Implemented"); break;
		default:  printf("unknown"); break;
		}
		printf("\r\n");
		fflush(stdout);
	}
}

void printMyHeaders(int code)
{
	if (http1)
	{
		printf( "Date: %s\r\n"
				"Server: Screws %s - %s\r\n"
				"Connection: close\r\n",
				getenv("DATE"),VERSION,getenv("UNAME")); //,getenv("MIME"));
		if (code!=200)
		{
			printf("Content-type: %s\r\n",getenv("MIME"));
			printf("\r\n");
		}
	}
}


void
module_hsmlexec_range(long *len, long *seek)
{
	char *ptr;

	ptr=getenv("RANGE_LEN");
	if (ptr)
		*len=atoi(ptr);
	else *len=0;

	ptr=getenv("RANGE_SEEK");
	if (ptr)
		*seek=atoi(ptr);
	else *seek=0;
}


bool exec(char **opts) /* Exec function */
{
	int err;
	FILE *fd;
	char *file;
	char *method;
	char *range_;
	long range_len;
	long range_seek;
	long n,len,off;
	struct stat st;
	int tcpwin;
	char *params;
	
	http1=getenv("HTTP");
	if (http1[0]!='1') http1=0;

	method=getenv("METHOD");
	if (method)
	{
		if (!strcmp(method,"HEAD"))
		{
			if (http1)
			{
			printMyCode(200);
			printMyHeaders(200);
			}
			return true;
		}
		if (strcmp(method,"GET") && 
			 strcmp(method,"POST") &&
			 strcmp(method,"PUT") )
		{
			if (http1)
			{
				printMyCode(501);
				printMyHeaders(200);
				printf("Content-Type: text/plain\r\n\r\n");
			}
			printf("501 - Method '%s' not implemented.\r\n",method);
			return true;
		}
	} else return true; // XXX nice errlog? (internal error) (403 ?)

	file=getenv("TCPWINSIZE");
	if (file)
	{
		tcpwin=atoi(file);
		if (tcpwin<1 || tcpwin>65000) tcpwin=16000;
	} else tcpwin=16000;
	
	err=chdir(wwwroot);
	if (err)
	{
		printMyCode(404);
		printMyHeaders(404);
		printf("Cannot Change to dir '%s'\r\n",wwwroot);
	}

	file=getenv("FILE");
	if (!file) file=strdup("/"); // XXX ugly
	if (file)
	{
		file=(char *)malloc(strlen(file)+40);
		sprintf(file,"./%s",getenv("FILE"));
	}


	stat(file,&st);
	if (st.st_mode & S_IFDIR)
		{
		strcat(file,wwwindex);
		}

	module_hsmlexec_range(&range_len,&range_seek);

	/* parse body */
	params = getenv("ARGS");
	
	fd=fopen(file,"r");
	if (fd)
	{
		fseek(fd,0,SEEK_END);
		len=ftell(fd);
		fseek(fd,0,SEEK_SET);

		// Range support
		fseek(fd,range_seek,SEEK_SET);
		if (range_len>0)
		{
			if (range_len<len)
				len=range_len;
		} else {
			len-=range_seek;
			if (len<0) len=0;
		}

		printMyCode(200);

		if(!strcmp( getenv("MIME"),"text/html") )
		//if (!strcmp(getenv("FILETYPE"),"hsml"))
		{
			// XXX broken for large html files
			b=(char *)malloc(len);
			fread(b,len,1,fd);
			b[len]=0;

			printMyHeaders(200);
			if (!subLang(file,len))
			{
				/* isn't HSMLv2 just fflush */
				if (http1)
				{
					printf("Content-type: %s\r\n",getenv("MIME"));
					printf("\r\n");
					fflush(stdout); // provisional patch
				}
				//screws_send(1,"pop",3);
				//screws_send(1,b,len);
				err=fwrite(b,len,1,stdout);
				if (err<=0)
				{
					return true;
				}
			}
		} else {
			if (range_seek)
			{
			printf("Content-Range: bytes %d-%d/%d\r\n",range_seek,len,len+1);
			}
			printf("Content-Length: %d\r\n",len);
			printMyHeaders(300);	
			b=(char*)malloc(tcpwin+1);
			for(;;)
			{
				n=fread(b,1,tcpwin,fd);
				if (n==0)  break;
				fwrite(b,n,1,stdout);
				fflush(stdout);
		//		sleep(1);
			}
		}
	} else {
		setenv("MIME","text/plain",1);
		printMyCode(404);
		printMyHeaders(404);
		printf("File '%s' not found!\n",getenv("FILE"));
	}
   return true;
}
