summaryrefslogtreecommitdiff
path: root/usr.bin/mail
diff options
context:
space:
mode:
authorchristos <christos@NetBSD.org>2006-12-10 06:06:47 +0000
committerchristos <christos@NetBSD.org>2006-12-10 06:06:47 +0000
commiteea42e044a4ff988f6da7e8753cbf64405e5bf70 (patch)
tree662396453dd284a229b4023c90ad2dda7caf7243 /usr.bin/mail
parent098ea45eb4de7e59db94150c19ea96b923995166 (diff)
Fix timezone and date parsing. From Anon Ymous.
Diffstat (limited to 'usr.bin/mail')
-rw-r--r--usr.bin/mail/format.c89
1 files changed, 54 insertions, 35 deletions
diff --git a/usr.bin/mail/format.c b/usr.bin/mail/format.c
index 6887a8be95c..acdfaca7e4f 100644
--- a/usr.bin/mail/format.c
+++ b/usr.bin/mail/format.c
@@ -1,4 +1,4 @@
-/* $NetBSD: format.c,v 1.2 2006/11/28 18:45:32 christos Exp $ */
+/* $NetBSD: format.c,v 1.3 2006/12/10 06:06:47 christos Exp $ */
/*-
* Copyright (c) 2006 The NetBSD Foundation, Inc.
@@ -38,7 +38,7 @@
#include <sys/cdefs.h>
#ifndef __lint__
-__RCSID("$NetBSD: format.c,v 1.2 2006/11/28 18:45:32 christos Exp $");
+__RCSID("$NetBSD: format.c,v 1.3 2006/12/10 06:06:47 christos Exp $");
#endif /* not __lint__ */
#include <time.h>
@@ -475,6 +475,26 @@ my_strptime(const char *buf, const char *fmtstr, struct tm *tm)
return tail;
}
+static char *
+mk_gmtoff(struct tm *tm)
+{
+ char *gmtoff;
+ char sign;
+ int offset;
+ int hour;
+ int min;
+
+ offset = tm->tm_gmtoff / 60;
+ sign = offset < 0 ? '-' : '+';
+ if (offset < 0)
+ offset = -offset;
+ offset %= 24 * 60;
+ min = offset % 60;
+ hour = offset / 60;
+ (void)sasprintf(&gmtoff, "%c%02d%02d", sign, hour, min);
+ return gmtoff;
+}
+
/*
* Get the date and time info from the "Date:" line, parse it into a
* tm structure as much as possible.
@@ -485,26 +505,24 @@ my_strptime(const char *buf, const char *fmtstr, struct tm *tm)
PUBLIC const char *
dateof(struct tm *tm, struct message *mp, int use_hl_date)
{
+ static int tzinit = 0;
char *tail;
char *gmtoff;
const char *date;
(void)memset(tm, 0, sizeof(*tm));
+ tm->tm_isdst = -1;
+ /* Make sure the time zone info is initialized. */
+ if (!tzinit) {
+ tzinit = 1;
+ tzset();
+ }
if (mp == NULL) { /* use local time */
- char buf[6]; /* space for "+0000" */
- int hour;
- int min;
time_t now;
- tzset();
(void)time(&now);
(void)localtime_r(&now, tm);
- min = (tm->tm_gmtoff / 60) % 60;
- hour = tm->tm_gmtoff / 3600;
- if (hour > 12)
- hour = 24 - hour;
- (void)snprintf(buf, sizeof(buf), "%+03d%02d", hour, min);
- return savestr(buf);
+ return mk_gmtoff(tm);
}
gmtoff = NULL;
tail = NULL;
@@ -549,16 +567,14 @@ dateof(struct tm *tm, struct message *mp, int use_hl_date)
* Scan the gmtoff and use it to convert the time to a
* local time.
*
+ * Note: "-0000" means no valid zone info. See
+ * RFC 2822, sec 3.3.
+ *
* XXX - This is painful! Is there a better way?
*/
- if (sscanf(gmtoff, " %[+-]%2d%2d ", &sign, &hour, &min) == 3) {
+ if (strcmp(gmtoff, "-0000") != 0 &&
+ sscanf(gmtoff, " %[+-]%2d%2d ", &sign, &hour, &min) == 3) {
time_t otime;
- /*
- * This seems like a crazy way to convert the
- * sent times from the Date field to local
- * times.
- */
- tm->tm_isdst = -1;
if (sign == '-') {
tm->tm_hour += hour;
tm->tm_min += min;
@@ -567,11 +583,15 @@ dateof(struct tm *tm, struct message *mp, int use_hl_date)
tm->tm_hour -= hour;
tm->tm_min -= min;
}
+ tm->tm_isdst = -1;
if ((time_t)(otime = timegm(tm)) == -1)
warn("timegm: %s", date);
-
+
if(localtime_r(&otime, tm) == NULL)
warn("localtime: %s", date);
+
+ /* extract the new gmtoff string */
+ gmtoff = mk_gmtoff(tm);
}
else
tm->tm_gmtoff = 0;
@@ -597,23 +617,22 @@ dateof(struct tm *tm, struct message *mp, int use_hl_date)
date = headline;
(void)mail_readline(setinput(mp), headline, sizeof(headline));
parse(headline, &hl, pbuf);
- if (hl.l_date != NULL &&
- (tail = my_strptime(hl.l_date, " %a %b %d %T ", tm)) == NULL &&
- (tail = my_strptime(hl.l_date, " %a %b %d %R ", tm)) == NULL) {
- warnx("dateof: cannot determine date: %s", hl.l_date);
+ if (hl.l_date != NULL) {
+ if ((tail = my_strptime(hl.l_date, " %a %b %d %T ", tm)) == NULL &&
+ (tail = my_strptime(hl.l_date, " %a %b %d %R ", tm)) == NULL)
+ warnx("dateof: cannot determine date: %s", hl.l_date);
+ else {
+ tm->tm_isdst = -1;
+ if(mktime(tm) == -1)
+ warn("mktime: %s", date);
+
+ /* extract the gmtoff string */
+ gmtoff = mk_gmtoff(tm);
+ }
}
}
- /* tail will be NULL here if the mail file is empty, so don't
- * check it. */
-
- /*
- * XXX - how should we really handle the zone info? The
- * problem seems to be figuring out whether to set tm_isdst to
- * 1 or 0.
- */
-
- /* mark the zone and gmtoff info as invalid for strftime. */
- tm->tm_isdst = -1;
+ /* 'tail' will be NULL here if the mail file is empty, so
+ * don't check it with an assert(). */
return gmtoff;
}