/* Synchronet RFC822 message date/time string conversion routines */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
 *																			*
 * 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.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "msgdate.h"
#include "smblib.h"
#include "datewrap.h"
#include "date_str.h"

/****************************************************************************/
/* Convert when_t structure to RFC822 date header field (string)			*/
/****************************************************************************/
char* msgdate(when_t when, char* buf)
{
	struct tm tm;
	char      plus = '+';
	short     tz;
	time_t    tt;

	tz = smb_tzutc(when.zone);
	if (tz < 0) {
		plus = '-';
		tz = -tz;
	}

	tt = smb_time(when);
	if (localtime_r(&tt, &tm) == NULL)
		memset(&tm, 0, sizeof(tm));
	sprintf(buf, "%s, %d %s %d %02d:%02d:%02d %c%02u%02u"
	        , wday[tm.tm_wday]
	        , tm.tm_mday
	        , mon[tm.tm_mon]
	        , 1900 + tm.tm_year
	        , tm.tm_hour
	        , tm.tm_min
	        , tm.tm_sec
	        /* RFC1123: implementations SHOULD use numeric timezones instead of timezone names */
	        , plus, tz / 60, tz % 60
	        );
	return buf;
}

/****************************************************************************/
/* Convert RFC822 date header field to when_t structure						*/
/* dd mon yyyy hh:mm:ss [zone]												*/
/****************************************************************************/
when_t rfc822date(char* date)
{
	char*     p = date;
	char      str[32];
	char      month[32];
	struct tm tm;
	int16_t   zone = 0;

	memset(&tm, 0, sizeof(tm));

	while (*p && *p <= ' ') p++;
	while (*p && !IS_DIGIT(*p)) p++;
	/* DAY */
	tm.tm_mday = atoi(p);
	while (*p && IS_DIGIT(*p)) p++;
	/* MONTH */
	while (*p && *p <= ' ') p++;
	sprintf(month, "%3.3s", p);
	if (!stricmp(month, "jan"))
		tm.tm_mon = 0;
	else if (!stricmp(month, "feb"))
		tm.tm_mon = 1;
	else if (!stricmp(month, "mar"))
		tm.tm_mon = 2;
	else if (!stricmp(month, "apr"))
		tm.tm_mon = 3;
	else if (!stricmp(month, "may"))
		tm.tm_mon = 4;
	else if (!stricmp(month, "jun"))
		tm.tm_mon = 5;
	else if (!stricmp(month, "jul"))
		tm.tm_mon = 6;
	else if (!stricmp(month, "aug"))
		tm.tm_mon = 7;
	else if (!stricmp(month, "sep"))
		tm.tm_mon = 8;
	else if (!stricmp(month, "oct"))
		tm.tm_mon = 9;
	else if (!stricmp(month, "nov"))
		tm.tm_mon = 10;
	else
		tm.tm_mon = 11;
	p += 4;
	/* YEAR */
	tm.tm_year = atoi(p);
	if (tm.tm_year < Y2K_2DIGIT_WINDOW)
		tm.tm_year += 100;
	else if (tm.tm_year > 1900)
		tm.tm_year -= 1900;

	while (*p && IS_DIGIT(*p)) p++;
	/* HOUR */
	while (*p && *p <= ' ') p++;
	tm.tm_hour = atoi(p);
	while (*p && IS_DIGIT(*p)) p++;
	/* MINUTE */
	if (*p)
		p++;
	tm.tm_min = atoi(p);
	while (*p && IS_DIGIT(*p)) p++;
	/* SECONDS */
	if (*p)
		p++;
	tm.tm_sec = atoi(p);
	while (*p && IS_DIGIT(*p)) p++;
	/* TIME ZONE */
	while (*p && *p <= ' ') p++;
	if (*p) {
		if (IS_DIGIT(*p) || *p == '-' || *p == '+') { /* [+|-]HHMM format */
			if (*p == '+')
				p++;
			sprintf(str, "%.*s", *p == '-'? 3:2, p);
			zone = atoi(str) * 60;
			p += (*p == '-') ? 3:2;
			if (zone < 0)
				zone -= atoi(p);
			else
				zone += atoi(p);
		}
		else if (!strnicmp(p, "PDT", 3))
			zone = (short)PDT;
		else if (!strnicmp(p, "MDT", 3))
			zone = (short)MDT;
		else if (!strnicmp(p, "CDT", 3))
			zone = (short)CDT;
		else if (!strnicmp(p, "EDT", 3))
			zone = (short)EDT;
		else if (!strnicmp(p, "PST", 3))
			zone = (short)PST;
		else if (!strnicmp(p, "MST", 3))
			zone = (short)MST;
		else if (!strnicmp(p, "CST", 3))
			zone = (short)CST;
		else if (!strnicmp(p, "EST", 3))
			zone = (short)EST;
	}

	tm.tm_isdst = -1; /* Don't adjust for daylight-savings-time */

	return smb_when(mktime(&tm), zone);
}