Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <bio.h>
4
#include <auth.h>
5
#include "imap4d.h"
6
 
7
char *
8
wdayname[7] =
9
{
10
	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
11
};
12
 
13
char *
14
monname[12] =
15
{
16
	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
17
};
18
 
19
static void	time2tm(Tm *tm, char *s);
20
static void	zone2tm(Tm *tm, char *s);
21
static int	dateindex(char *d, char **tab, int n);
22
 
23
int
24
rfc822date(char *s, int n, Tm *tm)
25
{
26
	char *plus;
27
	int m;
28
 
29
	plus = "+";
30
	if(tm->tzoff < 0)
31
		plus = "";
32
	m = 0;
33
	if(0 <= tm->wday && tm->wday < 7){
34
		m = snprint(s, n, "%s, ", wdayname[tm->wday]);
35
		if(m < 0)
36
			return m;
37
	}
38
	return snprint(s+m, n-m, "%.2d %s %.4d %.2d:%.2d:%.2d %s%.4d",
39
		tm->mday, monname[tm->mon], tm->year+1900, tm->hour, tm->min, tm->sec,
40
		plus, (tm->tzoff/3600)*100 + (tm->tzoff/60)%60);
41
}
42
 
43
int
44
imap4date(char *s, int n, Tm *tm)
45
{
46
	char *plus;
47
 
48
	plus = "+";
49
	if(tm->tzoff < 0)
50
		plus = "";
51
	return snprint(s, n, "%2d-%s-%.4d %2.2d:%2.2d:%2.2d %s%4.4d",
52
		tm->mday, monname[tm->mon], tm->year+1900, tm->hour, tm->min, tm->sec, plus, (tm->tzoff/3600)*100 + (tm->tzoff/60)%60);
53
}
54
 
55
int
56
imap4Date(Tm *tm, char *date)
57
{
58
	char *flds[4];
59
 
60
	if(getfields(date, flds, 3, 0, "-") != 3)
61
		return 0;
62
 
63
	tm->mday = strtol(flds[0], nil, 10);
64
	tm->mon = dateindex(flds[1], monname, 12);
65
	tm->year = strtol(flds[2], nil, 10) - 1900;
66
	return 1;
67
}
68
 
69
/*
70
 * parse imap4 dates
71
 */
72
ulong
73
imap4DateTime(char *date)
74
{
75
	Tm tm;
76
	char *flds[4], *sflds[4];
77
	ulong t;
78
 
79
	if(getfields(date, flds, 4, 0, " ") != 3)
80
		return ~0;
81
 
82
	if(!imap4Date(&tm, flds[0]))
83
		return ~0;
84
 
85
	if(getfields(flds[1], sflds, 3, 0, ":") != 3)
86
		return ~0;
87
 
88
	tm.hour = strtol(sflds[0], nil, 10);
89
	tm.min = strtol(sflds[1], nil, 10);
90
	tm.sec = strtol(sflds[2], nil, 10);
91
 
92
	strcpy(tm.zone, "GMT");
93
	tm.yday = 0;
94
	t = tm2sec(&tm);
95
	zone2tm(&tm, flds[2]);
96
	t -= tm.tzoff;
97
	return t;
98
}
99
 
100
/*
101
 * parse dates of formats
102
 * [Wkd[,]] DD Mon YYYY HH:MM:SS zone
103
 * [Wkd] Mon ( D|DD) HH:MM:SS zone YYYY
104
 * plus anything similar
105
 * return nil for a failure
106
 */
107
Tm*
108
date2tm(Tm *tm, char *date)
109
{
110
	Tm gmt, *atm;
111
	char *flds[7], *s, dstr[64];
112
	int n;
113
 
114
	/*
115
	 * default date is Thu Jan  1 00:00:00 GMT 1970
116
	 */
117
	tm->wday = 4;
118
	tm->mday = 1;
119
	tm->mon = 1;
120
	tm->hour = 0;
121
	tm->min = 0;
122
	tm->sec = 0;
123
	tm->year = 70;
124
	strcpy(tm->zone, "GMT");
125
	tm->tzoff = 0;
126
 
127
	strncpy(dstr, date, sizeof(dstr));
128
	dstr[sizeof(dstr)-1] = '\0';
129
	n = tokenize(dstr, flds, 7);
130
	if(n != 6 && n != 5)
131
		return nil;
132
 
133
	if(n == 5){
134
		for(n = 5; n >= 1; n--)
135
			flds[n] = flds[n - 1];
136
		n = 5;
137
	}else{
138
		/*
139
		 * Wday[,]
140
		 */
141
		s = strchr(flds[0], ',');
142
		if(s != nil)
143
			*s = '\0';
144
		tm->wday = dateindex(flds[0], wdayname, 7);
145
		if(tm->wday < 0)
146
			return nil;
147
	}
148
 
149
	/*
150
	 * check for the two major formats:
151
	 * Month first or day first
152
	 */
153
	tm->mon = dateindex(flds[1], monname, 12);
154
	if(tm->mon >= 0){
155
		tm->mday = strtoul(flds[2], nil, 10);
156
		time2tm(tm, flds[3]);
157
		zone2tm(tm, flds[4]);
158
		tm->year = strtoul(flds[5], nil, 10);
159
		if(strlen(flds[5]) > 2)
160
			tm->year -= 1900;
161
	}else{
162
		tm->mday = strtoul(flds[1], nil, 10);
163
		tm->mon = dateindex(flds[2], monname, 12);
164
		tm->year = strtoul(flds[3], nil, 10);
165
		if(strlen(flds[3]) > 2)
166
			tm->year -= 1900;
167
		time2tm(tm, flds[4]);
168
		zone2tm(tm, flds[5]);
169
	}
170
 
171
	if(n == 5){
172
		gmt = *tm;
173
		strncpy(gmt.zone, "", 4);
174
		gmt.tzoff = 0;
175
		atm = gmtime(tm2sec(&gmt));
176
		tm->wday = atm->wday;
177
	}else{
178
		/*
179
		 * Wday[,]
180
		 */
181
		s = strchr(flds[0], ',');
182
		if(s != nil)
183
			*s = '\0';
184
		tm->wday = dateindex(flds[0], wdayname, 7);
185
		if(tm->wday < 0)
186
			return nil;
187
	}
188
	return tm;
189
}
190
 
