about summary refs log tree commit diff
path: root/parse.c
diff options
context:
space:
mode:
authorC. McEnroe <june@causal.agency>2021-04-11 17:10:47 -0400
committerC. McEnroe <june@causal.agency>2021-04-11 17:10:47 -0400
commit18e9dcbf8479242c16fe94dfca5da5dbb3b93a01 (patch)
tree3c4393288576a6cdb70d1a9da61c501da5dc9041 /parse.c
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.
Diffstat (limited to 'parse.c')
-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
 	);