/*
 *
 *  AM --- AmigaMail
 *  (C) 1991, 1992 by Christian Riede
 *
 *  AM is distributed in the hope that it will be useful, but WITHOUT ANY
 *  WARRANTY.  No author or distributor accepts responsibility to anyone
 *  for the consequences of using it or for whether it serves any
 *  particular purpose or works at all, unless he says so in writing.
 *  Refer to the GNU General Public License, Version 1, for full details.
 *  
 *  Everyone is granted permission to copy, modify and redistribute AM,
 *  but only under the conditions described in the GNU General Public
 *  License, Version 1.  A copy of this license is supposed to have been 
 *  given to you along with AM so you can know your rights and responsi-
 *  bilities.  It should be in a file named COPYING.  Among other things,
 *  the copyright notice and this notice must be preserved on all copies.
 *
 *  
 *
 */

#include "am.h"

static char *DayOfWeek[] = 
{
	"Sun","Mon","Tue","Wed","Thu","Fri","Sat"
};

static char *NameOfMonth[] = 
{	
	"Jan","Feb","Mar","Apr",
	"May","Jun","Jul","Aug",
	"Sep","Oct","Nov","Dec"
};

static int days[12]={31,30,31,28,31,30,31,31,30,31,30,31};

static void AddTime(struct tm *tm,int hoffset,int moffset)
{
	/* add minutes */
	tm->tm_min += moffset;

	/* handle minute over-/underflow */
	while (tm->tm_min>59) {tm->tm_min -= 60; tm->tm_hour +=1; }
	while (tm->tm_min<0) {tm->tm_min += 60; tm->tm_hour -=1; }

	/* add hours */
	tm->tm_hour += hoffset;

	/* handle hour over-/underflow */
	while (tm->tm_hour>23) {tm->tm_hour -= 24; tm->tm_mday +=1; }
	while (tm->tm_hour<0) {tm->tm_hour += 24; tm->tm_mday -=1; }

	/* handle day-of-month over-/underflow */
	while (tm->tm_mday>days[tm->tm_mon]) {tm->tm_mday -= days[ABS(tm->tm_mon%12)]; tm->tm_mon -=1; }
	while (tm->tm_mday<0) {tm->tm_mday += days[ABS(tm->tm_mon%12)]; tm->tm_mon -=1; }

	/* handle year over-/underflow */
	while (tm->tm_year<0) {tm->tm_mon  += 12; tm->tm_year -=1; }
	while (tm->tm_year<0) {tm->tm_mon  += 12; tm->tm_year -=1; }
}



/* generate date-time as specified in RFC822 */
/* returns pointer to internal buffer */
/* input (if given) in gmt, result in local time */
char *DateTime(time_t t,char *Return)
{
	struct tm *tm;

	if (!t) /* date given? */
	{
		time(&t);
		tm = gmtime(&t);
	}
	else
	{
		 /* date given in gmt! */
		tm = gmtime(&t);
	}

	sprintf(Return,
		"%s, %02d %s %04d %02d:%02d:%02d %s",
		DayOfWeek[tm->tm_wday],    /* day of week */
		tm->tm_mday,               /* day of month */
		NameOfMonth[tm->tm_mon],    /* month */
		1900+tm->tm_year,          /* year */
		tm->tm_hour,               /* hour */
		tm->tm_min,                /* minute */
		tm->tm_sec,                /* second */
		TimeZone                   /* Time Zone from uulib:config */
		);

	return(Return);
}

#define SKIPBLANKS(s) {while (isspace((int)*s)) s++;}


