From 18e9dcbf8479242c16fe94dfca5da5dbb3b93a01 Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Sun, 11 Apr 2021 17:10:47 -0400 Subject: Parse dates in a hopefully more portable fashion On GNU, struct tm doesn't have tm_gmtoff and %z or %Z in strptime do nothing. mktime(3) interprets the struct as local time, regardless of any tm_gmtoff, except on FreeBSD. Parse the zone portion of the date manually, subtract it from the struct tm fields, and call timegm(3). While here, correctly parse the optional seconds portion of the time. --- parse.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) (limited to 'parse.c') diff --git a/parse.c b/parse.c index b4f429e..da1ba47 100644 --- a/parse.c +++ b/parse.c @@ -67,6 +67,30 @@ static char *parseID(char *id) { return &id[1]; } +static time_t parseDate(const char *date) { + struct tm tm = {0}; + if (isalpha(*date)) { + date = strptime(date, "%a, ", &tm); + if (!date) goto err; + } + date = strptime(date, "%e %b %Y %H:%M", &tm); + if (!date) goto err; + if (*date == ':') { + date = strptime(date, ":%S", &tm); + if (!date) goto err; + } + while (isspace(*date)) date++; + if (*date == '+' || *date == '-') { + long zone = strtol(date, NULL, 10); + tm.tm_hour -= zone / 100; + tm.tm_min -= zone % 100; + } + return timegm(&tm); + +err: + errx(EX_PROTOCOL, "invalid envelope date format"); +} + void parseEnvelope(struct Envelope *envelope, struct List list) { enum { Date, Subject, From, Sender, ReplyTo, @@ -77,22 +101,8 @@ void parseEnvelope(struct Envelope *envelope, struct List list) { errx(EX_PROTOCOL, "missing envelope structure fields"); } - struct tm time; - const char *date = dataCheck(list.ptr[Date], String).string; - envelope->date = date; - if (isalpha(date[0])) { - date = strptime(date, "%a, %e %b %Y %H:%M:%S ", &time); - } else { - date = strptime(date, "%e %b %Y %H:%M:%S ", &time); - } - if (date && (date[0] == '+' || date[0] == '-')) { - date = strptime(date, "%z", &time); - } else if (date) { - date = strptime(date, "%Z", &time); - } - if (!date) errx(EX_PROTOCOL, "invalid envelope date format"); - envelope->time = mktime(&time); - + envelope->date = dataCheck(list.ptr[Date], String).string; + envelope->time = parseDate(envelope->date); envelope->subject = decodeHeader( dataCheck(list.ptr[Subject], String).string ); -- cgit 1.4.1