/*
New safe cgi library

*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include <errno.h>
#ifdef WIN32
#include <process.h>
#endif
#include "emsg.h"
#include "lib.h"
#include "lprintf.h"
#include "cgilib.h"
#include "defines.h"
#ifndef TRUE
#define FALSE 0
#define TRUE (!FALSE)
#endif
static char path_script[BFSZ];
static Pair *query,*form;
static Pair *attachments;

char *cgi_path(void)
{
	return path_script;
}

int cgi_pressed(char *s)
{
	char bf[BFSZ];
	if (strlen(cgi_get(s))>0) return TRUE;
	sprintf(bf,"%s.x",s);
	if (strlen(cgi_get(bf))>0) return TRUE;
	return FALSE;
}
int cgi_get_left(char *part, char *var, char *val)
{
	Pair *p=form;
	strcpy(var,""); strcpy(val,"");
	for (;p!=NULL;p=p->next) {
		if (strncmp(p->var,part,strlen(part))==0) {
			ncpy(var,p->var,100);
			ncpy(val,p->val,100);
			return TRUE;
		}
	}
	return FALSE;
}
Pair *cgi_form_pair(void)
{
	return form;
}
char *cgi_get(char *var)
{
	char *s;
	s = pair_find(form,var);
	if ((s==NULL) || strlen(s)==0) s = pair_find(query,var);
	if (s==NULL) return "";
	return s;
}
int cgi_true(char *var)
{
	char bf[BFSZ];
	ncpy(bf,cgi_get(var),BFSZ-1);
	strlwr(bf);
	if (strcmp(bf,"on")==0) return TRUE;
	if (strcmp(bf,"checked")==0) return TRUE;
	if (strcmp(bf,"true")==0) return TRUE;
	return FALSE;
}
void cgi_find_root(char *script, char *rootname)
{
        char *last;
        char *s;
        char bf[BFSZ];
        ncpy(path_script,script,BFSZ-1);
        ncpy(bf,script,BFSZ-1);
        last = bf-1;
        for (s=bf;*s!=0;s++) {
                if (*s=='/') last = s;
                if (*s=='\\') last = s;
        }
        ncpy(rootname,last+1,BFSZ-1);
        s = strchr(rootname,'.');
        if (s!=NULL) *s = 0;
        if (strlen(rootname)==0) strcpy(rootname,"dnotice");
}

void cgi_wash_pair(Pair *list)
{
	Pair *p;
	for (p=list;p!=NULL;p=p->next) lib_simple_wash(p->val);
}
void cgi_wash(void)
{
	cgi_wash_pair(form);
	cgi_wash_pair(query);
}
void cgi_decode(void)
{
    int cl = atoi(lib_mygetenv("CONTENT_LENGTH"));
	char *m;
	cgi_decode_ref(lib_mygetenv("QUERY_STRING"));
	if (cl>0) {
		m = malloc(cl+100);
		fread(m,1,cl,stdin);
		m[cl] = 0;
		cgi_decode_content(m,cl);
		free(m);
	}
}
char *web_file_name(char *name)
{
	return pair_find(attachments,name);
}
int wmime_attach_close(FILE **attach, char *name, char *fname)
{
	if (*attach!=NULL) {
		fclose(*attach);
		*attach = NULL;
		pair_add(&attachments,name,fname);
	}
	strcpy(fname,"");	
	return TRUE;
}
#ifdef WIN32
#define getpid _getpid
#endif
char *web_attach_temp_name(char *bf, int bfsz)
{
	lprintf(bf,bfsz-1,"webnews_attach_%d.tmp",getpid());
	return bf;
}
#define BIGSZ 100000
void web_decode_mime(char *contents, int contentlen)
{
	char content[BFSZ];
	char tmp[BFSZ];
	Strlines v;
	char bound_part[BFSZ];
	char bound_end[BFSZ];
	char *s;
	int len,i;
	char tmp5[BFSZ];
	FILE *attach=NULL;
	char *line=NULL;
	int lasteol=FALSE;
	char fname[BFSZ];
	char name[BFSZ];
	char rname[BFSZ];
	char bf2[BFSZ];
	char boundary[BFSZ];
	char *body=NULL;
	int inhead = FALSE;
	char a_type[BFSZ];
	char a_name[BFSZ];
//	FILE *f;

	body = malloc(BIGSZ+1);
	strcpy(a_name,"");
	strcpy(body,""); strcpy(a_type,"");
	web_attach_temp_name(fname,BFSZ-1);
	ncpy(content,lib_mygetenv("CONTENT_TYPE"),BFSZ-1);
	s = strstr(content,"boundary=");
    if (s==NULL) {
        imsg("Can't find boundary in mime contents %s",content);
		free(body); body = NULL;
		return;
	}
	s += 9;
    ncpy(boundary,lib_get_quote(s,tmp),BFSZ-1);
    lprintf(bound_part,BFSZ-1,"--%s",boundary);
    lprintf(bound_end,BFSZ-1,"--%s--",boundary);
	strcpy(name,"");

	str_lines_start(&v,contents,contentlen);
	line = str_lines_next_bin(&v,&len);
	for (;line!=NULL;line = str_lines_next_bin(&v,&len)) {
		char xline[BFSZ];
		int n;
		n = len;
		if (n>=BFSZ) n = BFSZ-1;
		if (n<0) n = 0;
		ncpy(xline,line,n);

		if (strncmp(xline,bound_part,strlen(bound_part))==0) {
			inhead = TRUE;
			if (!name[0]) continue;
			if (attach!=NULL) wmime_attach_close(&attach,name,fname);
			else pair_add(&form,name,body);
			continue;
		}
		else if (strncmp(xline,bound_end,strlen(bound_end))==0) {
			if (!name[0]) continue;
			if (attach!=NULL) wmime_attach_close(&attach,name,fname);
			else pair_add(&form,name,body);
			continue;
		}
		if (inhead) {
			strcpy(body,"");
			lasteol = FALSE;
			if (strcmp(xline,"\r\n")==0) inhead = FALSE;
			if (isspace(xline[0])) goto skip;
			ncpy(bf2,xline,BFSZ-1); strlwr(bf2);
			if (strstr(bf2,"content-type: ")!=NULL) {
				s = xline + 14;
				ncpy(a_type,xline,BFSZ-1);
				s = strchr(a_type,';'); if (s!=NULL) *s = 0;
				s = strchr(a_type,'\r'); if (s!=NULL) *s = 0;
				s = strchr(a_type,'\n'); if (s!=NULL) *s = 0;
			}
			if (strstr(bf2,"content-disposition:")!=NULL) {
skip:			s = strstr(xline,"name="); if (s==NULL) continue;
				ncpy(name,lib_get_quote(s+5,tmp),BFSZ-1);
				s = strstr(xline,"filename="); if (s==NULL) continue;
				ncpy(rname,lib_get_quote(s+9,tmp),BFSZ-1);
				ncpy(a_name,rname,BFSZ-1);
				//pair_add(&form,"attach_name",a_name);

				// So if variable is 'pdf'
				// then, pdf_name = "xyz.pdf" 
				
				lprintf(tmp5,BFSZ-1,"%s_name",name);
				imsg("Adding to web (%s) (%s) (%s)\n",tmp5,a_name,name);
				pair_add(&form,tmp5,a_name);
				//web_input_add(l,tmp5,a_name);
				if ((attach==NULL)&&(strlen(a_name)>0)) {
					attach = fopen(fname,"wb");
//					l->has_attach=true;
					if (attach==NULL) emsg("Cannot create (%s) (%s)\n",fname,strerror(errno));
					imsg("Writing to %s %p\n",fname,attach);
				}
			}
		} else {
			if (attach!=NULL) {
				if (lasteol) fwrite("\r\n",1,2,attach);
				lasteol = FALSE;
				if (len>=2) if (strncmp(line+len-2,"\r\n",2)==0) {
					len-=2;
					lasteol = TRUE;
				} 
//printf("len %d, lasteol %d\n",len,lasteol);
				fwrite(line,1,len,attach);
			} else if (strlen(name)>0) {
				if (lasteol) ncat(body,"\r\n",BIGSZ-1);
				lasteol = FALSE;
				if (len >= 2 && strncmp(&line[len-2],"\r\n",2)==0) {
					lasteol = TRUE;
					len -= 2;
				}
				for(s = body; *s; s++) {}
				for(i = 0; i < len && (s-body) < BIGSZ-1; i++) *s++ = line[i];
				*s = 0;
			}
		}
	}
	str_lines_end(&v);
	if (attach!=NULL) fclose(attach);    
	free(body); body = NULL;
}


void cgi_decode_content(char *bf, int len)
{
	char *var;
	char *cl=bf;
	char *s;
	int x;


	if (strstr(lib_mygetenv("CONTENT_TYPE"),"multipart/form-data")!=NULL) {
		web_decode_mime(bf,len);
		return;
	}

	var = malloc(strlen(cl)*2+1000);
	pair_free(&form);
        for(x=0;cl[0] != '\0';x++) {
                cgi_getword(var,cl,'&');
                cgi_plustospace(var);
                cgi_unescape_url(var);
		s = strchr(var,'=');
		if (s==NULL) continue;
		*s = 0;
		pair_add(&form,var,s+1);
	}
	free(var);
}
int cgi_set(char *var, char *val)
{
	pair_add(&form,var,val);
	return TRUE;
}

void cgi_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++]);
}
void cgi_plustospace(char *str)
{
    register int x;

    for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' ';
}
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);
}

void cgi_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';
}

int cgi_decode_ref(char *ref)
{
	char *cl;
	char *var;
	char *s;
	int x;
	char *cgi;

	/* /cgi/dftpmgr.cgi?cmd=domain&domain=2 */
	cgi = strdup(ref);
	s = cgi;
	cl = s;
	var = malloc(strlen(cl)*2+1000);
	pair_free(&query);
        for(x=0;cl[0] != '\0';x++) {
                cgi_getword(var,cl,'&');
                cgi_plustospace(var);
                cgi_unescape_url(var);
		s = strchr(var,'=');
		if (s==NULL) continue;
		*s = 0;
		pair_add(&query,var,s+1);
	}
	free(var);
	return TRUE;
}
static char *weekday[]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", };
static char *months[]={
        "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
};
char *cookie_date_plus(int tplus, char *bf)
{
        time_t now;
        struct tm *t;
	struct tm atm;

        time(&now);
	now += tplus;
        t = safe_localtime(&now,&atm);
        if (t==NULL) t = safe_gmtime(&now,&atm);
        lprintf(bf,70-1,"%s, %d-%s-%d %02d:%02d:%02d GMT",
                weekday[t->tm_wday],
                t->tm_mday,months[t->tm_mon],t->tm_year+1900,
                t->tm_hour,t->tm_min,t->tm_sec);
        return bf;
}