int ParseTimeZone(char *s,int *hoffset,int *moffset)
{
	char ZoneName[10];
	char *t;
	int i;

	if (*s=='+')
	{
		s++;
		sscanf(s,"%2d%2d",hoffset,moffset);
	}
	else if (*s=='-')
	{
		s++;
		sscanf(s,"%2d%2d",hoffset,moffset);
		*hoffset = -*hoffset;
		*moffset = -*moffset;
	}
	else
	{
		/* named zimezone */
		*hoffset = *moffset = 0;

		i=0; t=ZoneName;

		/* get name */
		while (isalpha((int)*s)&&i++<9)
			*t++ = *s++;
		*t=0;

		     if (!strcmp(ZoneName,"ADT")) *hoffset = -3;
		else if (!strcmp(ZoneName,"AHST")) *hoffset = -10;
		else if (!strcmp(ZoneName,"AST")) *hoffset = -4;
		else if (!strcmp(ZoneName,"AT")) *hoffset = -2;
		else if (!strcmp(ZoneName,"BST")) *hoffset = +1;
		else if (!strcmp(ZoneName,"BST")) *hoffset = -3;
		else if (!strcmp(ZoneName,"BST")) *hoffset = -11;
		else if (!strcmp(ZoneName,"BT")) *hoffset = -11;
		else if (!strcmp(ZoneName,"BT")) *hoffset = +3;
		else if (!strcmp(ZoneName,"CADT")) {*hoffset = +10; *moffset = 30;}
		else if (!strcmp(ZoneName,"CAST")) {*hoffset = +9; *moffset = 30;}
		else if (!strcmp(ZoneName,"CAT")) *hoffset = -10;
		else if (!strcmp(ZoneName,"CCT")) *hoffset = +8;
		else if (!strcmp(ZoneName,"CDT")) *hoffset = -5;
		else if (!strcmp(ZoneName,"CED")) *hoffset = +2;
		else if (!strcmp(ZoneName,"CEDT")) *hoffset = +2;
		else if (!strcmp(ZoneName,"CES")) *hoffset = +2;
		else if (!strcmp(ZoneName,"CEST")) *hoffset = +2;
		else if (!strcmp(ZoneName,"CET")) *hoffset = +1;
		else if (!strcmp(ZoneName,"CST")) *hoffset = -6;
		else if (!strcmp(ZoneName,"EADT")) *hoffset = +11;
		else if (!strcmp(ZoneName,"EAST")) *hoffset = +10;
		else if (!strcmp(ZoneName,"ECT")) *hoffset = +1;
		else if (!strcmp(ZoneName,"EDT")) *hoffset = -4;
		else if (!strcmp(ZoneName,"EET")) *hoffset = +2;
		else if (!strcmp(ZoneName,"EST")) *hoffset = -5;
		else if (!strcmp(ZoneName,"FST")) *hoffset = +2;
		else if (!strcmp(ZoneName,"FST")) *hoffset = +2;
		else if (!strcmp(ZoneName,"FWT")) *hoffset = +1;
		else if (!strcmp(ZoneName,"GMT")) *hoffset = 0;
		else if (!strcmp(ZoneName,"GST")) *hoffset = -3;
		else if (!strcmp(ZoneName,"GST")) *hoffset = +10;
		else if (!strcmp(ZoneName,"GVA")) *hoffset = +1;
		else if (!strcmp(ZoneName,"HFE")) *hoffset = +2;
		else if (!strcmp(ZoneName,"HFH")) *hoffset = +1;
		else if (!strcmp(ZoneName,"IDLE")) *hoffset = +12;
		else if (!strcmp(ZoneName,"IDLW")) *hoffset = -12;
		else if (!strcmp(ZoneName,"IST")) *hoffset = +2;
		else if (!strcmp(ZoneName,"IST")) {*hoffset = +5; *moffset = 30;}
		else if (!strcmp(ZoneName,"IT")) {*hoffset = +3; *moffset = 30;}
		else if (!strcmp(ZoneName,"JST")) *hoffset = +9;
		else if (!strcmp(ZoneName,"JT")) {*hoffset = +7; *moffset = 30;}
		else if (!strcmp(ZoneName,"MDT")) *hoffset = -6;
		else if (!strcmp(ZoneName,"MEST")) *hoffset = +2;
		else if (!strcmp(ZoneName,"MESZ")) *hoffset = +2;
		else if (!strcmp(ZoneName,"MET")) *hoffset = +1;
		else if (!strcmp(ZoneName,"MEWT")) *hoffset = +1;
		else if (!strcmp(ZoneName,"MEZ")) *hoffset = +1;
		else if (!strcmp(ZoneName,"MST")) *hoffset = -7;
		else if (!strcmp(ZoneName,"MT")) {*hoffset = +8; *moffset = 30;}
		else if (!strcmp(ZoneName,"NDT")){*hoffset = -2; *moffset = 30;}
		else if (!strcmp(ZoneName,"NST")) {*hoffset = -3; *moffset = 30;}
		else if (!strcmp(ZoneName,"NST")) {*hoffset = +6; *moffset = 30;}
		else if (!strcmp(ZoneName,"NT")) *hoffset = -11;
		else if (!strcmp(ZoneName,"NZDT")) *hoffset = +13;
		else if (!strcmp(ZoneName,"NZST")) *hoffset = +12;
		else if (!strcmp(ZoneName,"NZT")) *hoffset = +12;
		else if (!strcmp(ZoneName,"PDT")) *hoffset = -7;
		else if (!strcmp(ZoneName,"PST")) *hoffset = -8;
		else if (!strcmp(ZoneName,"SADT")) {*hoffset = +10; *moffset = 30;}
		else if (!strcmp(ZoneName,"SAST")) {*hoffset = +9; *moffset = 30;}
		else if (!strcmp(ZoneName,"SET")) *hoffset = +1;
		else if (!strcmp(ZoneName,"SST")) *hoffset = +2;
		else if (!strcmp(ZoneName,"SST")) *hoffset = +8;
		else if (!strcmp(ZoneName,"SST")) *hoffset = +7;
		else if (!strcmp(ZoneName,"SWT")) *hoffset = +1;
		else if (!strcmp(ZoneName,"UT")) *hoffset = 0;
		else if (!strcmp(ZoneName,"UTC")) *hoffset = 0;
		else if (!strcmp(ZoneName,"WADT")) *hoffset = +8;
		else if (!strcmp(ZoneName,"WAST")) *hoffset = +7;
		else if (!strcmp(ZoneName,"WAT")) *hoffset = -1;
		else if (!strcmp(ZoneName,"WET")) *hoffset = 0;
		else if (!strcmp(ZoneName,"WZ")) *hoffset = 0;
		else if (!strcmp(ZoneName,"YST")) *hoffset = -9;
		else if (!strcmp(ZoneName,"Z")) *hoffset = 0;
		else if (!strcmp(ZoneName,"ZP4")) *hoffset = +4;
		else if (!strcmp(ZoneName,"ZP5")) *hoffset = +5;
		else if (!strcmp(ZoneName,"ZP6")) *hoffset = +6;

		if (*s=='+')
		{
			sscanf(s,"%d",&i);
			*hoffset+=i;
		}
		else if (*s=='-')
		{
			sscanf(s,"%d",&i);
			*hoffset-=i;
		}
	}

	return(TRUE);
}


