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