/*
    NewsCoaster
    Copyright (C) 1999-2002 Mark Harman

    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-1307  USA

    NewsCoaster Homepage :
        http://newscoaster.tripod.com/

    Mailing List to hear about announcements of new releases etc at:
        http://groups.yahoo.com/group/newscoaster-announce/
*/

#include <libraries/mui.h>

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

#include <clib/dos_protos.h>

#include "Vector.h"
#include "various.h"
#include "misc.h"
#include "DateHandler.h"
#include "strings.h"

/* Variable for the nLog #define. */
BOOL logbool = FALSE;

/* The log file handle. */
BPTR logFile=NULL;

/* Reads a line (either CR or LF terminated) from 'file' into 'buffer'.
 */
void Readln(BPTR file,char * buffer) {
	LONG ch = 0;
	for(;;) {
		ch=FGetC(file);
		if(ch==-1 || ch==10 || ch==13) {
			*buffer=0;
			break;
		}
		*buffer=(char)ch;
		buffer++;
	}
}

/* Decodes quoted printable plain text from 'in' and copies the result to
 * 'out'.
 * 'length' is the length of the encoded text.
 * 'nl' should be TRUE iff newline characters are to be skipped (this will
 * normally be the case).
 */
int decode_qprint(char * in,char * out,int length,BOOL nl) {
	// leave as %d not %s below!
	nLog("decode_qprint((char *)%d,(char *)%d,(int)%d,(BOOL)%d) called\n",in,out,length,nl);
	char t[4]="";
	int asc=0;
	int d=0;
	char * end=&in[length];
	do {
		if(*in=='=') {
			in++;
			if(*in==10) {
				if(nl) {
					in++;
					if(*in==13)
						in++;
				}
			}
			else {
				strncpy(t,in,2);
				t[2]=0;
				in+=2;
				sscanf(t,"%x",&asc);
				*out++=(char)asc;
				d++;
			}
		}
		else {
			*out++=*in++;
			d++;
		}
	} while(in<end);
	*out= '\0';
	return d;
}

/* Output a newline character to 'out', followed by 'quoteLevel' '>'
 * characters.
 */
void newLineHtml(char **out,int quoteLevel) {
	*(*out)++ = 10;
	for(int i=0;i<quoteLevel;i++) {
		*(*out)++ = '>';
		*(*out)++ = ' ';
	}
}

/* Converts HTML from 'in' into plain text and outputs the result to 'out'.
 * 'length' is the length of the HTML text.
 * 'reset' is whether to reset the quote level.
 */
void parse_html(char * in,char * out,int length,BOOL reset) {
	// leave as %d not %s below!
	nLog("parse_html((char *)%s,(char *)%d,(int)%d,(BOOL)%d) called\n",in,out,length,reset);
	static BOOL inTag=FALSE;
	static int quoteLevel = 0;
	if(reset) {
		inTag=FALSE;
		quoteLevel = 0;
	}
	char t[16] = "";
	char * end=&in[length];
	do {
		if(*in==10 || *in==13) {
			*out++ = ' ';
			in++;
		}
		else if(*in == '&') {
			in++;
			int i=0;
			while(*in != ';' && i<15)
				t[i++] = *in++;
			in++;
			t[i] = 0;
			if(iequals(t,"nbsp"))
				*out++ = ' ';
			else if(iequals(t,"amp"))
				*out++ = '&';
			else if(iequals(t,"copy"))
				*out++ = '©';
			else if(iequals(t,"lt"))
				*out++ = '<';
			else if(iequals(t,"gt"))
				*out++ = '>';
			else if(*t == '#' && i>1) {
				int val = atoi(&t[1]);
				*out++ = (char)val;
			}
		}
		else {
			if(inTag) {
				if(*in == '>')
					inTag=FALSE;
				in++;
			}
			else {
				if(*in == '<') {
					inTag=TRUE;
					in++;
					strncpy(t,in,15);
					t[15]=0;
					if(strincmp(in,"B>",2)==0)
						*out++ = '*';
					else  if(strincmp(in,"/B>",3)==0)
						*out++ = '*';
					else  if(strincmp(in,"I>",2)==0)
						*out++ = '/';
					else  if(strincmp(in,"/I>",3)==0)
						*out++ = '/';
					else  if(strincmp(in,"U>",2)==0)
						*out++ = '_';
					else  if(strincmp(in,"/O>",3)==0)
						*out++ = '_';
					else  if(strincmp(in,"BR>",3)==0)
						newLineHtml(&out,quoteLevel);
					else  if(strincmp(in,"P>",2)==0) {
						newLineHtml(&out,quoteLevel);
						newLineHtml(&out,quoteLevel);
					}
					else if(strincmp(in,"BLOCKQUOTE>",11)==0 || strincmp(in,"BLOCKQUOTE ",11)==0) {
						quoteLevel++;
						newLineHtml(&out,quoteLevel);
					}
					else if(strincmp(in,"/BLOCKQUOTE>",12)==0) {
						if(quoteLevel>0) {
							quoteLevel--;
							newLineHtml(&out,quoteLevel);
						}
					}
				}
				else
					*out++ = *in++;
			}
		}
	} while(in<end);
	*out=0;
}

