xref: /plan9/sys/src/cmd/ip/imap4d/date.c (revision dba79dc8121478fd8794e9b3575bf7e9783bb69c)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
49a747e4fSDavid du Colombier #include <auth.h>
57dd7cddfSDavid du Colombier #include "imap4d.h"
67dd7cddfSDavid du Colombier 
77dd7cddfSDavid du Colombier char *
87dd7cddfSDavid du Colombier wdayname[7] =
97dd7cddfSDavid du Colombier {
107dd7cddfSDavid du Colombier 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
117dd7cddfSDavid du Colombier };
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier char *
147dd7cddfSDavid du Colombier monname[12] =
157dd7cddfSDavid du Colombier {
167dd7cddfSDavid du Colombier 	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
177dd7cddfSDavid du Colombier };
187dd7cddfSDavid du Colombier 
197dd7cddfSDavid du Colombier static void	time2tm(Tm *tm, char *s);
207dd7cddfSDavid du Colombier static void	zone2tm(Tm *tm, char *s);
217dd7cddfSDavid du Colombier static int	dateindex(char *d, char **tab, int n);
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier int
rfc822date(char * s,int n,Tm * tm)247dd7cddfSDavid du Colombier rfc822date(char *s, int n, Tm *tm)
257dd7cddfSDavid du Colombier {
267dd7cddfSDavid du Colombier 	char *plus;
277dd7cddfSDavid du Colombier 	int m;
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier 	plus = "+";
307dd7cddfSDavid du Colombier 	if(tm->tzoff < 0)
317dd7cddfSDavid du Colombier 		plus = "";
327dd7cddfSDavid du Colombier 	m = 0;
33d917ddf4SDavid du Colombier 	if(0 <= tm->wday && tm->wday < 7){
347dd7cddfSDavid du Colombier 		m = snprint(s, n, "%s, ", wdayname[tm->wday]);
357dd7cddfSDavid du Colombier 		if(m < 0)
367dd7cddfSDavid du Colombier 			return m;
377dd7cddfSDavid du Colombier 	}
387dd7cddfSDavid du Colombier 	return snprint(s+m, n-m, "%.2d %s %.4d %.2d:%.2d:%.2d %s%.4d",
397dd7cddfSDavid du Colombier 		tm->mday, monname[tm->mon], tm->year+1900, tm->hour, tm->min, tm->sec,
407dd7cddfSDavid du Colombier 		plus, (tm->tzoff/3600)*100 + (tm->tzoff/60)%60);
417dd7cddfSDavid du Colombier }
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier int
imap4date(char * s,int n,Tm * tm)447dd7cddfSDavid du Colombier imap4date(char *s, int n, Tm *tm)
457dd7cddfSDavid du Colombier {
467dd7cddfSDavid du Colombier 	char *plus;
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier 	plus = "+";
497dd7cddfSDavid du Colombier 	if(tm->tzoff < 0)
507dd7cddfSDavid du Colombier 		plus = "";
517dd7cddfSDavid du Colombier 	return snprint(s, n, "%2d-%s-%.4d %2.2d:%2.2d:%2.2d %s%4.4d",
527dd7cddfSDavid du Colombier 		tm->mday, monname[tm->mon], tm->year+1900, tm->hour, tm->min, tm->sec, plus, (tm->tzoff/3600)*100 + (tm->tzoff/60)%60);
537dd7cddfSDavid du Colombier }
547dd7cddfSDavid du Colombier 
557dd7cddfSDavid du Colombier int
imap4Date(Tm * tm,char * date)567dd7cddfSDavid du Colombier imap4Date(Tm *tm, char *date)
577dd7cddfSDavid du Colombier {
587dd7cddfSDavid du Colombier 	char *flds[4];
597dd7cddfSDavid du Colombier 
607dd7cddfSDavid du Colombier 	if(getfields(date, flds, 3, 0, "-") != 3)
617dd7cddfSDavid du Colombier 		return 0;
627dd7cddfSDavid du Colombier 
637dd7cddfSDavid du Colombier 	tm->mday = strtol(flds[0], nil, 10);
647dd7cddfSDavid du Colombier 	tm->mon = dateindex(flds[1], monname, 12);
657dd7cddfSDavid du Colombier 	tm->year = strtol(flds[2], nil, 10) - 1900;
667dd7cddfSDavid du Colombier 	return 1;
677dd7cddfSDavid du Colombier }
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier /*
707dd7cddfSDavid du Colombier  * parse imap4 dates
717dd7cddfSDavid du Colombier  */
727dd7cddfSDavid du Colombier ulong
imap4DateTime(char * date)737dd7cddfSDavid du Colombier imap4DateTime(char *date)
747dd7cddfSDavid du Colombier {
757dd7cddfSDavid du Colombier 	Tm tm;
767dd7cddfSDavid du Colombier 	char *flds[4], *sflds[4];
777dd7cddfSDavid du Colombier 	ulong t;
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier 	if(getfields(date, flds, 4, 0, " ") != 3)
807dd7cddfSDavid du Colombier 		return ~0;
817dd7cddfSDavid du Colombier 
827dd7cddfSDavid du Colombier 	if(!imap4Date(&tm, flds[0]))
837dd7cddfSDavid du Colombier 		return ~0;
847dd7cddfSDavid du Colombier 
857dd7cddfSDavid du Colombier 	if(getfields(flds[1], sflds, 3, 0, ":") != 3)
867dd7cddfSDavid du Colombier 		return ~0;
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier 	tm.hour = strtol(sflds[0], nil, 10);
897dd7cddfSDavid du Colombier 	tm.min = strtol(sflds[1], nil, 10);
907dd7cddfSDavid du Colombier 	tm.sec = strtol(sflds[2], nil, 10);
917dd7cddfSDavid du Colombier 
927dd7cddfSDavid du Colombier 	strcpy(tm.zone, "GMT");
936b6b9ac8SDavid du Colombier 	tm.yday = 0;
947dd7cddfSDavid du Colombier 	t = tm2sec(&tm);
957dd7cddfSDavid du Colombier 	zone2tm(&tm, flds[2]);
967dd7cddfSDavid du Colombier 	t -= tm.tzoff;
977dd7cddfSDavid du Colombier 	return t;
987dd7cddfSDavid du Colombier }
997dd7cddfSDavid du Colombier 
1007dd7cddfSDavid du Colombier /*
1017dd7cddfSDavid du Colombier  * parse dates of formats
1027dd7cddfSDavid du Colombier  * [Wkd[,]] DD Mon YYYY HH:MM:SS zone
1037dd7cddfSDavid du Colombier  * [Wkd] Mon ( D|DD) HH:MM:SS zone YYYY
1047dd7cddfSDavid du Colombier  * plus anything similar
1057dd7cddfSDavid du Colombier  * return nil for a failure
1067dd7cddfSDavid du Colombier  */
1077dd7cddfSDavid du Colombier Tm*
date2tm(Tm * tm,char * date)1087dd7cddfSDavid du Colombier date2tm(Tm *tm, char *date)
1097dd7cddfSDavid du Colombier {
1107dd7cddfSDavid du Colombier 	Tm gmt, *atm;
1117dd7cddfSDavid du Colombier 	char *flds[7], *s, dstr[64];
1127dd7cddfSDavid du Colombier 	int n;
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier 	/*
1157dd7cddfSDavid du Colombier 	 * default date is Thu Jan  1 00:00:00 GMT 1970
1167dd7cddfSDavid du Colombier 	 */
1177dd7cddfSDavid du Colombier 	tm->wday = 4;
1187dd7cddfSDavid du Colombier 	tm->mday = 1;
1197dd7cddfSDavid du Colombier 	tm->mon = 1;
1207dd7cddfSDavid du Colombier 	tm->hour = 0;
1217dd7cddfSDavid du Colombier 	tm->min = 0;
1227dd7cddfSDavid du Colombier 	tm->sec = 0;
1237dd7cddfSDavid du Colombier 	tm->year = 70;
1247dd7cddfSDavid du Colombier 	strcpy(tm->zone, "GMT");
1257dd7cddfSDavid du Colombier 	tm->tzoff = 0;
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier 	strncpy(dstr, date, sizeof(dstr));
1287dd7cddfSDavid du Colombier 	dstr[sizeof(dstr)-1] = '\0';
1297dd7cddfSDavid du Colombier 	n = tokenize(dstr, flds, 7);
1307dd7cddfSDavid du Colombier 	if(n != 6 && n != 5)
1317dd7cddfSDavid du Colombier 		return nil;
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier 	if(n == 5){
134*dba79dc8SDavid du Colombier 		for(n = 5; n >= 1; n--)
1357dd7cddfSDavid du Colombier 			flds[n] = flds[n - 1];
1367dd7cddfSDavid du Colombier 		n = 5;
1377dd7cddfSDavid du Colombier 	}else{
1387dd7cddfSDavid du Colombier 		/*
1397dd7cddfSDavid du Colombier 		 * Wday[,]
1407dd7cddfSDavid du Colombier 		 */
1417dd7cddfSDavid du Colombier 		s = strchr(flds[0], ',');
1427dd7cddfSDavid du Colombier 		if(s != nil)
1437dd7cddfSDavid du Colombier 			*s = '\0';
1447dd7cddfSDavid du Colombier 		tm->wday = dateindex(flds[0], wdayname, 7);
1457dd7cddfSDavid du Colombier 		if(tm->wday < 0)
1467dd7cddfSDavid du Colombier 			return nil;
1477dd7cddfSDavid du Colombier 	}
1487dd7cddfSDavid du Colombier 
1497dd7cddfSDavid du Colombier 	/*
1507dd7cddfSDavid du Colombier 	 * check for the two major formats:
1517dd7cddfSDavid du Colombier 	 * Month first or day first
1527dd7cddfSDavid du Colombier 	 */
1537dd7cddfSDavid du Colombier 	tm->mon = dateindex(flds[1], monname, 12);
1547dd7cddfSDavid du Colombier 	if(tm->mon >= 0){
1557dd7cddfSDavid du Colombier 		tm->mday = strtoul(flds[2], nil, 10);
1567dd7cddfSDavid du Colombier 		time2tm(tm, flds[3]);
1577dd7cddfSDavid du Colombier 		zone2tm(tm, flds[4]);
1587dd7cddfSDavid du Colombier 		tm->year = strtoul(flds[5], nil, 10);
1597dd7cddfSDavid du Colombier 		if(strlen(flds[5]) > 2)
1607dd7cddfSDavid du Colombier 			tm->year -= 1900;
1617dd7cddfSDavid du Colombier 	}else{
1627dd7cddfSDavid du Colombier 		tm->mday = strtoul(flds[1], nil, 10);
1637dd7cddfSDavid du Colombier 		tm->mon = dateindex(flds[2], monname, 12);
1647dd7cddfSDavid du Colombier 		tm->year = strtoul(flds[3], nil, 10);
1657dd7cddfSDavid du Colombier 		if(strlen(flds[3]) > 2)
1667dd7cddfSDavid du Colombier 			tm->year -= 1900;
1677dd7cddfSDavid du Colombier 		time2tm(tm, flds[4]);
1687dd7cddfSDavid du Colombier 		zone2tm(tm, flds[5]);
1697dd7cddfSDavid du Colombier 	}
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier 	if(n == 5){
1727dd7cddfSDavid du Colombier 		gmt = *tm;
1737dd7cddfSDavid du Colombier 		strncpy(gmt.zone, "", 4);
1747dd7cddfSDavid du Colombier 		gmt.tzoff = 0;
1757dd7cddfSDavid du Colombier 		atm = gmtime(tm2sec(&gmt));
1767dd7cddfSDavid du Colombier 		tm->wday = atm->wday;
1777dd7cddfSDavid du Colombier 	}else{
1787dd7cddfSDavid du Colombier 		/*
1797dd7cddfSDavid du Colombier 		 * Wday[,]
1807dd7cddfSDavid du Colombier 		 */
1817dd7cddfSDavid du Colombier 		s = strchr(flds[0], ',');
1827dd7cddfSDavid du Colombier 		if(s != nil)
1837dd7cddfSDavid du Colombier 			*s = '\0';
1847dd7cddfSDavid du Colombier 		tm->wday = dateindex(flds[0], wdayname, 7);
1857dd7cddfSDavid du Colombier 		if(tm->wday < 0)
1867dd7cddfSDavid du Colombier 			return nil;
1877dd7cddfSDavid du Colombier 	}
1887dd7cddfSDavid du Colombier 	return tm;
1897dd7cddfSDavid du Colombier }
1907dd7cddfSDavid du Colombier 
1917dd7cddfSDavid du Colombier /*
1927dd7cddfSDavid du Colombier  * zone	: [A-Za-z][A-Za-z][A-Za-z]	some time zone names
1937dd7cddfSDavid du Colombier  *	| [A-IK-Z]			military time; rfc1123 says the rfc822 spec is wrong.
1947dd7cddfSDavid du Colombier  *	| "UT"				universal time
1957dd7cddfSDavid du Colombier  *	| [+-][0-9][0-9][0-9][0-9]
1967dd7cddfSDavid du Colombier  * zones is the rfc-822 list of time zone names
1977dd7cddfSDavid du Colombier  */
1987dd7cddfSDavid du Colombier static NamedInt zones[] =
1997dd7cddfSDavid du Colombier {
2007dd7cddfSDavid du Colombier 	{"A",	-1 * 3600},
2017dd7cddfSDavid du Colombier 	{"B",	-2 * 3600},
2027dd7cddfSDavid du Colombier 	{"C",	-3 * 3600},
2037dd7cddfSDavid du Colombier 	{"CDT", -5 * 3600},
2047dd7cddfSDavid du Colombier 	{"CST", -6 * 3600},
2057dd7cddfSDavid du Colombier 	{"D",	-4 * 3600},
2067dd7cddfSDavid du Colombier 	{"E",	-5 * 3600},
2077dd7cddfSDavid du Colombier 	{"EDT", -4 * 3600},
2087dd7cddfSDavid du Colombier 	{"EST", -5 * 3600},
2097dd7cddfSDavid du Colombier 	{"F",	-6 * 3600},
2107dd7cddfSDavid du Colombier 	{"G",	-7 * 3600},
2117dd7cddfSDavid du Colombier 	{"GMT", 0},
2127dd7cddfSDavid du Colombier 	{"H",	-8 * 3600},
2137dd7cddfSDavid du Colombier 	{"I",	-9 * 3600},
2147dd7cddfSDavid du Colombier 	{"K",	-10 * 3600},
2157dd7cddfSDavid du Colombier 	{"L",	-11 * 3600},
2167dd7cddfSDavid du Colombier 	{"M",	-12 * 3600},
2177dd7cddfSDavid du Colombier 	{"MDT", -6 * 3600},
2187dd7cddfSDavid du Colombier 	{"MST", -7 * 3600},
2197dd7cddfSDavid du Colombier 	{"N",	+1 * 3600},
2207dd7cddfSDavid du Colombier 	{"O",	+2 * 3600},
2217dd7cddfSDavid du Colombier 	{"P",	+3 * 3600},
2227dd7cddfSDavid du Colombier 	{"PDT", -7 * 3600},
2237dd7cddfSDavid du Colombier 	{"PST", -8 * 3600},
2247dd7cddfSDavid du Colombier 	{"Q",	+4 * 3600},
2257dd7cddfSDavid du Colombier 	{"R",	+5 * 3600},
2267dd7cddfSDavid du Colombier 	{"S",	+6 * 3600},
2277dd7cddfSDavid du Colombier 	{"T",	+7 * 3600},
2287dd7cddfSDavid du Colombier 	{"U",	+8 * 3600},
2297dd7cddfSDavid du Colombier 	{"UT",	0},
2307dd7cddfSDavid du Colombier 	{"V",	+9 * 3600},
2317dd7cddfSDavid du Colombier 	{"W",	+10 * 3600},
2327dd7cddfSDavid du Colombier 	{"X",	+11 * 3600},
2337dd7cddfSDavid du Colombier 	{"Y",	+12 * 3600},
2347dd7cddfSDavid du Colombier 	{"Z",	0},
2357dd7cddfSDavid du Colombier 	{nil,	0}
2367dd7cddfSDavid du Colombier };
2377dd7cddfSDavid du Colombier 
2387dd7cddfSDavid du Colombier static void
zone2tm(Tm * tm,char * s)2397dd7cddfSDavid du Colombier zone2tm(Tm *tm, char *s)
2407dd7cddfSDavid du Colombier {
2417dd7cddfSDavid du Colombier 	Tm aux, *atm;
2427dd7cddfSDavid du Colombier 	int i;
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier 	if(*s == '+' || *s == '-'){
2457dd7cddfSDavid du Colombier 		i = strtol(s, &s, 10);
2467dd7cddfSDavid du Colombier 		tm->tzoff = (i / 100) * 3600 + i % 100;
2477dd7cddfSDavid du Colombier 		strncpy(tm->zone, "", 4);
2487dd7cddfSDavid du Colombier 		return;
2497dd7cddfSDavid du Colombier 	}
2507dd7cddfSDavid du Colombier 
2517dd7cddfSDavid du Colombier 	/*
2527dd7cddfSDavid du Colombier 	 * look it up in the standard rfc822 table
2537dd7cddfSDavid du Colombier 	 */
2547dd7cddfSDavid du Colombier 	strncpy(tm->zone, s, 3);
2557dd7cddfSDavid du Colombier 	tm->zone[3] = '\0';
2567dd7cddfSDavid du Colombier 	tm->tzoff = 0;
2577dd7cddfSDavid du Colombier 	for(i = 0; zones[i].name != nil; i++){
2587dd7cddfSDavid du Colombier 		if(cistrcmp(zones[i].name, s) == 0){
2597dd7cddfSDavid du Colombier 			tm->tzoff = zones[i].v;
2607dd7cddfSDavid du Colombier 			return;
2617dd7cddfSDavid du Colombier 		}
2627dd7cddfSDavid du Colombier 	}
2637dd7cddfSDavid du Colombier 
2647dd7cddfSDavid du Colombier 	/*
2657dd7cddfSDavid du Colombier 	 * one last try: look it up in the current local timezone
2667dd7cddfSDavid du Colombier 	 * probe a couple of times to get daylight/standard time change.
2677dd7cddfSDavid du Colombier 	 */
2687dd7cddfSDavid du Colombier 	aux = *tm;
2697dd7cddfSDavid du Colombier 	memset(aux.zone, 0, 4);
2707dd7cddfSDavid du Colombier 	aux.hour--;
2717dd7cddfSDavid du Colombier 	for(i = 0; i < 2; i++){
2727dd7cddfSDavid du Colombier 		atm = localtime(tm2sec(&aux));
2737dd7cddfSDavid du Colombier 		if(cistrcmp(tm->zone, atm->zone) == 0){
2747dd7cddfSDavid du Colombier 			tm->tzoff = atm->tzoff;
2757dd7cddfSDavid du Colombier 			return;
2767dd7cddfSDavid du Colombier 		}
2777dd7cddfSDavid du Colombier 		aux.hour++;
2787dd7cddfSDavid du Colombier 	}
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier 	strncpy(tm->zone, "GMT", 4);
2817dd7cddfSDavid du Colombier 	tm->tzoff = 0;
2827dd7cddfSDavid du Colombier }
2837dd7cddfSDavid du Colombier 
2847dd7cddfSDavid du Colombier /*
2857dd7cddfSDavid du Colombier  * hh[:mm[:ss]]
2867dd7cddfSDavid du Colombier  */
2877dd7cddfSDavid du Colombier static void
time2tm(Tm * tm,char * s)2887dd7cddfSDavid du Colombier time2tm(Tm *tm, char *s)
2897dd7cddfSDavid du Colombier {
2907dd7cddfSDavid du Colombier 	tm->hour = strtoul(s, &s, 10);
2917dd7cddfSDavid du Colombier 	if(*s++ != ':')
2927dd7cddfSDavid du Colombier 		return;
2937dd7cddfSDavid du Colombier 	tm->min = strtoul(s, &s, 10);
2947dd7cddfSDavid du Colombier 	if(*s++ != ':')
2957dd7cddfSDavid du Colombier 		return;
2967dd7cddfSDavid du Colombier 	tm->sec = strtoul(s, &s, 10);
2977dd7cddfSDavid du Colombier }
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier static int
dateindex(char * d,char ** tab,int n)3007dd7cddfSDavid du Colombier dateindex(char *d, char **tab, int n)
3017dd7cddfSDavid du Colombier {
3027dd7cddfSDavid du Colombier 	int i;
3037dd7cddfSDavid du Colombier 
3047dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++)
3057dd7cddfSDavid du Colombier 		if(cistrcmp(d, tab[i]) == 0)
3067dd7cddfSDavid du Colombier 			return i;
3077dd7cddfSDavid du Colombier 	return -1;
3087dd7cddfSDavid du Colombier }
309