191
/*
192
 * zone	: [A-Za-z][A-Za-z][A-Za-z]	some time zone names
193
 *	| [A-IK-Z]			military time; rfc1123 says the rfc822 spec is wrong.
194
 *	| "UT"				universal time
195
 *	| [+-][0-9][0-9][0-9][0-9]
196
 * zones is the rfc-822 list of time zone names
197
 */
198
static NamedInt zones[] =
199
{
200
	{"A",	-1 * 3600},
201
	{"B",	-2 * 3600},
202
	{"C",	-3 * 3600},
203
	{"CDT", -5 * 3600},
204
	{"CST", -6 * 3600},
205
	{"D",	-4 * 3600},
206
	{"E",	-5 * 3600},
207
	{"EDT", -4 * 3600},
208
	{"EST", -5 * 3600},
209
	{"F",	-6 * 3600},
210
	{"G",	-7 * 3600},
211
	{"GMT", 0},
212
	{"H",	-8 * 3600},
213
	{"I",	-9 * 3600},
214
	{"K",	-10 * 3600},
215
	{"L",	-11 * 3600},
216
	{"M",	-12 * 3600},
217
	{"MDT", -6 * 3600},
218
	{"MST", -7 * 3600},
219
	{"N",	+1 * 3600},
220
	{"O",	+2 * 3600},
221
	{"P",	+3 * 3600},
222
	{"PDT", -7 * 3600},
223
	{"PST", -8 * 3600},
224
	{"Q",	+4 * 3600},
225
	{"R",	+5 * 3600},
226
	{"S",	+6 * 3600},
227
	{"T",	+7 * 3600},
228
	{"U",	+8 * 3600},
229
	{"UT",	0},
230
	{"V",	+9 * 3600},
231
	{"W",	+10 * 3600},
232
	{"X",	+11 * 3600},
233
	{"Y",	+12 * 3600},
234
	{"Z",	0},
235
	{nil,	0}
236
};
237
 
238
static void
239
zone2tm(Tm *tm, char *s)
240
{
241
	Tm aux, *atm;
242
	int i;
243
 
244
	if(*s == '+' || *s == '-'){
245
		i = strtol(s, &s, 10);
246
		tm->tzoff = (i / 100) * 3600 + i % 100;
247
		strncpy(tm->zone, "", 4);
248
		return;
249
	}
250
 
251
	/*
252
	 * look it up in the standard rfc822 table
253
	 */
254
	strncpy(tm->zone, s, 3);
255
	tm->zone[3] = '\0';
256
	tm->tzoff = 0;
257
	for(i = 0; zones[i].name != nil; i++){
258
		if(cistrcmp(zones[i].name, s) == 0){
259
			tm->tzoff = zones[i].v;
260
			return;
261
		}
262
	}
263
 
264
	/*
265
	 * one last try: look it up in the current local timezone
266
	 * probe a couple of times to get daylight/standard time change.
267
	 */
268
	aux = *tm;
269
	memset(aux.zone, 0, 4);
270
	aux.hour--;
271
	for(i = 0; i < 2; i++){
272
		atm = localtime(tm2sec(&aux));
273
		if(cistrcmp(tm->zone, atm->zone) == 0){
274
			tm->tzoff = atm->tzoff;
275
			return;
276
		}
277
		aux.hour++;
278
	}
279
 
280
	strncpy(tm->zone, "GMT", 4);
281
	tm->tzoff = 0;
282
}
283
 
284
/*
285
 * hh[:mm[:ss]]
286
 */
287
static void
288
time2tm(Tm *tm, char *s)
289
{
290
	tm->hour = strtoul(s, &s, 10);
291
	if(*s++ != ':')
292
		return;
293
	tm->min = strtoul(s, &s, 10);
294
	if(*s++ != ':')
295
		return;
296
	tm->sec = strtoul(s, &s, 10);
297
}
298
 
299
static int
300
dateindex(char *d, char **tab, int n)
301
{
302
	int i;
303
 
304
	for(i = 0; i < n; i++)
305
		if(cistrcmp(d, tab[i]) == 0)
306
			return i;
307
	return -1;
308
}