/* Decodes base64 'in' and copies the result to 'out'.
 * 'length' is the length of the encoded text.
 */
int decode_base64(char *in,char *out,int length) {
	// leave as %d not %s below!
	nLog("decode_base64((char *)%d,(char *)%d,(int)%d) called\n",in,out,length);
	char *buffer = new char[length + 1024];
	char *buffero = buffer;
	int d=0,d2=0,c=0;
	char *end = &in[length];
	do {
		if(*in>='A' && *in<='Z') {
			*buffer++=*in - 'A';
			d++;
		}
		else if(*in>='a' && *in<='z') {
			*buffer++=*in - 'a' + 26;
			d++;
		}
		else if(*in>='0' && *in<='9') {
			*buffer++=*in - '0' + 52;
			d++;
		}
		else if (*in=='+') {
			*buffer++=62;
			d++;
		}
		else if (*in=='/') {
			*buffer++=63;
			d++;
		}
		else if (*in=='=') {
			//end of data?
			break;
		}
		in++;
	} while(in<end);
	*buffer = '\0';
	d2=0;
	for(c=0;c<d;c+=4) {
		if( d-c<4 ) {
			// needs special handling!
			*out++ = buffero[c]*4 + (buffero[c+1] / 16);
			d2++;
			if(c+2>=d)
				break;
			*out++ = (buffero[c+1] % 16)*16 + (buffero[c+2] / 4);
			d2++;
			break;
		}
		*out++ = buffero[c]*4 + (buffero[c+1] / 16);
		*out++ = (buffero[c+1] % 16)*16 + (buffero[c+2] / 4);
		*out++ = (buffero[c+2] % 4)*64 + buffero[c+3];
		d2+=3;
	}
	delete [] buffero;
	return d2;
}