int cgi_set_cookie(char *var, char *value, int life)
{
	char tmp[BFSZ];
	if (life==0)  // Session cookie, only lasts while browser is open
 	 printf("Set-Cookie: %s=%s\r\n",var,value);
	else // Real cookie, lasts for longer, but may not work...
 	 printf("Set-Cookie: %s=%s; expires=%s\r\n",var,value,cookie_date_plus(life,tmp));
	return TRUE;
}
//23 15:07:04:Info:p=4060  We got raw cookie (persist=chris@here.com|5141; session
//=chris@here.com|5141; webmail_lang-127.0.0.1=english; SW-STYLE=ocean; webnews
//=41ac_cookie)
//23 15:07:04:Info:p=4060  session cookie: (persist)
char *cgi_get_cookie(char *var, char *orig, int tmpsz)
{
        char *s;
        char *s2;
	char *upto;
        s = lib_mygetenv("HTTP_COOKIE");
        if (strlen(s)==0) s = lib_mygetenv("COOKIE");
        if (strlen(s)==0) {
		return "";
	}
	imsg("We got raw cookie (%s)\n",s);
        ncpy(orig,s,tmpsz);
        s = mystrtok(orig,";",&upto);
        for (;s!=NULL;) {
                for (;*s==' ';) s++;
                s2 = strchr(s,'='); if (s2==NULL) break;
                *s2 = 0;
                if (strcmp(s,var)==0) return s2+1;
                s = mystrtok(NULL,";",&upto);
        }
        return "";

}
char *cgi_clean(char *fname, char *tmp)
{
	char *s;
	char *xtmp=tmp;
	for (s=fname;*s!=0;s++) {
		if (isalnum(*s)) *tmp++ = *s;
		else if (*s=='/') *tmp++ = *s;
		else if (*s=='.') *tmp++ = *s;
		else if (*s==':') *tmp++ = *s;
		else if (*s==' ') *tmp++ = *s;
		else if (*s=='-') *tmp++ = *s;
		else if (*s=='+') *tmp++ = *s;
		else if (*s=='_') *tmp++ = *s;
		else if (*s=='\\') *tmp++ = *s;
		else *tmp++ = '?';
	}
	*tmp++ = 0;
	return xtmp;
}
char *cgi_clean_right(char *fname, char *tmp)
{
	char bf[BFSZ];
	char *s;
	char *last=NULL;
	ncpy(bf,cgi_clean(fname,tmp),BFSZ-1);
	for (s=bf;*s!=0;s++) {
		if (*s=='/') last = s;
		if (*s=='\\') last = s;
	}
	if (last!=NULL) ncpy(tmp,last+1,BFSZ-1);
	else ncpy(tmp,bf,BFSZ-1);
	return tmp;
}

