static char rcsid[] = "@(#)$Id: parsarpdat.c,v 1.3 2006/04/09 07:37:08 hurtta Exp $"; /****************************************************************************** * The Elm (ME+) Mail System - $Revision: 1.3 $ $State: Exp $ * * Modified by: Kari Hurtta * (was hurtta+elm@ozone.FMI.FI) ****************************************************************************** * The Elm Mail System * * Copyright (c) 1993 USENET Community Trust *****************************************************************************/ #include "def_mbox.h" DEBUG_VAR(Debug,__FILE__,"header"); /* Quoting from RFC 822: 5. DATE AND TIME SPECIFICATION 5.1. SYNTAX date-time = [ day "," ] date time ; dd mm yy ; hh:mm:ss zzz day = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun" date = 1*2DIGIT month 2DIGIT ; day month year ; e.g. 20 Jun 82 month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" time = hour zone ; ANSI and Military hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59 zone = "UT" / "GMT" ; Universal Time ; North American : UT / "EST" / "EDT" ; Eastern: - 5/ - 4 / "CST" / "CDT" ; Central: - 6/ - 5 / "MST" / "MDT" ; Mountain: - 7/ - 6 / "PST" / "PDT" ; Pacific: - 8/ - 7 / 1ALPHA ; Military: Z = UT; ; A:-1; (J not used) ; M:-12; N:+1; Y:+12 / ( ("+" / "-") 4DIGIT ) ; Local differential ; hours+min. (HHMM) */ int parse_date_time(str,time_zone,size_time_zone,tz_offset, time_result) CONST char *str; char *time_zone; int size_time_zone; time_t *tz_offset; time_t *time_result; { /* * Parse a date field in either RFC-822 or Unix date(1) format. */ char field[STRING], save_tz[STRING]; int month, day, year, hours, mins, secs, tz, len, i; /* * Since this is an RFC-822 field, there might be parenthetical * comments. Yank them out. Note that strip_parens() returns * a pointer to static data. */ str = strip_parens(str); /* * The first field is an optional day of the week. If it exists * it is supposed to have a trailing comma by RFC-822, but we won't * complain if it doesn't. If the date string was generated by * the Unix date(1) command then it won't have the comma. We don't * do anything with this information, just skip over it if it exists. */ if ((len = get_word(str, 0, field, sizeof(field))) < 0) goto failed; if (cvt_dayname_to_daynum(field, &i)) str += len; /* * Peek at the next character to determine what format to * parse the rest of the line as. */ while (isspace(*str)) ++str; if (!isdigit(*str)) { /* * Parse the line in Unix date(1) format. The syntax is: * * month day hh:mm:ss [tz] year * * e.g. "Jun 21 06:45:44 CDT 1989". The timezone is optional. */ DPRINT(Debug,7,(&Debug, "parse_date_time parsing \"%s\" in time(1) format\n", str)); /* */ if ((len = get_word(str, 0, field, sizeof(field))) < 0 || !cvt_monthname_to_monthnum(field, &month)) goto failed; str += len; /* */ if ((len = get_word(str, 0, field, sizeof(field))) < 0 || (day = atonum(field)) < 0) goto failed; str += len; /* */ if ((len = get_word(str, 0, field, sizeof(field))) < 0 || !cvt_timestr_to_hhmmss(field, &hours, &mins, &secs)) goto failed; str += len; /* optional */ save_tz[0] = save_tz[1] = '\0'; tz = 0; while ((len = get_word(str, 0, field, sizeof(field))) > 0 && cvt_timezone_to_offset(field, &i, sizeof field)) { (void) strfcat(save_tz, " ", sizeof save_tz); (void) strfcat(save_tz, field, sizeof save_tz); tz += i; str += len; } /* */ if ((len = get_word(str, 0, field, sizeof(field))) < 0 || (year = atonum(field)) < 0) goto failed; str += len; /* there might be more...but we ignore it */ } else { /* * Parse the line in RFC-822 format. The syntax is: * * day month year hh:mm:ss zone * * e.g. "17 Nov 92 23:34:25 CST". */ DPRINT(Debug,7,(&Debug, "parse_date_time parsing \"%s\" in RFC-822 format\n", str)); /* */ if ((len = get_word(str, 0, field, sizeof(field))) < 0 || (day = atonum(field)) < 0) goto failed; str += len; /* */ if ((len = get_word(str, 0, field, sizeof(field))) < 0 || !cvt_monthname_to_monthnum(field, &month)) goto failed; str += len; /* */ if ((len = get_word(str, 0, field, sizeof(field))) < 0 || !cvt_yearstr_to_yearnum(field, &year)) goto failed; str += len; /* */ if ((len = get_word(str, 0, field, sizeof(field))) < 0) { /* on expires header there is no necessary time -part */ save_tz[0] = save_tz[1] = '\0'; tz = 0; hours = 0; mins = 0; secs = 0; DPRINT(Debug,7,(&Debug, " only date given (no time and timezone)\n")); goto notime; } if (!cvt_timestr_to_hhmmss(field, &hours, &mins, &secs)) goto failed; str += len; /* - silently ignore bogus or missing timezones */ save_tz[0] = save_tz[1] = '\0'; tz = 0; while ((len = get_word(str, 0, field, sizeof(field))) > 0 && cvt_timezone_to_offset(field, &i, sizeof field)) { (void) strfcat(save_tz, " ", sizeof save_tz); (void) strfcat(save_tz, field, sizeof save_tz); tz += i; str += len; } /* there might be more...but we ignore it */ } notime: if (time_zone) strfcpy(time_zone, save_tz+1, size_time_zone); if (tz_offset) *tz_offset = tz*60; *time_result = make_gmttime(year, month, day, hours, mins-tz, secs); DPRINT(Debug,7,(&Debug, " year=%d month=%d day=%d\n", year, month, day)); DPRINT(Debug,7,(&Debug, " hours=%d mins=%d secs=%d tz=%d\n", hours, mins, secs, tz)); DPRINT(Debug,7,(&Debug, " time_result=%ld\n",(long)*time_result)); DPRINT(Debug,7,(&Debug, " return success\n")); return TRUE; failed: DPRINT(Debug,4,(&Debug, "parse_date_time failed at \"%s\"\n", (len <= 0 ? "" : field))); return FALSE; } int parse_arpa_date(src, entry) char *src; struct header_rec *entry; { /* * Parse a date field in either RFC-822 or Unix date(1) format. * We will fill in the "time_zone", "tz_offset", and "time_sent" * parts of the "entry" structure. Return TRUE on success, FALSE * on failure. */ if (parse_date_time(src, entry->time_zone,sizeof(entry->time_zone), &(entry->tz_offset), &(entry->time_sent))) { DPRINT(Debug,7,(&Debug, "parse_arpa_date SUCCESS for %s\n",src)); return TRUE; } DPRINT(Debug,7,(&Debug, "parse_arpa_date failed for %s\n",src)); return FALSE; } #ifdef _TEST int debug = 9999; main() { struct header_rec hdr; char buf[1024]; while (gets(buf) != NULL) { if (!parse_arpa_date(buf, &hdr)) fprintf(stderr, "FAIL %s\n", buf); else { fprintf(stderr, "OK %s\n", buf); fprintf(stderr, "time_zone=%s tz_offset=%d time_sent=%ld\n", hdr.time_zone, hdr.tz_offset, hdr.time_sent); } putc('\n', stderr); } exit(0); } #endif /* * Local Variables: * mode:c * c-basic-offset:4 * buffer-file-coding-system: iso-8859-1 * End: */