int encode_base64(char *in,char *out,int length) {
	// leave as %d not %s below!
	nLog("encode_base64((char *)%d,(char *)%d,(int)%d) called\n",in,out,length);
	char *buffer = new char[(length*5)/3+8192];
	char *buffero = buffer;
	int d=0,d2=0,c=0;
	for(c=0;c<length;c+=3) {
		if( length-c<3) {
			// needs special handling!
			*buffer++ = (in[c] & 252)/4;
			if(c+1>=length) {
				*buffer++='=';
				*buffer++='=';
				*buffer++='=';
				d+=4;
				break;
			}
			*buffer++ = (in[c] & 3)*16 + (in[c+1] & 240)/16;
			*buffer++='=';
			*buffer++='=';
			d+=4;
			break;
		}
		*buffer++ = (in[c] & 252)/4;
		*buffer++ = (in[c] & 3)*16 + (in[c+1] & 240)/16;
		*buffer++ = (in[c+1] & 15)*4 + (in[c+2] & 192)/64;
		*buffer++ = (in[c+2] & 63);
		d+=4;
	}
	for(c=0;c<d;c++) {
		if(buffero[c]>=0 && buffero[c]<26) {
			*out++=buffero[c] + 'A';
			d2++;
		}
		else if(buffero[c]>=26 && buffero[c]<52) {
			*out++=buffero[c] - 26 + 'a';
			d2++;
		}
		else if(buffero[c]>=52 && buffero[c]<62) {
			*out++=buffero[c] - 52 + '0';
			d2++;
		}
		else if(buffero[c]==62) {
			*out++='+';
			d2++;
		}
		else if(buffero[c]==63) {
			*out++='/';
			d2++;
		}
		if((d2+1) % 73 == 0) {
			*out++=10;
			d2++;
		}
	}
	*out = '\0';
	delete [] buffero;
	return d2;
}

// todo: better handling of multifile messages
int ydecode(BOOL *corrupt,char *in,char *out,int length,uuEncodeData *uudata) {
	nLog("ydecode((BOOL *)%d,(char *)%d,(char *)%d,(int)%d,(uuEncodeData *)%d) called\n",corrupt,in,out,length,uudata);
	*corrupt = FALSE;
	char *end=&in[length];
	char *in2=NULL,*begin=NULL;
	char filename[1024] = "unnamed";
	char bbuf[1024] = "";
	if(strincmp(in,"=ybegin ",8)==0) {
		in2 = in;
		begin = in;
	}
	else {
		in2 = stristr_q(in,"\n=YBEGIN ");
		begin = in2+1;
	}
	in2 = strchr(in2+1,'\n');
	in2++;
	strncpy(bbuf,begin,(int)(in2-begin));
	bbuf[(int)(in2-begin)]=0;
	// name
	char *ptr = stristr_q(bbuf,"NAME=");
	if(ptr != NULL) {
		ptr += 5;
		char *eptr = NULL;
		if(*ptr == '\"') {
			ptr++;
			eptr = strchr(ptr,'\"');
		}
		else {
			eptr = strchr(ptr,' ');
			char *nl = strchr(ptr,'\n');
			if( (nl != NULL && nl < eptr) || eptr == NULL )
				eptr = nl;
		}
		if(eptr == NULL)
			strcpy(filename,ptr);
		else {
			strncpy(filename,ptr,(int)(eptr - ptr));
			filename[(int)(eptr - ptr)] = '\0';
		}
		StripTrail(filename,'\r');
	}
	// size
	int size1 = -1;
	ptr = stristr_q(bbuf,"SIZE=");
	if(ptr != NULL) {
		size1 = atoi( &ptr[5] );
		nLog("  found size1 = %d\n",size1);
	}

	strncpy(uudata->filename,filename,UUENCODEDATA_FILENAME_LEN);
	uudata->filename[UUENCODEDATA_FILENAME_LEN] = '\0';
	char *dot = NULL,*ndot = NULL;
	dot = strchr(uudata->filename,'.');
	while(dot != NULL) {
		ndot = strchr(&dot[1],'.');
		if(ndot == NULL)
			break;
		dot = ndot;
	}
	if(dot)
		strncpy(uudata->ext,dot,UUENCODEDATA_EXT_LEN);
	else
		strncpy(uudata->ext,".txt",UUENCODEDATA_EXT_LEN);
	uudata->ext[UUENCODEDATA_EXT_LEN] = '\0';

	int d2 = 0;
	//int size2 = -1;
	do {
		unsigned char c = *in2++;
		if(c == '\0' || c == 10 || c == 13) {
		//if(c == '\0' || c == 9 || c == 10 || c == 13) {
			// skip
		}
		else if(c == '=') {
			unsigned char c2 = *in2++;
			if(c2 == 'y' || c2 == 'Y') {
				//printf("%c %c %c\n",in2[0],in2[1],in2[2]);
				/*if(strincmp_q(in2,"END ",4)==0) {
					char *ptr = stristr_q(in2,"SIZE=");
					if(ptr != NULL) {
						size2 = atoi( &ptr[5] );
						nLog("  found size2 = %d\n",size2);
					}
				}*/
				char *nl = strchr(in2,'\n');
				if(nl != NULL)
					in2 = nl + 1;
				//printf(":%d %d\n",in2,end);
			}
			else {
				c2 = (unsigned char)(c2 - 64);
				c2 = (unsigned char)(c2 - 42);
				*out++ = c2;
				d2++;
			}
		}
		else {
			c = (unsigned char)(c - 42);
			*out++ = c;
			d2++;
		}
	} while(in2<end);
	*out = '\0';

	nLog("  actual length is = %d\n",d2);
	//if(d2 != size1 || d2 != size2) {
	if(d2 != size1) {
		*corrupt = TRUE;
	}

	return d2;
}

