
#ifdef __BORLANDC__
#pragma warn -8060
#endif
#ifdef __XCODE__
#include "xcode_quiet.h"
#endif

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#define DMID 14
#include "debug.h"
#include "decode.h"
static char vec[]=
	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";


int sisdigit(int c);
int sisalnum(int c);
int sisalpha(int c);
int sisupper(int c);
int sislower(int c);
int sisprint(int c);


static char chartonibble[256]=
{
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,			/* 0x00 - 0x0f */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,			/* 0x10 - 0x1f */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,			/*  ' ' - '/'  */
	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,			/*  '0' - '?'  */
	0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/*  '@' - 'O'  */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,			/*  'P' - '_'  */
	0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/*  '`' - 'o'  */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,			/*  'p' - 0x7f */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,			/* 0x80 - 0x8f */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,			/* 0x90 - 0x9f */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,			/* 0xa0 - 0xaf */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,			/* 0xb0 - 0xbf */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,			/* 0xc0 - 0xcf */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,			/* 0xd0 - 0xdf */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,			/* 0xe0 - 0xef */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0			/* 0xf0 - 0xff */
};

static char nibbletochar[16]=
{
	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
	
int decode_base64(char *in, char *out, int outlen)
{
	int	i, num=0, len, j;
	int nout=0;
	long	d, val;
	char	nw[4], *p, *c;

	len = (int)strlen(in)-1;
	for (i = 0; i < len; i += 4)	{
		val = 0;
		num = 3;
		c = in+i; 
		if (c[2] == '=')
			num = 1;
		else if (c[3] == '=') 
			num = 2;
		for (j = 0; j <= num; j++){
			if (!(p = strchr(vec, c[j]))) {
				*out = 0;  // FATAL ERROR, IT USED TO RETURN -1 AND RANDOM DATA...
				return 0;
			}
			d = (int)(p-vec);
			d <<= (3-j)*6;
			val += d;
		}
		for (j = 2; j >= 0; j--){
			nw[j] = val & 255;
			val >>= 8;
		}
		if (outlen>0) if (nout+num>=outlen) break;
		if (num<0) break;
		memcpy(out+nout,nw,num);
		nout += num;
	}
	if (nout<0) nout = 0; // FATAL ERROR, CHRISP FIXED 6/10/2020
	out[nout] = 0;
	return nout;
}


//same as decode_base64 except ignore cr and lf chars in input
int decode_base64_lines(char *in, int inlen, char *out, int outlen)
{
	int	i, num=0, len=inlen, j;
	int nout=0;
	long	d, val;
	char	nw[4], *p, *c;

	if (!inlen) inlen = (int)strlen(in)-1;
	for (i = 0; i < len; i += 4)	{
		val = 0;
		num = 3;
		c = in+i; 
		while (*c=='\r' || *c=='\n') {
			c++;
			i++;
			if (i>=len) break;
		}
		if (i>=len) break;
		if (c[2] == '=')
			num = 1;
		else if (c[3] == '=') 
			num = 2;
		for (j = 0; j <= num; j++){
			while (c[j]=='\r' || c[j]=='\n') {
				c++;i++;
			}
			if (!(p = strchr(vec, c[j]))) {
				return 0; // CHRISP FIXED USED TO RETURN -1
			}
			d = (int)(p-vec);
			d <<= (3-j)*6;
			val += d;
		}
		for (j = 2; j >= 0; j--){
			nw[j] = val & 255;
			val >>= 8;
		}
		if (outlen>0) if (nout+num>=outlen) break;
		if (num<0) break;
		memcpy(out+nout,nw,num);
		nout += num;
	}
	out[nout] = 0;
	return nout;
}


int encode_base64(char *in, char *out, int max_len)
/*
Warning - max_len must be one more than the length of the input.
e.g. encode_base64(txt,bf,(int)strlen(txt)+1)
out buffer should be at least max_len*4/3+4?
*/
{
	int  index, shift, save_shift=0;
	int help_flag = 0, replace_flag = 0, perm_replace_flag = 0, quit = 0;
	int cycle_flag = 0;
	unsigned char blivit;
	unsigned long accum, value;
	int firsttime = 1;
	int skipflag = 0;
	int printmsg = 1;
	char *xout=out;

	shift = 0;
	accum = 0;
	index = 0;
	while ( ( max_len>0 ) || (shift != 0) )
	{
		if ( ( max_len>0 ) && ( quit == 0 ) )
		{
			blivit = *(in++);
			max_len--;

			if ( max_len==0 )
			{
				quit = 1;
				save_shift = shift;
				blivit = 0;
			}
		}
		else
		{
			quit = 1;
			save_shift = shift;
			blivit = 0;
		}

		if ( (quit == 0) || (shift != 0) )
		{
			value = (unsigned long)blivit;
			accum <<= 8;
			shift += 8;
			accum |= value;
		}

		while ( shift >= 6 )
		{
			shift -= 6;
			value = (accum >> shift) & 0x3Fl;
			blivit = vec[value];

			*(out++)=blivit;

			if ( quit != 0 )
			{
				shift = 0;
			}
		}
	}

	if ( save_shift == 2 )
	{
		*(out++)='=';
		*(out++)='=';
	}
	else if ( save_shift == 4 )
	{
		*(out++)='=';
	}
	(*out)=0;
	
	return (int)(out-xout);
}

#define DEC(c)	(((c) - ' ') & 077)

int decode_uu(char *in, char *out, int outlen)
{
    int c, len;
    int nout=0;

	if(*in==0)
		return 0;

    len = DEC(*in++);
    while (len && nout<outlen) {
	c = DEC(*in) << 2 | DEC(in[1]) >> 4;
	out[nout++] = c;
	if (--len) {
	    c = DEC(in[1]) << 4 | DEC(in[2]) >> 2;
	    out[nout++] = c;
	    if (--len) {
		c = DEC(in[2]) << 6 | DEC(in[3]);
	        out[nout++] = c;
		len--;
	    }
	}
	in += 4;
    }
    out[nout] = 0;
    return nout;
}

#define ENC(c) (((c)&077)+' ')

void uuenc(FILE *in,FILE *out)
{
	char buff[80];
	int i,x=1;

	do {
		memset(buff,0,79);
		x = (int)fread(buff,1,45,in);
		if(x>0) {	
			putc(ENC(x),out);
			for (i=0;i<x;i+=3) {		
				putc(ENC(buff[i]>>2),out);
				putc(ENC((buff[i]<<4)&060)|((buff[i+1]>>4)&017),out);
				putc(ENC((buff[i+1]<<2)&074)|((buff[i+2]>>6)&03),out);
				putc(ENC(buff[i+2]&077),out);
			}
			putc('\r',out);
			putc('\n',out);
		}
	} while(x>0);
}


int encode_quoted(char *in, int inlen, char *out, int outlen)
{

	char *start=out;
	int i;
	/* returns actual length */	
	for (i=0; i<inlen; i++) {
		if (sisprint(in[i]) && in[i] != '=') {
			*out++ = in[i];
		} else {
			*out++ = '=';
			*out++ = nibbletochar[(in[i]&0xf0)>>4];
			*out++ = nibbletochar[(in[i]&0x0f)];
		}
		if (out-start>(outlen-4)) break;
	}
	start[out-start] = 0;
	return (int)(out-start);
}

int decode_quoted(char *in, char *out, int outlen)
{
	int i;
	char *upto=out, *s=in, c;
	for (i=0; upto-out<outlen-2 && *s!=0;s++) {
		if (*s<0) {
			*upto++ = *s++;
			*upto++ = *s;
		} else if (*s=='=') {
			if (strncmp(s,"=\r\n",3)==0) { /* SOFT crlf, remove */
				s += 2;
				continue;
			}
			if (strncmp(s,"=\n",3)==0) { /* SOFT lf, remove */
				s++;
				continue;
			}
			if (s[1]==0) break;
			if (s[2]==0) break;
			c = decode_hexbyte(s+1);
			*upto++ = c;
			s+=2;
		} else *upto++ = *s;
	}
	*upto = 0;
	return (int)(upto-out);
}

int decode_hexbyte(char *in)
{
	char c;

	if(*in==0)
		return 0;

	c=(chartonibble[*in++]<<4);

	if(*in==0)
		return c;

	c|=(chartonibble[*in++]);
	return c;
}
int ydecode(char *in,int insz,char *out, int outsz) /* RL, modified by chrisp, outsz added */
{
	int inpos,outpos;
	int bol=TRUE;
	int skip=FALSE;

	for(inpos=outpos=0;inpos<insz;) {
		if(*(in+inpos)=='\r' || *(in+inpos)=='\n') {inpos++; bol = TRUE; skip=FALSE; continue;}
		//=ypart begin=1 end=320000
		if (bol) if (in[inpos]=='=') {
			if (strncmp(in+inpos,"=ybegin",7)==0) {
				skip = TRUE;
			}
			if (strncmp(in+inpos,"=ypart",6)==0) {
				skip = TRUE;
			}
			if (strncmp(in+inpos,"=yend",5)==0) {
				skip = TRUE;
			}
		}
		bol = FALSE;
		if (skip) { // Skipping =ypart etc... to end of line.
			inpos++;
			continue;
		}
		if(*(in+inpos)!='=') {
			*(out+outpos)=*(in+inpos)-42;
		} else {
			inpos++;
			*(out+outpos)=*(in+inpos)-106;
		}
		inpos++;
		outpos++;
		if (outpos>=outsz-5) break;
	}
	return outpos;
}

int hex_digit(char c)
{
	if (c>='0' && c<='9')
		return c-'0';
	if (c>='A' && c<='F')
		return c-'A'+10;
	if (c>='a' && c<='f')
		return c-'a'+10;
	return 0;
}

char hex_char(char *code)
{
	int c=hex_digit(*code)*16+hex_digit(*(code+1));
	return c;
}

int decode_quoted_printable(char *line, char *out, int bfsz)
{
	char *xout=out;
	int end_with_nl=TRUE;
	while(*line && (out-xout<bfsz-5)) {
		if (*line=='=') {
			line++;
			if (*line && *(line+1)) {
				*(out++)=hex_char(line);
				line++;
				line++;
			}
			else {
				end_with_nl=FALSE;
			}
		}
/*		else if (*line=='_') {
			*(out++)=' ';
			line++;
		}
*/
		else {
			*(out++)=*(line++);
		}
	}
	if (end_with_nl) {
		*(out++)='\r';
		*(out++)='\n';
	}
	return (int)(out-xout);
}
    
char *decode_iso_q(char *text, char *xbf, int bfsz)
{
	char *bf=xbf;
	while (bf-xbf<bfsz-4 && *text && *text!='?') {
		if (*text=='=' && *(text+1) && *(text+2)) {
			*bf=hex_char(text+1);
			text+=2;

		}
		else if (*text=='_') {
			*bf=' ';
		}
		else {
			*bf=*text;
		}
		bf++;text++;
	}
	*bf=0;
	return xbf;
}
char *decode_iso_b(char *text, char *bf, int bfsz)
{
	char tmp[2000];
	int len;
	char *p;
	strncpy(tmp,text,1999);
	tmp[1999]=0;
	p=strchr(tmp,'?');
	if (p) *p=0;
	if (*tmp==0) return "";
	len=decode_base64(tmp,bf,bfsz-1);
	if (len<=0) return "";
	if (len>bfsz-1) len=bfsz-1;
	bf[len]=0;
	return bf;
}

int (*dmsg_fn)(const char * arg_list, ...);


void decode_set_dmsg(int (*vemsg)(const char * arg_list, ...))
{
	dmsg_fn=vemsg;
}


char *decode_iso(char *text)
{
	return mime_header_inplace(text);
}

char *decode_iso_broken(char *text)
/*

modifies input buffer and returns it

=?iso-8859-1?q?this=20is=20some=20text?=

*/
{
	char *ret=text;
	char *p,*p2,*p3,*p4;
	char tmp[2000];
	while(1) {
		char *out;
		int len;
		int mtype=0;
		char *decoded_text;
		char *src_text;
		char *type_char;
		p=strstr(text,"=?");
		if (!p) break;
		if (dmsg_fn) dmsg_fn("decode [%s]",text);
		p2=strchr(p+2,'?');
		if (!p2) break;
		type_char=p2+1;
		p3=strchr(type_char,'?');
		if (!p3) break;
		src_text=p3+1;
		p4=strstr(src_text,"?=");
		if (!p4) break;
		*p=0;
		*p4=0;
		out=p;
		if (dmsg_fn) dmsg_fn("type char=%c",*type_char);
		if (*type_char=='Q' || *type_char=='q')
			mtype=1;
		else if (*type_char=='B' || *type_char=='b')
			mtype=2;

		if (mtype==0) break;
		if (mtype==1) decoded_text=decode_iso_q(src_text,tmp,1999);
		else decoded_text=decode_iso_b(src_text,tmp,1999);
		if (dmsg_fn) dmsg_fn("decode [%s]->[%s]",src_text,decoded_text);
		len=(int)strlen(decoded_text);
		strcpy(out,decoded_text);
		text=out+len;
		strcpy(text,p4+2);
	}
	return ret;
}

char *decode_iso_old(char *xtext, char *bf, int bfsz)
/*
=?iso-8859-1?q?this=20is=20some=20text?=
*/
{
	char *text=xtext;
	char *p;
	char tmp[2000];
	int len;
	char *decoded_text;
	int mtype=0;
	char *p2;
	if (*text!='=' || *(text+1)!='?') return xtext;
	if (dmsg_fn) dmsg_fn("text1=[%s]",text);
	text+=2;
	p2=strchr(text,'?');if (!p2) return xtext;
	/*if (strnicmp(text,"iso-8859-1?",11)==0) text+=11;
	else if (strnicmp(text,"iso-8859-15?",12)==0) text+=12;
	else return xtext;*/
	text=p2+1;

	if (*text=='Q' || *text=='q')
		mtype=1;
	else if (*text=='B' || *text=='b')
		mtype=2;
	else return xtext;
	text++;
	if (dmsg_fn) dmsg_fn("texta=[%s]",text);
	if (*text!='?') return xtext;
	if (dmsg_fn) dmsg_fn("textb=[%s]",text);
	text++;
	p=strchr(text,'?');
	if (!p) return xtext;
	//if (*(p+1)!='=' || *(p+2)!=0) return xtext;
	if (*(p+1)!='=') return xtext;
	if (mtype==1) decoded_text=decode_iso_q(text,tmp,1999);
	else decoded_text=decode_iso_b(text,tmp,1999);
	if (dmsg_fn) dmsg_fn("decoded_text=[%s]",decoded_text);
	len=(int)strlen(decoded_text);
	if (len>bfsz-1) len=bfsz-1;
	strncpy(bf,decoded_text,len);
	bf[len]=0;
	bfsz-=len;
	strncpy(bf+len,p+2,bfsz-len-1);
	bf[bfsz-1]=0;
	return bf;
}

