
static char rcsid[] = "@(#)$Id: parsarpdat.c,v 1.2 1995/09/29 17:41:24 wfp5p Exp $";

/*******************************************************************************
 *  The Elm Mail System  -  $Revision: 1.2 $   $State: Exp $
 *
 *                      Copyright (c) 1988-1995 USENET Community Trust
 *******************************************************************************
 * Bug reports, patches, comments, suggestions should be sent to:
 *
 *      Bill Pemberton, Elm Coordinator
 *      flash@virginia.edu
 *
 *******************************************************************************
 * $Log: parsarpdat.c,v $
 * Revision 1.2  1995/09/29  17:41:24  wfp5p
 * Alpha 8 (Chip's big changes)
 *
 * Revision 1.1.1.1  1995/04/19  20:38:33  wfp5p
 * Initial import of elm 2.4 PL0 as base for elm 2.5.
 *
 ******************************************************************************/


#include "elm_defs.h"


/*

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_arpa_date(datestr, entry)
const char *datestr;
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.
     */

    char field[STRING], save_tz[STRING], *str;
    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(datestr);

    /*
     * 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(7, (debugfile,
	    "parse_arpa_date parsing \"%s\" in time(1) format\n", str));

	/* <month> */
	if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
		!cvt_monthname_to_monthnum(field, &month))
	    goto failed;
	str += len;

	/* <day> */
	if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
		(day = atonum(field)) < 0)
	    goto failed;
	str += len;

	/* <hh:mm:ss> */
	if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
		!cvt_timestr_to_hhmmss(field, &hours, &mins, &secs))
	    goto failed;
	str += len;

	/* optional <tz> */
	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)) {
	    (void) strcat(save_tz, " ");
	    (void) strcat(save_tz, field);
	    tz += i;
	    str += len;
	}

	/* <year> */
	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(7, (debugfile,
	    "parse_arpa_date parsing \"%s\" in RFC-822 format\n", str));

	/* <day> */
	if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
		(day = atonum(field)) < 0)
	    goto failed;
	str += len;

	/* <month> */
	if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
		!cvt_monthname_to_monthnum(field, &month))
	    goto failed;
	str += len;

	/* <year> */
	if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
		!cvt_yearstr_to_yearnum(field, &year))
	    goto failed;
	str += len;

	/* <hh:mm:ss> */
	if ((len = get_word(str, 0, field, sizeof(field))) < 0 ||
		!cvt_timestr_to_hhmmss(field, &hours, &mins, &secs))
	    goto failed;
	str += len;

	/* <tz> - 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)) {
	    (void) strcat(save_tz, " ");
	    (void) strcat(save_tz, field);
	    tz += i;
	    str += len;
	}

	/* there might be more...but we ignore it */

    }

    strfcpy(entry->time_zone, save_tz+1, sizeof(entry->time_zone));
    entry->tz_offset = tz*60;
    entry->time_sent = make_gmttime(year, month, day, hours, mins-tz, secs);

    dprint(7, (debugfile, "  year=%d month=%d day=%d\n", year, month, day));
    dprint(7, (debugfile, "  hours=%d mins=%d secs=%d tz=%d\n",
	hours, mins, secs, tz));
    dprint(7, (debugfile, "  return success\n"));
    return TRUE;

failed:
    dprint(4, (debugfile, "parse_arpa_date failed at \"%s\"\n",
	(len <= 0 ? "<premature eol>" : field)));
    return FALSE;
}

#ifdef _TEST
int debug = 9999;
FILE *debugfile = stderr;
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