int uudecode(char * in,char * out,int length,uuEncodeData* uudata) {
	// leave as %d not %s below!
	nLog("uudecode((char *)%d,(char *)%d,(int)%d,(uuEncodeData *)%d) called\n",in,out,length,uudata);
	char *buffer = new char[length + 1024];
	char *buffero = buffer;
	int d=0,d2=0,c=0;
	char *end=&in[length];
	char *in2=NULL,*begin=NULL;
	char filename[1024] = "";
	char bbuf[1024] = "";
	//if(strincmp(in,"begin ",6)==0 && isdigit(in[6]) ) {
	// we should be at the start anyway
	if(strincmp(in,"begin ",6)==0) {
		in2=in;
		begin=in;
	}
	else {
		in2=stristr_q(in,"\nBEGIN ");
		begin=in2+1;
	}
	in2=strchr(in2+1,'\n');
	in2++;
	strncpy(bbuf,begin,(int)(in2-begin));
	bbuf[(int)(in2-begin)]=0;
	word(filename,bbuf,3);
	strncpy(uudata->filename,filename,UUENCODEDATA_FILENAME_LEN);
	uudata->filename[UUENCODEDATA_FILENAME_LEN] = '\0';
	char *dot = NULL,*ndot = NULL;
	dot = strchr(uudata->filename,'.');
	while(dot != NULL) {
		ndot = strchr(&dot[1],'.');
		if(ndot == NULL)
			break;
		dot = ndot;
	}
	if(dot)
		strncpy(uudata->ext,dot,UUENCODEDATA_EXT_LEN);
	else
		strncpy(uudata->ext,".txt",UUENCODEDATA_EXT_LEN);
	uudata->ext[UUENCODEDATA_EXT_LEN] = '\0';
	int count = 0;
	int k = 0;
	do {
		count=(int)*in2++ - 32;
		if(*in2=='\n' || *in2=='\0')
			break;
		if(count % 3!=0) {
			count+=3;
			if(count % 3==1)
				d-=2;
			if(count % 3==2)
				d--;
		}
		count=(count/3)*4;
		for(k=0;k<count;k++) {
			*buffer++=(*in2++ - 32) % 64;
			d++;
		}
		while(*in2!='\n' && *in2!='\0')
			in2++;
		if(*in2=='\0')
			break; // just to be safe
		in2++;
	} while(in2<end);
	*buffer = '\0';
	d2=0;
	for(c=0;c<d;c+=4) {
		if( d-c<4) {
			// needs special handling!
			*out++ = buffero[c]*4 + (buffero[c+1] / 16);
			d2++;
			if(c+2>=d)
				break;
			*out++ = (buffero[c+1] % 16)*16 + (buffero[c+2] / 4);
			d2++;
			break;
 		}
		*out++ = buffero[c]*4 + (buffero[c+1] / 16);
		*out++ = (buffero[c+1] % 16)*16 + (buffero[c+2] / 4);
		*out++ = (buffero[c+2] % 4)*64 + buffero[c+3];
		d2+=3;
	}
	delete [] buffero;
	return d2;
}

