about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2021-04-11 17:10:47 -0400
committerJune McEnroe <june@causal.agency>2021-04-11 17:10:47 -0400
commit18e9dcbf8479242c16fe94dfca5da5dbb3b93a01 (patch)
tree3c4393288576a6cdb70d1a9da61c501da5dc9041
parentRemove unnecessary capture group in URL regex (diff)
downloadbubger-18e9dcbf8479242c16fe94dfca5da5dbb3b93a01.tar.gz
bubger-18e9dcbf8479242c16fe94dfca5da5dbb3b93a01.zip
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.
-rw-r--r--parse.c42
1 files changed, 26 insertions, 16 deletions
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
 	);