int cgi_show_image(char *fname, char *savename, int isattach)
{
	int fz;
	int r;
	time_t mtime;
	char bf[BFSZ];
	char tmp3[BFSZ];
	FILE *f;
	f = fopen(fname,"rb");
	if (f==NULL) {
		printf("Content-type: text/html\n\n");	
		printf("Sorry, the file you requested does not exist\r\n\r\nThe file you requested does not exist. The url may be incorrect.\r\nRequested File: (%.200s)\r\n",cgi_clean_right(fname,tmp3));
		imsg("Sending no such file (%.100s)\n",fname);
		return TRUE;
	}
	fz = lib_file_osize(f);
	mtime = lib_mtime_open(f);

//Content-Type: image/gif;
// name="nicetits.gif"
//Content-Transfer-Encoding: base64
//Content-Disposition: inline;
// filename="nicetits.gif"


	if (!printf("Content-type: %.200s\r\n",lib_guess_content(fname))) goto failed;
	if (isattach) {
		printf("Content-disposition: Attachment; filename=\"%s\"\r\n",savename);
	} else {
		printf("Content-disposition: Inline; filename=\"%s\"\r\n",savename);
	}
	if (!printf("Content-Length: %d\r\n",fz)) goto failed;
	if (!printf("\r\n")) goto failed;
	for (;!feof(f);) {
		r = fread(bf,1,BFSZ-1,f);
		if (r<=0) break;
		fwrite(bf,1,r,stdout);
	}
failed:	if (f) fclose(f);
	return TRUE;
}