/* Converts a file extension 'ext' into a MIMEType 'type'.
 */
void getMIMEType(char * type,char * ext) {
	// leave as %d not %s below!
	nLog("getMIMEType((char *)%s,(char *)ext) called\n",type,ext);
	if(iequals(ext,".txt"))
		strcpy(type,"text/plain");
	else if(iequals(ext,".html"))
		strcpy(type,"text/html");
	else if(iequals(ext,".htm"))
		strcpy(type,"text/html");
	else if(iequals(ext,".shtml"))
		strcpy(type,"text/html");
	else if(iequals(ext,".guide"))
		strcpy(type,"text/x-aguide");
	else if(iequals(ext,".exe"))
		strcpy(type,"application/octet-stream");
	else if(iequals(ext,".ps"))
		strcpy(type,"application/postscript");
	else if(iequals(ext,".lha"))
		strcpy(type,"application/x-lha");
	else if(iequals(ext,".lzx"))
		strcpy(type,"application/x-lzx");
	else if(iequals(ext,".zip"))
		strcpy(type,"application/x-zip");
	else if(iequals(ext,".jpeg"))
		strcpy(type,"image/jpeg");
	else if(iequals(ext,".jpg"))
		strcpy(type,"image/jpeg");
	else if(iequals(ext,".png"))
		strcpy(type,"image/png");
	else if(iequals(ext,".gif"))
		strcpy(type,"image/gif");
	else if(iequals(ext,".iff"))
		strcpy(type,"image/x-ilbm");
	else if(iequals(ext,".wav"))
		strcpy(type,"audio/x-wav");
	else if(iequals(ext,".mpeg"))
		strcpy(type,"video/mpeg");
	else if(iequals(ext,".mpg"))
		strcpy(type,"video/mpeg");
	else if(iequals(ext,".mov"))
		strcpy(type,"video/quicktime");
	else if(iequals(ext,".anim"))
		strcpy(type,"video/x-anim");
}

BOOL translateCharset(unsigned char * text,char * charset) {
	if(*charset==0) {
		BOOL bit7=TRUE;
		while(*text!=NULL) {
			/*if(*text == 224) // bizarre hack, this ascii code appears sometimes for some unknown reason!
				*text = 32;*/
			if(*text++ > 128)
				bit7=FALSE;
		}
		return bit7;
	}
	else {
		BOOL bit7=TRUE;
		while(*text!=NULL) {
			/*if(*text == 224) // bizarre hack, this ascii code appears sometimes for some unknown reason!
				*text = 32;*/
			if(*text++ > 128)
				bit7=FALSE;
		}
		return bit7;
	}
	
}

/* Logging function.
 */
/*void nLog(char * text,...) {
	if((account.flags & Account::LOGGING)==0)
		return;*/
BOOL LogFunc(char * text,...) {
	struct DateStamp ds;
	DateTime dt;
	char dateLog[32] = "";
	char timeLog[32] = "";
	char message[16384] = "";
	va_list vlist;
	if(logFile!=NULL && text!=NULL) {
		va_start(vlist,text);
		vsprintf(message,text,vlist);
		va_end(vlist);
		DateStamp(&ds);
		dt.dat_Stamp=ds;
		dt.dat_Format=FORMAT_CDN;
		dt.dat_Flags=NULL;
		dt.dat_StrDay=NULL;
		dt.dat_StrDate=(unsigned char *)dateLog; // puts format dd-mm-yy
		dt.dat_StrTime=(unsigned char *)timeLog;
		DateToStr(&dt);
		Write(logFile,dateLog,strlen(dateLog));
		Write(logFile," - ",3);
		Write(logFile,timeLog,strlen(timeLog));
		Write(logFile," : ",3);
		Write(logFile,message,strlen(message));
		return TRUE;
	}
	return FALSE;
}
