Commit | Line | Data |
---|---|---|
d9898ee8 | 1 | /* |
b0322a85 | 2 | ** Copyright 1998 - 2011 Double Precision, Inc. |
d9898ee8 | 3 | ** See COPYING for distribution information. |
4 | */ | |
5 | ||
6 | /* | |
d9898ee8 | 7 | */ |
b0322a85 | 8 | #include "config.h" |
d9898ee8 | 9 | #include <stdio.h> |
10 | #include <string.h> | |
d9898ee8 | 11 | #include <time.h> |
12 | ||
b0322a85 CE |
13 | #define my_isalpha(c) ( ( (c) >= 'a' && (c) <= 'z' ) || \ |
14 | ( (c) >= 'A' && (c) <= 'Z' ) ) | |
15 | ||
16 | #define my_isdigit(c) ( (c) >= '0' && (c) <= '9' ) | |
17 | ||
18 | #define my_isalnum(c) ( my_isalpha(c) || my_isdigit(c) ) | |
19 | ||
20 | #define my_isspace(c) ( (c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n') | |
21 | ||
d9898ee8 | 22 | /* |
23 | ** time_t rfc822_parsedate(const char *p) | |
24 | ** | |
25 | ** p - contents of the Date: header, attempt to parse it into a time_t. | |
26 | ** | |
27 | ** returns - time_t, or 0 if the date cannot be parsed | |
28 | */ | |
29 | ||
30 | static unsigned parsedig(const char **p) | |
31 | { | |
b0322a85 | 32 | unsigned i=0; |
d9898ee8 | 33 | |
b0322a85 | 34 | while (my_isdigit(**p)) |
d9898ee8 | 35 | { |
36 | i=i*10 + **p - '0'; | |
37 | ++*p; | |
38 | } | |
39 | return (i); | |
40 | } | |
41 | ||
42 | static const char * const weekdays[7]={ | |
43 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" | |
44 | } ; | |
45 | ||
46 | static const char * const mnames[13]={ | |
47 | "Jan", "Feb", "Mar", "Apr", | |
48 | "May", "Jun", "Jul", "Aug", | |
49 | "Sep", "Oct", "Nov", "Dec", NULL}; | |
50 | ||
51 | #define leap(y) ( \ | |
52 | ((y) % 400) == 0 || \ | |
53 | (((y) % 4) == 0 && (y) % 100) ) | |
54 | ||
55 | static unsigned mlength[]={31,28,31,30,31,30,31,31,30,31,30,31}; | |
56 | #define mdays(m,y) ( (m) != 2 ? mlength[(m)-1] : leap(y) ? 29:28) | |
57 | ||
58 | static const char * const zonenames[] = { | |
59 | "UT","GMT", | |
60 | "EST","EDT", | |
61 | "CST","CDT", | |
62 | "MST","MDT", | |
63 | "PST","PDT", | |
64 | "Z", | |
d50284c4 | 65 | "A", "B", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M", |
d9898ee8 | 66 | "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", |
67 | NULL}; | |
68 | ||
69 | #define ZH(n) ( (n) * 60 * 60 ) | |
70 | ||
71 | static int zoneoffset[] = { | |
72 | 0, 0, | |
73 | ZH(-5), ZH(-4), | |
74 | ZH(-6), ZH(-5), | |
75 | ZH(-7), ZH(-6), | |
76 | ZH(-8), ZH(-7), | |
77 | 0, | |
78 | ||
79 | ZH(-1), ZH(-2), ZH(-3), ZH(-4), ZH(-5), ZH(-6), ZH(-7), ZH(-8), ZH(-9), ZH(-10), ZH(-11), ZH(-12), | |
80 | ZH(1), ZH(2), ZH(3), ZH(4), ZH(5), ZH(6), ZH(7), ZH(8), ZH(9), ZH(10), ZH(11), ZH(12) }; | |
81 | ||
b0322a85 CE |
82 | #define lc(x) ((x) >= 'A' && (x) <= 'Z' ? (x) + ('a'-'A'):(x)) |
83 | ||
d9898ee8 | 84 | static unsigned parsekey(const char **mon, const char * const *ary) |
85 | { | |
86 | unsigned m, j; | |
87 | ||
88 | for (m=0; ary[m]; m++) | |
89 | { | |
90 | for (j=0; ary[m][j]; j++) | |
b0322a85 | 91 | if (lc(ary[m][j]) != lc((*mon)[j])) |
d9898ee8 | 92 | break; |
93 | if (!ary[m][j]) | |
94 | { | |
95 | *mon += j; | |
96 | return (m+1); | |
97 | } | |
98 | } | |
99 | return (0); | |
100 | } | |
101 | ||
102 | static int parsetime(const char **t) | |
103 | { | |
b0322a85 CE |
104 | unsigned h,m,s=0; |
105 | ||
106 | if (!my_isdigit(**t)) return (-1); | |
d9898ee8 | 107 | |
d9898ee8 | 108 | h=parsedig(t); |
109 | if (h > 23) return (-1); | |
110 | if (**t != ':') return (-1); | |
111 | ++*t; | |
b0322a85 | 112 | if (!my_isdigit(**t)) return (-1); |
d9898ee8 | 113 | m=parsedig(t); |
114 | if (**t == ':') | |
115 | { | |
116 | ++*t; | |
b0322a85 CE |
117 | |
118 | if (!my_isdigit(**t)) return (-1); | |
d9898ee8 | 119 | s=parsedig(t); |
120 | } | |
121 | if (m > 59 || s > 59) return (-1); | |
122 | return (h * 60 * 60 + m * 60 + s); | |
123 | } | |
124 | ||
d50284c4 | 125 | int rfc822_parsedate_chk(const char *rfcdt, time_t *tret) |
d9898ee8 | 126 | { |
d50284c4 CE |
127 | unsigned day=0, mon=0, year; |
128 | int secs; | |
129 | int offset; | |
130 | time_t t; | |
131 | unsigned y; | |
132 | ||
133 | *tret=0; | |
d9898ee8 | 134 | |
135 | /* Ignore day of the week. Tolerate "Tue, 25 Feb 1997 ... " | |
136 | ** without the comma. Tolerate "Feb 25 1997 ...". | |
137 | */ | |
138 | ||
139 | while (!day || !mon) | |
140 | { | |
d50284c4 | 141 | if (!*rfcdt) return (-1); |
b0322a85 | 142 | if (my_isalpha(*rfcdt)) |
d9898ee8 | 143 | { |
d50284c4 | 144 | if (mon) return (-1); |
d9898ee8 | 145 | mon=parsekey(&rfcdt, mnames); |
146 | if (!mon) | |
b0322a85 | 147 | while (*rfcdt && my_isalpha(*rfcdt)) |
d9898ee8 | 148 | ++rfcdt; |
149 | continue; | |
150 | } | |
151 | ||
b0322a85 | 152 | if (my_isdigit(*rfcdt)) |
d9898ee8 | 153 | { |
d50284c4 | 154 | if (day) return (-1); |
d9898ee8 | 155 | day=parsedig(&rfcdt); |
d50284c4 | 156 | if (!day) return (-1); |
d9898ee8 | 157 | continue; |
158 | } | |
159 | ++rfcdt; | |
160 | } | |
161 | ||
b0322a85 | 162 | while (*rfcdt && my_isspace(*rfcdt)) |
d9898ee8 | 163 | ++rfcdt; |
d50284c4 | 164 | if (!my_isdigit(*rfcdt)) return (-1); |
d9898ee8 | 165 | year=parsedig(&rfcdt); |
166 | if (year < 70) year += 2000; | |
167 | if (year < 100) year += 1900; | |
168 | ||
b0322a85 | 169 | while (*rfcdt && my_isspace(*rfcdt)) |
d9898ee8 | 170 | ++rfcdt; |
171 | ||
172 | if (day == 0 || mon == 0 || mon > 12 || day > mdays(mon,year)) | |
d50284c4 | 173 | return (-1); |
d9898ee8 | 174 | |
175 | secs=parsetime(&rfcdt); | |
d50284c4 | 176 | if (secs < 0) return (-1); |
d9898ee8 | 177 | |
178 | offset=0; | |
179 | ||
180 | /* RFC822 sez no parenthesis, but I've seen (EST) */ | |
181 | ||
182 | while ( *rfcdt ) | |
183 | { | |
b0322a85 | 184 | if (my_isalnum(*rfcdt) || *rfcdt == '+' || *rfcdt == '-') |
d9898ee8 | 185 | break; |
186 | ++rfcdt; | |
187 | } | |
188 | ||
b0322a85 | 189 | if (my_isalpha((int)(unsigned char)*rfcdt)) |
d9898ee8 | 190 | { |
191 | int n=parsekey(&rfcdt, zonenames); | |
192 | ||
193 | if (n > 0) offset= zoneoffset[n-1]; | |
194 | } | |
195 | else | |
196 | { | |
197 | int sign=1; | |
198 | unsigned n; | |
199 | ||
200 | switch (*rfcdt) { | |
201 | case '-': | |
202 | sign= -1; | |
203 | case '+': | |
204 | ++rfcdt; | |
205 | } | |
206 | ||
b0322a85 | 207 | if (my_isdigit(*rfcdt)) |
d9898ee8 | 208 | { |
209 | n=parsedig(&rfcdt); | |
210 | if (n > 2359 || (n % 100) > 59) n=0; | |
211 | offset = sign * ( (n % 100) * 60 + n / 100 * 60 * 60); | |
212 | } | |
213 | } | |
214 | ||
d50284c4 CE |
215 | if (year < 1970) return (-1); |
216 | if (year > 9999) return (-1); | |
d9898ee8 | 217 | |
218 | t=0; | |
219 | for (y=1970; y<year; y++) | |
220 | { | |
221 | if ( leap(y) ) | |
222 | { | |
223 | if (year-y >= 4) | |
224 | { | |
225 | y += 3; | |
226 | t += ( 365*3+366 ) * 24 * 60 * 60; | |
227 | continue; | |
228 | } | |
229 | t += 24 * 60 * 60; | |
230 | } | |
231 | t += 365 * 24 * 60 * 60; | |
232 | } | |
233 | ||
234 | for (y=1; y < mon; y++) | |
235 | t += mdays(y, year) * 24 * 60 * 60; | |
236 | ||
d50284c4 CE |
237 | *tret = ( t + (day-1) * 24 * 60 * 60 + secs - offset ); |
238 | return 0; | |
d9898ee8 | 239 | } |
240 | ||
241 | const char *rfc822_mkdt(time_t t) | |
242 | { | |
243 | static char buf[80]; | |
244 | struct tm *tmptr=gmtime(&t); | |
245 | ||
246 | buf[0]=0; | |
247 | if (tmptr) | |
248 | { | |
249 | sprintf(buf, "%s, %02d %s %04d %02d:%02d:%02d GMT", | |
250 | weekdays[tmptr->tm_wday], | |
251 | tmptr->tm_mday, | |
252 | mnames[tmptr->tm_mon], | |
253 | tmptr->tm_year + 1900, | |
254 | tmptr->tm_hour, | |
255 | tmptr->tm_min, | |
256 | tmptr->tm_sec); | |
257 | } | |
258 | return (buf); | |
259 | } |