Commit 9b610735 9b610735d22a860127a43321864274e2d74c605a by Sergey Poznyakoff

see ChangeLog

1 parent 83f6a439
...@@ -79,7 +79,13 @@ imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen) ...@@ -79,7 +79,13 @@ imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen)
79 mailbox_name = strdup ((pw) ? pw->pw_name : ""); 79 mailbox_name = strdup ((pw) ? pw->pw_name : "");
80 } 80 }
81 else 81 else
82 mailbox_name = util_getfullpath (name, delim); 82 mailbox_name = namespace_getfullpath (name, delim);
83
84 if (!mailbox_name)
85 {
86 snprintf (resp, resplen, "NO Create failed.");
87 return RESP_NO;
88 }
83 89
84 /* If the destination mailbox does not exist, a server should return 90 /* If the destination mailbox does not exist, a server should return
85 an error. */ 91 an error. */
......
...@@ -52,7 +52,10 @@ imap4d_create (struct imap4d_command *command, char *arg) ...@@ -52,7 +52,10 @@ imap4d_create (struct imap4d_command *command, char *arg)
52 return util_finish (command, RESP_BAD, "Already exist"); 52 return util_finish (command, RESP_BAD, "Already exist");
53 53
54 /* Allocates memory. */ 54 /* Allocates memory. */
55 name = util_getfullpath (name, delim); 55 name = namespace_getfullpath (name, delim);
56
57 if (!name)
58 return util_finish (command, RESP_NO, "Can not create mailbox");
56 59
57 /* It will fail if the mailbox already exists. */ 60 /* It will fail if the mailbox already exists. */
58 if (access (name, F_OK) != 0) 61 if (access (name, F_OK) != 0)
......
...@@ -44,7 +44,9 @@ imap4d_delete (struct imap4d_command *command, char *arg) ...@@ -44,7 +44,9 @@ imap4d_delete (struct imap4d_command *command, char *arg)
44 return util_finish (command, RESP_NO, "Already exist"); 44 return util_finish (command, RESP_NO, "Already exist");
45 45
46 /* Allocates memory. */ 46 /* Allocates memory. */
47 name = util_getfullpath (name, delim); 47 name = namespace_getfullpath (name, delim);
48 if (!name)
49 return util_finish (command, RESP_NO, "Can not remove");
48 50
49 if (remove (name) != 0) 51 if (remove (name) != 0)
50 { 52 {
......
...@@ -32,12 +32,14 @@ static struct option long_options[] = ...@@ -32,12 +32,14 @@ static struct option long_options[] =
32 {"help", no_argument, 0, 'h'}, 32 {"help", no_argument, 0, 'h'},
33 {"inetd", no_argument, 0, 'i'}, 33 {"inetd", no_argument, 0, 'i'},
34 {"port", required_argument, 0, 'p'}, 34 {"port", required_argument, 0, 'p'},
35 {"other-namespace", required_argument, 0, 'O'},
36 {"shared-namespace", required_argument, 0, 'S'},
35 {"timeout", required_argument, 0, 't'}, 37 {"timeout", required_argument, 0, 't'},
36 {"version", no_argument, 0, 'v'}, 38 {"version", no_argument, 0, 'v'},
37 {0, 0, 0, 0} 39 {0, 0, 0, 0}
38 }; 40 };
39 41
40 const char *short_options ="d::hip:t:v"; 42 const char *short_options ="d::hip:t:vO:P:S:";
41 43
42 static int syslog_error_printer __P ((const char *fmt, va_list ap)); 44 static int syslog_error_printer __P ((const char *fmt, va_list ap));
43 static int imap4d_mainloop __P ((int, int)); 45 static int imap4d_mainloop __P ((int, int));
...@@ -90,6 +92,14 @@ main (int argc, char **argv) ...@@ -90,6 +92,14 @@ main (int argc, char **argv)
90 port = strtoul (optarg, NULL, 10); 92 port = strtoul (optarg, NULL, 10);
91 break; 93 break;
92 94
95 case 'O':
96 set_namespace (NS_OTHER, optarg);
97 break;
98
99 case 'S':
100 set_namespace (NS_SHARED, optarg);
101 break;
102
93 case 't': 103 case 't':
94 timeout = strtoul (optarg, NULL, 10); 104 timeout = strtoul (optarg, NULL, 10);
95 break; 105 break;
......
...@@ -132,11 +132,18 @@ struct imap4d_command ...@@ -132,11 +132,18 @@ struct imap4d_command
132 #define ERR_TIMEOUT 3 132 #define ERR_TIMEOUT 3
133 #define ERR_SIGNAL 4 133 #define ERR_SIGNAL 4
134 134
135 /* Namespace numbers */
136 #define NS_PRIVATE 0
137 #define NS_OTHER 1
138 #define NS_SHARED 2
139 #define NS_MAX 3
140
135 extern struct imap4d_command imap4d_command_table[]; 141 extern struct imap4d_command imap4d_command_table[];
136 extern FILE *ofile; 142 extern FILE *ofile;
137 extern unsigned int timeout; 143 extern unsigned int timeout;
138 extern mailbox_t mbox; 144 extern mailbox_t mbox;
139 extern char *homedir; 145 extern char *homedir;
146 extern char *rootdir;
140 extern int state; 147 extern int state;
141 extern volatile size_t children; 148 extern volatile size_t children;
142 149
...@@ -169,7 +176,8 @@ extern int imap4d_store0 __P ((char *, int, char *, size_t)); ...@@ -169,7 +176,8 @@ extern int imap4d_store0 __P ((char *, int, char *, size_t));
169 extern int imap4d_subscribe __P ((struct imap4d_command *, char *)); 176 extern int imap4d_subscribe __P ((struct imap4d_command *, char *));
170 extern int imap4d_uid __P ((struct imap4d_command *, char *)); 177 extern int imap4d_uid __P ((struct imap4d_command *, char *));
171 extern int imap4d_unsubscribe __P ((struct imap4d_command *, char *)); 178 extern int imap4d_unsubscribe __P ((struct imap4d_command *, char *));
172 179 extern int imap4d_namespace __P ((struct imap4d_command *, char *));
180
173 /* Synchronisation on simultenous access. */ 181 /* Synchronisation on simultenous access. */
174 extern int imap4d_sync __P ((void)); 182 extern int imap4d_sync __P ((void));
175 extern int imap4d_sync_flags __P ((size_t)); 183 extern int imap4d_sync_flags __P ((size_t));
......
...@@ -141,13 +141,19 @@ imap4d_list (struct imap4d_command *command, char *arg) ...@@ -141,13 +141,19 @@ imap4d_list (struct imap4d_command *command, char *arg)
141 } 141 }
142 142
143 /* Allocates. */ 143 /* Allocates. */
144 cwd = util_getfullpath (ref, delim); 144 cwd = namespace_checkfullpath (ref, wcard, delim);
145 if (!cwd)
146 {
147 free (ref);
148 return util_finish (command, RESP_NO,
149 "The requested item could not be found.");
150 }
145 151
146 /* If wcard match inbox return it too, part of the list. */ 152 /* If wcard match inbox return it too, part of the list. */
147 if (!*ref && (match ("INBOX", wcard, delim) 153 if (!*ref && (match ("INBOX", wcard, delim)
148 || match ("inbox", wcard, delim))) 154 || match ("inbox", wcard, delim)))
149 util_out (RESP_NONE, "LIST (\\NoInferiors) NIL INBOX"); 155 util_out (RESP_NONE, "LIST (\\NoInferiors) NIL INBOX");
150 156
151 if (chdir (cwd) == 0) 157 if (chdir (cwd) == 0)
152 { 158 {
153 list_file (cwd, ref, (dir) ? dir : "", delim); 159 list_file (cwd, ref, (dir) ? dir : "", delim);
...@@ -156,6 +162,7 @@ imap4d_list (struct imap4d_command *command, char *arg) ...@@ -156,6 +162,7 @@ imap4d_list (struct imap4d_command *command, char *arg)
156 free (cwd); 162 free (cwd);
157 free (ref); 163 free (ref);
158 } 164 }
165
159 return util_finish (command, RESP_OK, "Completed"); 166 return util_finish (command, RESP_OK, "Completed");
160 } 167 }
161 168
......
...@@ -136,9 +136,10 @@ imap4d_login (struct imap4d_command *command, char *arg) ...@@ -136,9 +136,10 @@ imap4d_login (struct imap4d_command *command, char *arg)
136 if (pw->pw_uid > 1) 136 if (pw->pw_uid > 1)
137 setuid (pw->pw_uid); 137 setuid (pw->pw_uid);
138 138
139 homedir = strdup (pw->pw_dir); 139 homedir = util_normalize_path (strdup (pw->pw_dir), "/");
140 /* FIXME: Check for errors. */ 140 /* FIXME: Check for errors. */
141 chdir (homedir); 141 chdir (homedir);
142 namespace_init(pw->pw_dir);
142 syslog (LOG_INFO, "User '%s' logged in", username); 143 syslog (LOG_INFO, "User '%s' logged in", username);
143 return util_finish (command, RESP_OK, "Completed"); 144 return util_finish (command, RESP_OK, "Completed");
144 } 145 }
......
...@@ -26,5 +26,6 @@ imap4d_noop (struct imap4d_command *command, char *arg) ...@@ -26,5 +26,6 @@ imap4d_noop (struct imap4d_command *command, char *arg)
26 return util_finish (command, RESP_BAD, "Wrong state"); 26 return util_finish (command, RESP_BAD, "Wrong state");
27 if (util_getword (arg, &sp)) 27 if (util_getword (arg, &sp))
28 return util_finish (command, RESP_BAD, "Too many args"); 28 return util_finish (command, RESP_BAD, "Too many args");
29 imap4d_select_status();
29 return util_finish (command, RESP_OK, "Completed"); 30 return util_finish (command, RESP_OK, "Completed");
30 } 31 }
......
...@@ -50,7 +50,9 @@ imap4d_rename (struct imap4d_command *command, char *arg) ...@@ -50,7 +50,9 @@ imap4d_rename (struct imap4d_command *command, char *arg)
50 return util_finish (command, RESP_NO, "Name Inbox is reservered"); 50 return util_finish (command, RESP_NO, "Name Inbox is reservered");
51 51
52 /* Allocates memory. */ 52 /* Allocates memory. */
53 newname = util_getfullpath (newname, delim); 53 newname = namespace_getfullpath (newname, delim);
54 if (!newname)
55 return util_finish (command, RESP_NO, "Permission denied");
54 56
55 /* It is an error to attempt to rename from a mailbox name that already 57 /* It is an error to attempt to rename from a mailbox name that already
56 exist. */ 58 exist. */
...@@ -118,15 +120,16 @@ imap4d_rename (struct imap4d_command *command, char *arg) ...@@ -118,15 +120,16 @@ imap4d_rename (struct imap4d_command *command, char *arg)
118 return util_finish (command, RESP_OK, "Already exist"); 120 return util_finish (command, RESP_OK, "Already exist");
119 } 121 }
120 122
121 oldname = util_getfullpath (oldname, delim); 123 oldname = namespace_getfullpath (oldname, delim);
122 124
123 /* It must exist. */ 125 /* It must exist. */
124 if (rename (oldname, newname) != 0) 126 if (!oldname || rename (oldname, newname) != 0)
125 { 127 {
126 rc = RESP_NO; 128 rc = RESP_NO;
127 msg = "Failed"; 129 msg = "Failed";
128 } 130 }
129 free (oldname); 131 if (oldname)
132 free (oldname);
130 free (newname); 133 free (newname);
131 return util_finish (command, rc, msg); 134 return util_finish (command, rc, msg);
132 } 135 }
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
17 17
18 #include "imap4d.h" 18 #include "imap4d.h"
19 19
20 static int select_flags;
21
20 /* select ::= "SELECT" SPACE mailbox */ 22 /* select ::= "SELECT" SPACE mailbox */
21 23
22 int 24 int
...@@ -67,40 +69,19 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags) ...@@ -67,40 +69,19 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags)
67 mailbox_name = strdup ("/dev/null"); 69 mailbox_name = strdup ("/dev/null");
68 } 70 }
69 else 71 else
70 mailbox_name = util_getfullpath (mailbox_name, "/"); 72 mailbox_name = namespace_getfullpath (mailbox_name, "/");
73
74 if (!mailbox_name)
75 return util_finish (command, RESP_NO, "Couldn't open mailbox");
71 76
72 if (mailbox_create (&mbox, mailbox_name) == 0 77 if (mailbox_create (&mbox, mailbox_name) == 0
73 && mailbox_open (mbox, flags) == 0) 78 && mailbox_open (mbox, flags) == 0)
74 { 79 {
75 const char *mflags = "\\Answered \\Flagged \\Deleted \\Seen \\Draft";
76 const char *pflags = "\\Answered \\Deleted \\Seen";
77 unsigned long uidvalidity = 0;
78 size_t count = 0, recent = 0, unseen = 0, uidnext = 0;
79
80 free (mailbox_name); 80 free (mailbox_name);
81 81 select_flags = flags;
82 mailbox_uidvalidity (mbox, &uidvalidity);
83 mailbox_uidnext (mbox, &uidnext);
84 mailbox_messages_count (mbox, &count);
85 mailbox_messages_recent (mbox, &recent);
86 mailbox_message_unseen (mbox, &unseen);
87 util_out (RESP_NONE, "%d EXISTS", count);
88 util_out (RESP_NONE, "%d RECENT", recent);
89 util_out (RESP_OK, "[UIDVALIDITY (%d)] UID valididy status",
90 uidvalidity);
91 util_out (RESP_OK, "[UIDNEXT %d] Predicted next uid", uidnext);
92 if (unseen)
93 util_out (RESP_OK, "[UNSEEN (%d)] first unseen messsage ", unseen);
94 util_out (RESP_NONE, "FLAGS (%s)", mflags);
95 /* FIXME:
96 - '\*' can be supported if we use the attribute_set userflag()
97 - Answered is still not set in the mailbox code. */
98 if (flags == MU_STREAM_READ)
99 util_out (RESP_OK, "[PERMANENTFLAGS ()] No Permanent flags");
100 else
101 util_out (RESP_OK, "[PERMANENTFLAGS (%s)] Permanent flags", pflags);
102 /* Need to set the state explicitely for select. */
103 state = STATE_SEL; 82 state = STATE_SEL;
83 imap4d_select_status();
84 /* Need to set the state explicitely for select. */
104 return util_send ("%s OK [%s] %s Completed\r\n", command->tag, 85 return util_send ("%s OK [%s] %s Completed\r\n", command->tag,
105 (MU_STREAM_READ == flags) ? 86 (MU_STREAM_READ == flags) ?
106 "READ-ONLY" : "READ-WRITE", command->name); 87 "READ-ONLY" : "READ-WRITE", command->name);
...@@ -109,3 +90,37 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags) ...@@ -109,3 +90,37 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags)
109 free (mailbox_name); 90 free (mailbox_name);
110 return status; 91 return status;
111 } 92 }
93
94 /* The code is shared between select and noop */
95 void
96 imap4d_select_status()
97 {
98 const char *mflags = "\\Answered \\Flagged \\Deleted \\Seen \\Draft";
99 const char *pflags = "\\Answered \\Deleted \\Seen";
100 unsigned long uidvalidity = 0;
101 size_t count = 0, recent = 0, unseen = 0, uidnext = 0;
102
103 if (state != STATE_SEL)
104 return;
105
106 mailbox_uidvalidity (mbox, &uidvalidity);
107 mailbox_uidnext (mbox, &uidnext);
108 mailbox_messages_count (mbox, &count);
109 mailbox_messages_recent (mbox, &recent);
110 mailbox_message_unseen (mbox, &unseen);
111 util_out (RESP_NONE, "%d EXISTS", count);
112 util_out (RESP_NONE, "%d RECENT", recent);
113 util_out (RESP_OK, "[UIDVALIDITY (%d)] UID valididy status",
114 uidvalidity);
115 util_out (RESP_OK, "[UIDNEXT %d] Predicted next uid", uidnext);
116 if (unseen)
117 util_out (RESP_OK, "[UNSEEN (%d)] first unseen messsage ", unseen);
118 util_out (RESP_NONE, "FLAGS (%s)", mflags);
119 /* FIXME:
120 - '\*' can be supported if we use the attribute_set userflag()
121 - Answered is still not set in the mailbox code. */
122 if (select_flags & MU_STREAM_READ)
123 util_out (RESP_OK, "[PERMANENTFLAGS ()] No Permanent flags");
124 else
125 util_out (RESP_OK, "[PERMANENTFLAGS (%s)] Permanent flags", pflags);
126 }
......
...@@ -51,7 +51,10 @@ imap4d_status (struct imap4d_command *command, char *arg) ...@@ -51,7 +51,10 @@ imap4d_status (struct imap4d_command *command, char *arg)
51 mailbox_name = strdup ((pw) ? pw->pw_name : ""); 51 mailbox_name = strdup ((pw) ? pw->pw_name : "");
52 } 52 }
53 else 53 else
54 mailbox_name = util_getfullpath (name, delim); 54 mailbox_name = namespace_getfullpath (name, delim);
55
56 if (!mailbox_name)
57 return util_finish (command, RESP_NO, "Error opening mailbox");
55 58
56 status = mailbox_create_default (&smbox, mailbox_name); 59 status = mailbox_create_default (&smbox, mailbox_name);
57 if (status == 0) 60 if (status == 0)
......
...@@ -138,6 +138,7 @@ imap4d_store0 (char *arg, int isuid, char *resp, size_t resplen) ...@@ -138,6 +138,7 @@ imap4d_store0 (char *arg, int isuid, char *resp, size_t resplen)
138 } 138 }
139 attribute_set_flags (attr, type); 139 attribute_set_flags (attr, type);
140 } 140 }
141 attribute_set_flags (attr, MU_ATTRIBUTE_MODIFIED);
141 flags = realloc (flags, strlen (flags) + strlen (item) + 2); 142 flags = realloc (flags, strlen (flags) + strlen (item) + 2);
142 if (*flags) 143 if (*flags)
143 strcat (flags, " "); 144 strcat (flags, " ");
......
...@@ -152,6 +152,71 @@ util_tilde_expansion (const char *ref, const char *delim) ...@@ -152,6 +152,71 @@ util_tilde_expansion (const char *ref, const char *delim)
152 return p; 152 return p;
153 } 153 }
154 154
155 /* util_normalize_path: convert pathname containig relative paths specs (../)
156 into an equivalent absolute path. Strip trailing delimiter if present,
157 unless it is the only character left. E.g.:
158
159 /home/user/../smith --> /home/smith
160 /home/user/../.. --> /
161
162 FIXME: delim is superfluous. The function deals with unix filesystem
163 paths, so delim should be always "/" */
164 char *
165 util_normalize_path (char *path, const char *delim)
166 {
167 int len;
168 char *p;
169
170 if (!path)
171 return path;
172
173 len = strlen (path);
174
175 /* Empty string is returned as is */
176 if (len == 0)
177 return path;
178
179 /* delete trailing delimiter if any */
180 if (len && path[len-1] == delim[0])
181 path[len-1] = 0;
182
183 /* Eliminate any /../ */
184 for (p = strchr (path, '.'); p; p = strchr (p, '.'))
185 {
186 if (p > path && p[-1] == delim[0])
187 {
188 if (p[1] == '.' && (p[2] == 0 || p[2] == delim[0]))
189 /* found */
190 {
191 char *q, *s;
192
193 /* Find previous delimiter */
194 for (q = p-2; *q != delim[0] && q >= path; q--)
195 ;
196
197 if (q < path)
198 break;
199 /* Copy stuff */
200 s = p + 2;
201 p = q;
202 while (*q++ = *s++)
203 ;
204 continue;
205 }
206 }
207
208 p++;
209 }
210
211 if (path[0] == 0)
212 {
213 path[0] = delim[0];
214 path[1] = 0;
215 }
216
217 return path;
218 }
219
155 /* Get the absolute path. */ 220 /* Get the absolute path. */
156 /* NOTE: Path is allocated and must be free()d by the caller. */ 221 /* NOTE: Path is allocated and must be free()d by the caller. */
157 char * 222 char *
...@@ -165,7 +230,7 @@ util_getfullpath (char *name, const char *delim) ...@@ -165,7 +230,7 @@ util_getfullpath (char *name, const char *delim)
165 free (p); 230 free (p);
166 p = s; 231 p = s;
167 } 232 }
168 return p; 233 return util_normalize_path (p, delim);
169 } 234 }
170 235
171 /* Return in set an allocated array contain (n) numbers, for imap messsage set 236 /* Return in set an allocated array contain (n) numbers, for imap messsage set
...@@ -226,7 +291,7 @@ util_msgset (char *s, size_t **set, int *n, int isuid) ...@@ -226,7 +291,7 @@ util_msgset (char *s, size_t **set, int *n, int isuid)
226 { 291 {
227 long tmp = low; 292 long tmp = low;
228 tmp -= 2; 293 tmp -= 2;
229 if (tmp <= 0 || val == 0) 294 if (tmp < 0 || val == 0)
230 { 295 {
231 free (*set); 296 free (*set);
232 *n = 0; 297 *n = 0;
...@@ -245,7 +310,7 @@ util_msgset (char *s, size_t **set, int *n, int isuid) ...@@ -245,7 +310,7 @@ util_msgset (char *s, size_t **set, int *n, int isuid)
245 } 310 }
246 else 311 else
247 { 312 {
248 status = add2set(set, n, val); 313 status = add2set (set, n, val);
249 if (status != 0) 314 if (status != 0)
250 return status; 315 return status;
251 } 316 }
...@@ -397,7 +462,7 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...) ...@@ -397,7 +462,7 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...)
397 462
398 va_start (ap, format); 463 va_start (ap, format);
399 status = vfprintf (ofile, buf, ap); 464 status = vfprintf (ofile, buf, ap);
400 va_end(ap); 465 va_end (ap);
401 free (buf); 466 free (buf);
402 /* Reset the state. */ 467 /* Reset the state. */
403 new_state = (rc == RESP_OK) ? command->success : command->failure; 468 new_state = (rc == RESP_OK) ? command->success : command->failure;
...@@ -610,3 +675,189 @@ add2set (size_t **set, int *n, unsigned long val) ...@@ -610,3 +675,189 @@ add2set (size_t **set, int *n, unsigned long val)
610 (*n)++; 675 (*n)++;
611 return 0; 676 return 0;
612 } 677 }
678
679 static const char *months[] =
680 {
681 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
682 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
683 };
684
685 #define c2d(c) (c-'0')
686
687 int
688 util_parse_internal_date (char *date, time_t *timep)
689 {
690 struct tm tm;
691 char *save;
692 int n, i;
693 int year, day, hour, min, sec;
694 char mon[4];
695 char sign[2];
696 char tzs[6];
697 time_t time;
698
699 memset (&tm, 0, sizeof (tm));
700 n = sscanf (date, "%2d-%3s-%4d %2d:%2d:%2d %5s\n",
701 &day, mon, &year,
702 &hour, &min, &sec, &tzs);
703
704 switch (n)
705 {
706 case 3:
707 case 6:
708 case 7: break;
709 default: return 1;
710 }
711
712 tm.tm_mday = day;
713 for (i = 0; i < 11; i++)
714 if (strncmp (months[i], mon, 3) == 0)
715 break;
716 if (i == 12)
717 return 1;
718 tm.tm_mon = i;
719 tm.tm_year = (year < 1900) ? year : year - 1900;
720
721 if (n >= 6)
722 {
723 tm.tm_hour = hour;
724 tm.tm_min = min;
725 tm.tm_sec = sec;
726 }
727
728 tm.tm_isdst = -1; /* unknown. */
729
730 time = mktime (&tm);
731 if (time == (time_t) -1)
732 return 2;
733
734 if (n == 7)
735 {
736 int sign;
737 int tz;
738
739 if (strlen (tzs) != 5)
740 return 3;
741
742 for (i = 1; i <= 4; i++)
743 if (!isdigit (tzs[i]))
744 return 3;
745
746 tz = (c2d (tzs[1])*10 + c2d (tzs[2]))*60 +
747 c2d (tzs[3])*10 + c2d (tzs[4]);
748 if (tzs[0] == '-')
749 tz = -tz;
750 else if (tzs[0] != '+')
751 return 4;
752 time -= tz*60;
753 }
754 *timep = time;
755 return 0;
756 }
757
758 int
759 util_parse_header_date (char *date, time_t *timep)
760 {
761 struct tm tm;
762 char *save;
763 int n, i;
764 int year, day, hour, min, sec;
765 char wday[5];
766 char mon[4];
767 char sign[2];
768 char tzs[6];
769 time_t time;
770
771 memset (&tm, 0, sizeof (tm));
772 n = sscanf (date, "%3s, %2d %3s %4d %2d:%2d:%2d %5s",
773 wday, &day, mon, &year,
774 &hour, &min, &sec, &tzs);
775
776 if (n < 7)
777 return 1;
778
779 tm.tm_mday = day;
780 for (i = 0; i < 11; i++)
781 if (strncmp (months[i], mon, 3) == 0)
782 break;
783 if (i == 12)
784 return 1;
785 tm.tm_mon = i;
786 tm.tm_year = (year < 1900) ? year : year - 1900;
787
788 if (n >= 6)
789 {
790 tm.tm_hour = hour;
791 tm.tm_min = min;
792 tm.tm_sec = sec;
793 }
794
795 tm.tm_isdst = -1; /* unknown. */
796
797 time = mktime (&tm);
798 if (time == (time_t) -1)
799 return 2;
800
801 if (n == 8)
802 {
803 int sign;
804 int tz;
805
806 if (strlen (tzs) != 5)
807 return 3;
808
809 for (i = 1; i <= 4; i++)
810 if (!isdigit (tzs[i]))
811 return 3;
812
813 tz = (c2d (tzs[1])*10 + c2d (tzs[2]))*60 +
814 c2d (tzs[3])*10 + c2d (tzs[4]);
815 if (tzs[0] == '-')
816 tz = -tz;
817 else if (tzs[0] != '+')
818 return 4;
819 time -= tz*60;
820 }
821 *timep = time;
822 return 0;
823 }
824
825 int
826 util_parse_rfc822_date (char *date, time_t *timep)
827 {
828 int year, mon, day, hour, min, sec;
829 int offt;
830 int i;
831 struct tm tm;
832 char month[5];
833 char wday[5];
834
835 month[0] = '\0';
836 wday[0] = '\0';
837 day = mon = year = hour = min = sec = offt = 0;
838
839 /* RFC822 Date: format. */
840 if (sscanf (date, "%3s %3s %2d %2d:%2d:%2d %d\n", wday, month, &day,
841 &hour, &min, &sec, &year) != 7)
842 return 1;
843 tm.tm_sec = sec;
844 tm.tm_min = min;
845 tm.tm_hour = hour;
846 for (i = 0; i < 12; i++)
847 {
848 if (strncasecmp (month, months[i], 3) == 0)
849 {
850 mon = i;
851 break;
852 }
853 }
854 tm.tm_mday = day;
855 tm.tm_mon = mon;
856 tm.tm_year = (year > 1900) ? year - 1900 : year;
857 tm.tm_yday = 0; /* unknown. */
858 tm.tm_wday = 0; /* unknown. */
859 tm.tm_isdst = -1; /* unknown. */
860 /* What to do the timezone? */
861 *timep = mktime (&tm);
862 return 0;
863 }
......