Commit 9b414014 9b414014de10e4c543030b072a79d2de26fd239b by Sam Roberts

Moved some generically useful date/time handling functions to mutil.c,

fixed problems with portability of timezone information in struct tm, and
moved created a new structure to hold timezone information, since struct
tm doesn't do so reliably.
1 parent bd9d296b
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #ifndef _MAILUTILS_MUTIL_H
19 #define _MAILUTILS_MUTIL_H
20
21 /*
22 Collection of useful utility routines that are worth sharing,
23 but don't have a natural home somewhere else.
24 */
25
26 #include <time.h>
27
28 #ifndef __P
29 # ifdef __STDC__
30 # define __P(args) args
31 # else
32 # define __P(args) ()
33 # endif
34 #endif /*__P */
35
36 #ifdef __cplusplus
37 extern "C" {
38 #endif
39
40 struct mu_timezone
41 {
42 int utc_offset;
43 /* Seconds east of UTC. */
44
45 const char *tz_name;
46 /* Nickname for this timezone, if known. It is always considered
47 * to be a pointer to static string, so will never be freed. */
48 };
49
50 typedef struct mu_timezone mu_timezone;
51
52 extern int mu_parse_imap_date_time __P ((const char **p, struct tm * tm,
53 mu_timezone * tz));
54 extern int mu_parse_ctime_date_time __P ((const char **p, struct tm * tm,
55 mu_timezone * tz));
56
57 extern time_t mu_utc_offset __P ((void));
58 extern time_t mu_tm2time __P ((struct tm * timeptr, mu_timezone * tz));
59
60 #ifdef __cplusplus
61 }
62 #endif
63
64 #endif /* _MAILUTILS_MUTIL_H */
65
...@@ -44,7 +44,7 @@ memory_stream.c \ ...@@ -44,7 +44,7 @@ memory_stream.c \
44 mime.c \ 44 mime.c \
45 misc.c \ 45 misc.c \
46 monitor.c \ 46 monitor.c \
47 mu_mktime.c \ 47 mutil.c \
48 muerror.c \ 48 muerror.c \
49 observer.c \ 49 observer.c \
50 parse822.c \ 50 parse822.c \
......
...@@ -30,12 +30,11 @@ ...@@ -30,12 +30,11 @@
30 30
31 #include <mailutils/address.h> 31 #include <mailutils/address.h>
32 #include <mailutils/error.h> 32 #include <mailutils/error.h>
33 #include <mailutils/mutil.h>
33 #include <mailbox0.h> 34 #include <mailbox0.h>
34 #include <registrar0.h> 35 #include <registrar0.h>
35 #include <imap0.h> 36 #include <imap0.h>
36 37
37 extern time_t mu_mktime __P((struct tm *timeptr, int tz));
38
39 /* Functions to overload the mailbox_t API. */ 38 /* Functions to overload the mailbox_t API. */
40 static void mailbox_imap_destroy __P ((mailbox_t)); 39 static void mailbox_imap_destroy __P ((mailbox_t));
41 static int mailbox_imap_open __P ((mailbox_t, int)); 40 static int mailbox_imap_open __P ((mailbox_t, int));
...@@ -91,13 +90,6 @@ static int imap_get_message0 __P ((msg_imap_t, message_t *)); ...@@ -91,13 +90,6 @@ static int imap_get_message0 __P ((msg_imap_t, message_t *));
91 static int message_operation __P ((f_imap_t, msg_imap_t, char *, size_t, size_t *)); 90 static int message_operation __P ((f_imap_t, msg_imap_t, char *, size_t, size_t *));
92 static void free_subparts __P ((msg_imap_t)); 91 static void free_subparts __P ((msg_imap_t));
93 92
94 static const char *MONTHS[] =
95 {
96 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
97 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
98 };
99
100
101 /* Initialize the concrete object mailbox_t by overloading the function of the 93 /* Initialize the concrete object mailbox_t by overloading the function of the
102 structure. */ 94 structure. */
103 int 95 int
...@@ -1232,67 +1224,6 @@ imap_envelope_sender (envelope_t envelope, char *buffer, size_t buflen, ...@@ -1232,67 +1224,6 @@ imap_envelope_sender (envelope_t envelope, char *buffer, size_t buflen,
1232 return status; 1224 return status;
1233 } 1225 }
1234 1226
1235 int
1236 imap_parse_date_time (const char **p, struct tm *tm, int *tz)
1237 {
1238 int year, mon, day, hour, min, sec;
1239 char zone[6] = "+0000"; /* ( "+" / "-" ) hhmm */
1240 char month[5] = "";
1241 int hh = 0;
1242 int mm = 0;
1243 int sign = 1;
1244 int scanned = 0, scanned3;
1245 int i;
1246
1247 day = mon = year = hour = min = sec = 0;
1248
1249 memset (tm, 0, sizeof (*tm));
1250
1251 switch (sscanf (*p,
1252 "%2d-%3s-%4d%n %2d:%2d:%2d %5s%n",
1253 &day, month, &year, &scanned3, &hour, &min, &sec, zone,
1254 &scanned))
1255 {
1256 case 3:
1257 scanned = scanned3;
1258 break;
1259 case 7:
1260 break;
1261 default:
1262 return -1;
1263 }
1264
1265 tm->tm_sec = sec;
1266 tm->tm_min = min;
1267 tm->tm_hour = hour;
1268 tm->tm_mday = day;
1269
1270 for (i = 0; i < 12; i++)
1271 {
1272 if (strncasecmp (month, MONTHS[i], 3) == 0)
1273 {
1274 mon = i;
1275 break;
1276 }
1277 }
1278 tm->tm_mon = mon;
1279 tm->tm_year = (year > 1900) ? year - 1900 : year;
1280 tm->tm_yday = 0; /* unknown. */
1281 tm->tm_wday = 0; /* unknown. */
1282 tm->tm_isdst = -1; /* unknown. */
1283
1284 hh = (zone[1] - '0') * 10 + (zone[2] - '0');
1285 mm = (zone[3] - '0') * 10 + (zone[4] - '0');
1286 sign = (zone[0] == '-') ? -1 : +1;
1287
1288 if (tz)
1289 *tz = sign * (hh * 60 * 60 + mm * 60);
1290
1291 *p += scanned;
1292
1293 return 0;
1294 }
1295
1296 static int 1227 static int
1297 imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen, 1228 imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen,
1298 size_t *plen) 1229 size_t *plen)
...@@ -1302,7 +1233,7 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen, ...@@ -1302,7 +1233,7 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen,
1302 m_imap_t m_imap = msg_imap->m_imap; 1233 m_imap_t m_imap = msg_imap->m_imap;
1303 f_imap_t f_imap = m_imap->f_imap; 1234 f_imap_t f_imap = m_imap->f_imap;
1304 struct tm tm; 1235 struct tm tm;
1305 int tz; 1236 mu_timezone tz;
1306 time_t now; 1237 time_t now;
1307 char datebuf[] = "mm-dd-yyyy hh:mm:ss +0000"; 1238 char datebuf[] = "mm-dd-yyyy hh:mm:ss +0000";
1308 const char* date = datebuf; 1239 const char* date = datebuf;
...@@ -1326,10 +1257,10 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen, ...@@ -1326,10 +1257,10 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen,
1326 if (status != 0) 1257 if (status != 0)
1327 return status; 1258 return status;
1328 1259
1329 if (imap_parse_date_time(datep, &tm, &tz) != 0) 1260 if (mu_parse_imap_date_time(datep, &tm, &tz) != 0)
1330 now = (time_t)-1; 1261 now = (time_t)-1;
1331 else 1262 else
1332 now = mu_mktime (&tm, tz); 1263 now = mu_tm2time (&tm, &tz);
1333 1264
1334 /* if the time was unparseable, or mktime() didn't like what we 1265 /* if the time was unparseable, or mktime() didn't like what we
1335 parsed, use the calendar time. */ 1266 parsed, use the calendar time. */
......
1 /* Copyright (C) 2001 Free Software Foundation, Inc.
2 A wrapper for mktime function allowing to specify the timezone.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
18
19 #if HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <stdio.h>
24 #ifdef HAVE_STRINGS_H
25 #include <strings.h>
26 #endif
27 #include <time.h>
28
29 #include <mailutils/mutil.h>
30 /* Convert struct tm into time_t, taking into account timezone offset.
31
32 mktime() always treats tm as if it was localtime, so convert it
33 to UTC, then adjust by the tm's real timezone, if it is known.
34 */
35 time_t
36 mu_tm2time (struct tm *timeptr, mu_timezone* tz)
37 {
38 int offset = tz ? tz->utc_offset : 0;
39
40 return mktime(timeptr) - mu_utc_offset() + offset;
41 }
42
43 /* Convert time 0 at UTC to our localtime, that tells us the offset
44 of our current timezone from UTC. */
45 time_t mu_utc_offset(void)
46 {
47 time_t t = 0;
48 struct tm* tm = gmtime(&t);
49
50 return mktime(tm);
51 }
52
53 static const char *months[] =
54 {
55 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
56 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL
57 };
58
59 static const char *wdays[] =
60 {
61 "Mon", "Teu", "Wed", "Thr", "Fri", "Sat", "Sun", NULL
62 };
63
64 int
65 mu_parse_imap_date_time (const char **p, struct tm *tm, mu_timezone *tz)
66 {
67 int year, mon, day, hour, min, sec;
68 char zone[6] = "+0000"; /* ( "+" / "-" ) hhmm */
69 char month[5] = "";
70 int hh = 0;
71 int mm = 0;
72 int sign = 1;
73 int scanned = 0, scanned3;
74 int i;
75 int tzoffset;
76
77 day = mon = year = hour = min = sec = 0;
78
79 memset (tm, 0, sizeof (*tm));
80
81 switch (sscanf (*p,
82 "%2d-%3s-%4d%n %2d:%2d:%2d %5s%n",
83 &day, month, &year, &scanned3, &hour, &min, &sec, zone,
84 &scanned))
85 {
86 case 3:
87 scanned = scanned3;
88 break;
89 case 7:
90 break;
91 default:
92 return -1;
93 }
94
95 tm->tm_sec = sec;
96 tm->tm_min = min;
97 tm->tm_hour = hour;
98 tm->tm_mday = day;
99
100 for (i = 0; i < 12; i++)
101 {
102 if (strncasecmp (month, months[i], 3) == 0)
103 {
104 mon = i;
105 break;
106 }
107 }
108 tm->tm_mon = mon;
109 tm->tm_year = (year > 1900) ? year - 1900 : year;
110 tm->tm_yday = 0; /* unknown. */
111 tm->tm_wday = 0; /* unknown. */
112 #if HAVE_TM_ISDST
113 tm->tm_isdst = -1; /* unknown. */
114 #endif
115
116 hh = (zone[1] - '0') * 10 + (zone[2] - '0');
117 mm = (zone[3] - '0') * 10 + (zone[4] - '0');
118 sign = (zone[0] == '-') ? -1 : +1;
119 tzoffset = sign * (hh * 60 * 60 + mm * 60);
120
121 #if HAVE_TM_GMTOFFSET
122 tm->tm_gmtoffset = tzoffset;
123 #endif
124
125 if (tz)
126 {
127 tz->utc_offset = tzoffset;
128 tz->tz_name = NULL;
129 }
130
131 *p += scanned;
132
133 return 0;
134 }
135
136 /* "ctime" format is: Thu Jul 01 15:58:27 1999, with no trailing \n. */
137 int
138 mu_parse_ctime_date_time (const char **p, struct tm *tm, mu_timezone * tz)
139 {
140 int wday = 0;
141 int year = 0;
142 int mon = 0;
143 int day = 0;
144 int hour = 0;
145 int min = 0;
146 int sec = 0;
147 int n = 0;
148 int i;
149 char weekday[5] = "";
150 char month[5] = "";
151
152 if (sscanf (*p, "%3s %3s %2d %2d:%2d:%2d %d%n\n",
153 weekday, month, &day, &hour, &min, &sec, &year, &n) != 7)
154 return -1;
155
156 *p += n;
157
158 for (i = 0; i < 7; i++)
159 {
160 if (strncasecmp (weekday, wdays[i], 3) == 0)
161 {
162 wday = i;
163 break;
164 }
165 }
166
167 for (i = 0; i < 12; i++)
168 {
169 if (strncasecmp (month, months[i], 3) == 0)
170 {
171 mon = i;
172 break;
173 }
174 }
175
176 if (tm)
177 {
178 memset (tm, 0, sizeof (struct tm));
179
180 tm->tm_sec = sec;
181 tm->tm_min = min;
182 tm->tm_hour = hour;
183 tm->tm_mday = day;
184 tm->tm_wday = wday;
185 tm->tm_mon = mon;
186 tm->tm_year = (year > 1900) ? year - 1900 : year;
187 #ifdef HAVE_TM_ISDST
188 tm->tm_isdst = -1; /* unknown. */
189 #endif
190 }
191
192 /* ctime has no timezone information, set tz to UTC if they ask. */
193 if (tz)
194 memset (tz, 0, sizeof (struct mu_timezone));
195
196 return 0;
197 }
198
199
...@@ -1431,7 +1431,7 @@ struct tm ...@@ -1431,7 +1431,7 @@ struct tm
1431 }; 1431 };
1432 #endif 1432 #endif
1433 1433
1434 int parse822_date_time(const char** p, const char* e, struct tm* tm) 1434 int parse822_date_time(const char** p, const char* e, struct tm* tm, struct mu_timezone* tz)
1435 { 1435 {
1436 /* date-time = [ day "," ] date time */ 1436 /* date-time = [ day "," ] date time */
1437 1437
...@@ -1448,7 +1448,7 @@ int parse822_date_time(const char** p, const char* e, struct tm* tm) ...@@ -1448,7 +1448,7 @@ int parse822_date_time(const char** p, const char* e, struct tm* tm)
1448 int min = 0; 1448 int min = 0;
1449 int sec = 0; 1449 int sec = 0;
1450 1450
1451 int tz = 0; 1451 int tzoffset = 0;
1452 const char* tzname = 0; 1452 const char* tzname = 0;
1453 1453
1454 if((rc = parse822_day(p, e, &wday))) { 1454 if((rc = parse822_day(p, e, &wday))) {
...@@ -1468,7 +1468,7 @@ int parse822_date_time(const char** p, const char* e, struct tm* tm) ...@@ -1468,7 +1468,7 @@ int parse822_date_time(const char** p, const char* e, struct tm* tm)
1468 *p = save; 1468 *p = save;
1469 return rc; 1469 return rc;
1470 } 1470 }
1471 if((rc = parse822_time(p, e, &hour, &min, &sec, &tz, &tzname))) { 1471 if((rc = parse822_time(p, e, &hour, &min, &sec, &tzoffset, &tzname))) {
1472 *p = save; 1472 *p = save;
1473 return rc; 1473 return rc;
1474 } 1474 }
...@@ -1486,9 +1486,21 @@ int parse822_date_time(const char** p, const char* e, struct tm* tm) ...@@ -1486,9 +1486,21 @@ int parse822_date_time(const char** p, const char* e, struct tm* tm)
1486 tm->tm_min = min; 1486 tm->tm_min = min;
1487 tm->tm_sec = sec; 1487 tm->tm_sec = sec;
1488 1488
1489 #ifdef HAVE_TM_ISDST
1489 tm->tm_isdst = -1; /* unknown whether it's dst or not */ 1490 tm->tm_isdst = -1; /* unknown whether it's dst or not */
1490 tm->tm_gmtoff = tz; 1491 #endif
1492 #ifdef HAVE_TM_GMTOFF
1493 tm->tm_gmtoff = tzoffset;
1494 #endif
1495 #ifdef HAVE_TM_ZONE
1491 tm->tm_zone = tzname; 1496 tm->tm_zone = tzname;
1497 #endif
1498 }
1499
1500 if(tz)
1501 {
1502 tz->utc_offset = tzoffset;
1503 tz->tz_name = tzname;
1492 } 1504 }
1493 1505
1494 return EOK; 1506 return EOK;
......