/* parse RFC822 conform date (result in GMT!!!)*/
int ParseDate(char *s,struct tm *tm)
{
	char Dummy[160],*t;
	int hoffset,moffset,i;

	/* skip leading blanks */
	SKIPBLANKS(s);

	/* skip day, if present */
	while (isalpha((int)*s)) s++;
	
	/* skip blanks, komma */
	while (*s==' ' || *s==',') s++;

	/* scan day of month */
	tm->tm_mday = 0;
	while (isdigit((int)*s))
	{
		tm->tm_mday *= 10;
		tm->tm_mday += *s-'0';
		s++;
	}

	SKIPBLANKS(s);

	/* scan monthname */
	t=Dummy; i=0;
	while (isalpha((int)*s) && i<159)
	{
		i++;
		*t++=*s++;
	}
	*t=0;

	/* get month */
	if (!strcmp(Dummy,"Jan")) tm->tm_mon = 0;
	else if (!strcmp(Dummy,"Feb")) tm->tm_mon = 1;
	else if (!strcmp(Dummy,"Mar")) tm->tm_mon = 2;
	else if (!strcmp(Dummy,"Apr")) tm->tm_mon = 3;
	else if (!strcmp(Dummy,"May")) tm->tm_mon = 4;
	else if (!strcmp(Dummy,"Jun")) tm->tm_mon = 5;
	else if (!strcmp(Dummy,"Jul")) tm->tm_mon = 6;
	else if (!strcmp(Dummy,"Aug")) tm->tm_mon = 7;
	else if (!strcmp(Dummy,"Sep")) tm->tm_mon = 8;
	else if (!strcmp(Dummy,"Oct")) tm->tm_mon = 9;
	else if (!strcmp(Dummy,"Nov")) tm->tm_mon = 10;
	else if (!strcmp(Dummy,"Dec")) tm->tm_mon = 11;

	SKIPBLANKS(s);

	/* scan year */
	tm->tm_year = 0;
	while (isdigit((int)*s))
	{
		tm->tm_year *= 10;
		tm->tm_year += *s-'0';
		s++;
	}

	/* full year given ? */
	if (tm->tm_year>100) tm->tm_year-=1900;
	
	SKIPBLANKS(s);

	/* scan hour */
	tm->tm_hour = 0;
	while (isdigit((int)*s))
	{
		tm->tm_hour *= 10;
		tm->tm_hour += *s-'0';
		s++;
	}

	if (*s==':') s++; /* skip : */

	/* scan minute */
	tm->tm_min = 0;
	while (isdigit((int)*s))
	{
		tm->tm_min *= 10;
		tm->tm_min += *s-'0';
		s++;
	}

	if (*s==':') s++; /* skip : */

	/* scan second */
	tm->tm_sec = 0;
	while (isdigit((int)*s))
	{
		tm->tm_sec *= 10;
		tm->tm_sec += *s-'0';
		s++;
	}

	SKIPBLANKS(s);

	/* zone */
	ParseTimeZone(s,&hoffset,&moffset);		

	/* convert to local time */
	AddTime(tm,-hoffset,-moffset);

	return(TRUE);
}
