* mailbox/imap4d/fetch.c : First draft implementation, very yucky.
* mailbox/imap4d/select.c : First draft implementation. * mailbox/imap4d/util.c : Add util_msgset() and util_send(). Reuse of util_getcommand() for subcommands.
Showing
4 changed files
with
620 additions
and
64 deletions
... | @@ -17,22 +17,412 @@ | ... | @@ -17,22 +17,412 @@ |
17 | 17 | ||
18 | #include "imap4d.h" | 18 | #include "imap4d.h" |
19 | 19 | ||
20 | /* | 20 | /* This will suck, too. |
21 | * This will suck, too | 21 | Alain: Yest it does. */ |
22 | */ | 22 | |
23 | /* Taken from RFC2060 | ||
24 | fetch ::= "FETCH" SPACE set SPACE ("ALL" / "FULL" / | ||
25 | "FAST" / fetch_att / "(" 1#fetch_att ")") | ||
26 | |||
27 | fetch_att ::= "ENVELOPE" / "FLAGS" / "INTERNALDATE" / | ||
28 | "RFC822" [".HEADER" / ".SIZE" / ".TEXT"] / | ||
29 | "BODY" ["STRUCTURE"] / "UID" / | ||
30 | "BODY" [".PEEK"] section | ||
31 | ["<" number "." nz_number ">"] | ||
32 | */ | ||
33 | |||
34 | static int fetch_all (struct imap4d_command *, char*); | ||
35 | static int fetch_full (struct imap4d_command *, char*); | ||
36 | static int fetch_fast (struct imap4d_command *, char*); | ||
37 | static int fetch_envelope (struct imap4d_command *, char*); | ||
38 | static int fetch_flags (struct imap4d_command *, char*); | ||
39 | static int fetch_internaldate (struct imap4d_command *, char*); | ||
40 | static int fetch_rfc822_header (struct imap4d_command *, char*); | ||
41 | static int fetch_rfc822_size (struct imap4d_command *, char*); | ||
42 | static int fetch_rfc822_text (struct imap4d_command *, char*); | ||
43 | static int fetch_rfc822 (struct imap4d_command *, char*); | ||
44 | static int fetch_bodystructure (struct imap4d_command *, char*); | ||
45 | static int fetch_body_peek (struct imap4d_command *, char*); | ||
46 | static int fetch_body (struct imap4d_command *, char*); | ||
47 | static int fetch_uid (struct imap4d_command *, char*); | ||
48 | |||
49 | struct imap4d_command fetch_command_table [] = | ||
50 | { | ||
51 | #define F_ALL 0 | ||
52 | {"ALL", fetch_all}, | ||
53 | #define F_FULL 1 | ||
54 | {"FULL", fetch_full}, | ||
55 | #define F_FAST 2 | ||
56 | {"FAST", fetch_fast}, | ||
57 | #define F_ENVELOPE 3 | ||
58 | {"ENVELOPE", fetch_envelope}, | ||
59 | #define F_FLAGS 4 | ||
60 | {"FLAGS", fetch_flags}, | ||
61 | #define F_INTERNALDATE 5 | ||
62 | {"INTERNALDATE", fetch_internaldate}, | ||
63 | #define F_RFC822_HEADER 6 | ||
64 | {"RFC822.HEADER", fetch_rfc822_header}, | ||
65 | #define F_RFC822_SIZE 7 | ||
66 | {"RFC822.SIZE", fetch_rfc822_size}, | ||
67 | #define F_RFC822_TEXT 8 | ||
68 | {"RFC822.TEXT", fetch_rfc822_text}, | ||
69 | #define F_RFC822 9 | ||
70 | {"RFC822", fetch_rfc822}, | ||
71 | #define F_BODYSTRUCTURE 10 | ||
72 | {"BODYSTRUCTURE", fetch_bodystructure}, | ||
73 | #define F_BODY_PEEK 12 | ||
74 | {"BODY.PEEK", fetch_body_peek}, | ||
75 | #define F_BODY 13 | ||
76 | {"BODY", fetch_body}, | ||
77 | #define F_UID 14 | ||
78 | {"UID", fetch_uid}, | ||
79 | { 0, 0}, | ||
80 | }; | ||
23 | 81 | ||
24 | int | 82 | int |
25 | imap4d_fetch (struct imap4d_command *command, char *arg) | 83 | imap4d_fetch (struct imap4d_command *command, char *arg) |
26 | { | 84 | { |
27 | char *sp = NULL; | 85 | char *sp = NULL; |
28 | char *message_set; | 86 | char *msgset; |
87 | int *set = NULL; | ||
29 | char *item; | 88 | char *item; |
89 | int i, n = 0; | ||
90 | int rc = RESP_OK; | ||
91 | int status; | ||
92 | const char *errmsg = "Completed"; | ||
93 | struct imap4d_command *fcmd; | ||
30 | 94 | ||
31 | message_set = util_getword (arg, &sp); | 95 | msgset = util_getword (arg, &sp); |
32 | item = util_getword (NULL, &sp); | 96 | if (!msgset) |
33 | if (!message_set || !item) | ||
34 | return util_finish (command, RESP_BAD, "Too few args"); | 97 | return util_finish (command, RESP_BAD, "Too few args"); |
35 | 98 | ||
36 | /* check for paren list */ | 99 | item = strchr (sp, '['); |
37 | return util_finish (command, RESP_NO, "Not supported"); | 100 | if (item) |
101 | { | ||
102 | char *s = alloca (item - sp + 1); | ||
103 | memcpy (s, sp, item - sp); | ||
104 | s[item - sp] = '\0'; | ||
105 | arg = item; | ||
106 | item = s; | ||
107 | } | ||
108 | else | ||
109 | arg = item = sp; | ||
110 | |||
111 | fcmd = util_getcommand (item, fetch_command_table); | ||
112 | if (!fcmd) | ||
113 | return util_finish (command, RESP_BAD, "Command unknown"); | ||
114 | |||
115 | status = util_msgset (msgset, &set, &n, 0); | ||
116 | if (status != 0) | ||
117 | return util_finish (command, RESP_BAD, "Bogus number set"); | ||
118 | |||
119 | /* We use the states to hold the msgno/uid, the success to say if we're | ||
120 | The first. */ | ||
121 | for (i = 0; i < n; i++) | ||
122 | { | ||
123 | fcmd->states = set[i]; | ||
124 | fcmd->tag = command->tag; | ||
125 | fcmd->success = 1; | ||
126 | status = fcmd->func (fcmd, sp); | ||
127 | if (status != 0) | ||
128 | { | ||
129 | rc = RESP_BAD; | ||
130 | errmsg = "Bogus attribute"; | ||
131 | break; | ||
132 | } | ||
133 | else | ||
134 | util_send (")\r\n"); | ||
135 | } | ||
136 | free (set); | ||
137 | return util_finish (command, rc, errmsg); | ||
138 | } | ||
139 | |||
140 | /* --------------- Fetch commands definition ----- */ | ||
141 | #define EPILOGUE(command) \ | ||
142 | do { \ | ||
143 | if (command->success) \ | ||
144 | util_send ("* FETCH %d (%s", command->states, command->name); \ | ||
145 | else \ | ||
146 | util_send (" %s", command->name); \ | ||
147 | } while (0) | ||
148 | |||
149 | static int | ||
150 | fetch_all (struct imap4d_command *command, char *arg) | ||
151 | { | ||
152 | struct imap4d_command c_env = fetch_command_table[F_ENVELOPE]; | ||
153 | fetch_fast (command, arg); | ||
154 | c_env.states = command->states; | ||
155 | c_env.success = 0; | ||
156 | fetch_envelope (&c_env, arg); | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int | ||
161 | fetch_full (struct imap4d_command *command, char *arg) | ||
162 | { | ||
163 | struct imap4d_command c_body = fetch_command_table[F_BODY]; | ||
164 | fetch_all (command, arg); | ||
165 | c_body.states = command->states; | ||
166 | c_body.success = 0; | ||
167 | fetch_body (&c_body, arg); | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int | ||
172 | fetch_fast (struct imap4d_command *command, char *arg) | ||
173 | { | ||
174 | struct imap4d_command c_idate = fetch_command_table[F_INTERNALDATE]; | ||
175 | struct imap4d_command c_rfc = fetch_command_table[F_RFC822_SIZE]; | ||
176 | struct imap4d_command c_flags = fetch_command_table[F_FLAGS]; | ||
177 | c_flags.states = command->states; | ||
178 | c_flags.success = command->success; | ||
179 | fetch_flags (&c_flags, arg); | ||
180 | command->success = 0; | ||
181 | c_idate.states = command->states; | ||
182 | c_idate.success = 0; | ||
183 | fetch_internaldate (&c_idate, arg); | ||
184 | c_rfc.states = command->states; | ||
185 | c_rfc.success = 0; | ||
186 | fetch_rfc822_size (&c_rfc, arg); | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | /* FIXME, FIXME: | ||
191 | - incorrect DATE | ||
192 | - address not the correct format | ||
193 | - strings change to literals when detecting '"' | ||
194 | */ | ||
195 | static int | ||
196 | fetch_envelope (struct imap4d_command *command, char *arg) | ||
197 | { | ||
198 | char buffer[512]; | ||
199 | header_t header = NULL; | ||
200 | message_t msg = NULL; | ||
201 | int status; | ||
202 | mailbox_get_message (mbox, command->states, &msg); | ||
203 | message_get_header (msg, &header); | ||
204 | EPILOGUE(command); | ||
205 | status = header_get_value (header, "Date", buffer, sizeof (buffer), NULL); | ||
206 | util_send (" \"%s\"", buffer); | ||
207 | status = header_get_value (header, "Subject", buffer, sizeof (buffer), NULL); | ||
208 | util_send (" \"%s\"", buffer); | ||
209 | status = header_get_value (header, "From", buffer, sizeof (buffer), NULL); | ||
210 | util_send (" ((NIL NIL NIL \"%s\"))", buffer); | ||
211 | status = header_get_value (header, "Sender", buffer, sizeof (buffer), NULL); | ||
212 | util_send (" ((NIL NIL NIL \"%s\"))", buffer); | ||
213 | status = header_get_value (header, "Reply-to", buffer, sizeof (buffer), NULL); | ||
214 | util_send (" ((NIL NIL NIL \"%s\"))", buffer); | ||
215 | status = header_get_value (header, "To", buffer, sizeof (buffer), NULL); | ||
216 | util_send (" ((NIL NIL NIL \"%s\"))", buffer); | ||
217 | status = header_get_value (header, "Cc", buffer, sizeof (buffer), NULL); | ||
218 | util_send (" ((NIL NIL NIL \"%s\"))", buffer); | ||
219 | status = header_get_value (header, "Bcc", buffer, sizeof (buffer), NULL); | ||
220 | util_send (" ((NIL NIL NIL \"%s\"))", buffer); | ||
221 | status = header_get_value (header, "In-Reply-To", buffer, sizeof (buffer), NULL); | ||
222 | util_send (" \"%s\"", buffer); | ||
223 | status = header_get_value (header, "Message-ID", buffer, sizeof (buffer), NULL); | ||
224 | util_send (" \"%s\"", buffer); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static int | ||
229 | fetch_flags (struct imap4d_command *command, char *arg) | ||
230 | { | ||
231 | attribute_t attr = NULL; | ||
232 | message_t msg = NULL; | ||
233 | mailbox_get_message (mbox, command->states, &msg); | ||
234 | message_get_attribute (msg, &attr); | ||
235 | EPILOGUE(command); | ||
236 | util_send (" ("); | ||
237 | if (attribute_is_deleted (attr)) | ||
238 | util_send (" \\Deleted"); | ||
239 | if (attribute_is_read (attr)) | ||
240 | util_send (" \\Read"); | ||
241 | if (attribute_is_seen (attr)) | ||
242 | util_send (" \\Seen"); | ||
243 | if (attribute_is_draft (attr)) | ||
244 | util_send (" \\Draft"); | ||
245 | util_send (" )"); | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int | ||
250 | fetch_internaldate (struct imap4d_command *command, char *arg) | ||
251 | { | ||
252 | char date[512]; | ||
253 | envelope_t env = NULL; | ||
254 | message_t msg = NULL; | ||
255 | mailbox_get_message (mbox, command->states, &msg); | ||
256 | message_get_envelope (msg, &env); | ||
257 | date[0] = '\0'; | ||
258 | envelope_date (env, date, sizeof (date), NULL); | ||
259 | EPILOGUE(command); | ||
260 | if (date[strlen (date) - 1] == '\n') | ||
261 | date[strlen (date) - 1] = '\0'; | ||
262 | util_send (" \"%s\"", date); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static int | ||
267 | fetch_rfc822_header (struct imap4d_command *command, char *arg) | ||
268 | { | ||
269 | char buffer[64]; | ||
270 | struct imap4d_command c_body_p = fetch_command_table[F_BODY_PEEK]; | ||
271 | c_body_p.states = command->states; | ||
272 | c_body_p.success = command->success; | ||
273 | strcpy (buffer, "[HEADER]"); | ||
274 | fetch_body_peek (&c_body_p, buffer); | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int | ||
279 | fetch_rfc822_size (struct imap4d_command *command, char *arg) | ||
280 | { | ||
281 | size_t size = 0; | ||
282 | size_t lines = 0; | ||
283 | message_t msg = NULL; | ||
284 | mailbox_get_message (mbox, command->states, &msg); | ||
285 | message_size (msg, &size); | ||
286 | message_lines (msg, &lines); | ||
287 | EPILOGUE(command); | ||
288 | util_send (" %u", size + lines); | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int | ||
293 | fetch_rfc822_text (struct imap4d_command *command, char *arg) | ||
294 | { | ||
295 | char buffer[64]; | ||
296 | struct imap4d_command c_body = fetch_command_table[F_BODY]; | ||
297 | c_body.states = command->states; | ||
298 | c_body.success = command->success; | ||
299 | strcpy (buffer, "[TEXT]"); | ||
300 | fetch_body (&c_body, buffer); | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | |||
305 | static int | ||
306 | fetch_rfc822 (struct imap4d_command *command, char *arg) | ||
307 | { | ||
308 | char buffer[64]; | ||
309 | struct imap4d_command c_body = fetch_command_table[F_BODY]; | ||
310 | c_body.states = command->states; | ||
311 | c_body.success = command->success; | ||
312 | strcpy (buffer, "[]"); | ||
313 | fetch_body (&c_body, buffer); | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | /* FIXME: not implemeted. */ | ||
318 | static int | ||
319 | fetch_bodystructure (struct imap4d_command *command, char *arg) | ||
320 | { | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static int | ||
325 | fetch_body (struct imap4d_command *command, char *arg) | ||
326 | { | ||
327 | attribute_t attr = NULL; | ||
328 | message_t msg = NULL; | ||
329 | struct imap4d_command c_body_p = fetch_command_table[F_BODY_PEEK]; | ||
330 | mailbox_get_message (mbox, command->states, &msg); | ||
331 | message_get_attribute (msg, &attr); | ||
332 | c_body_p.states = command->states; | ||
333 | c_body_p.success = command->success; | ||
334 | fetch_body_peek (&c_body_p, arg); | ||
335 | attribute_set_seen (attr); | ||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | static int | ||
340 | fetch_uid (struct imap4d_command *command, char *arg) | ||
341 | { | ||
342 | size_t uid = 0; | ||
343 | message_t msg = NULL; | ||
344 | mailbox_get_message (mbox, command->states, &msg); | ||
345 | message_get_uid (msg, &uid); | ||
346 | EPILOGUE (command); | ||
347 | util_send (" %d", uid); | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int | ||
352 | fetch_body_peek (struct imap4d_command *command, char *arg) | ||
353 | { | ||
354 | message_t msg = NULL; | ||
355 | char *partial = strchr (arg, '<'); | ||
356 | |||
357 | mailbox_get_message (mbox, command->states, &msg); | ||
358 | |||
359 | EPILOGUE(command); | ||
360 | |||
361 | if (strncasecmp (arg, "[]", 2) == 0) | ||
362 | { | ||
363 | stream_t stream = NULL; | ||
364 | char buffer[512]; | ||
365 | size_t size = 0, lines = 0, n = 0; | ||
366 | off_t off = 0; | ||
367 | message_get_stream (msg, &stream); | ||
368 | message_size (msg, &size); | ||
369 | message_size (msg, &lines); | ||
370 | util_send (" BODY[] {%u}\r\n", size + lines); | ||
371 | while (stream_readline (stream, buffer, sizeof (buffer), off, &n) == 0 | ||
372 | && n > 0) | ||
373 | { | ||
374 | /* Nuke the trainline newline. */ | ||
375 | if (buffer[n - 1] == '\n') | ||
376 | buffer[n - 1] = '\0'; | ||
377 | util_send ("%s\r\n", buffer); | ||
378 | off += n; | ||
379 | } | ||
380 | } | ||
381 | else if (strncasecmp (arg, "[HEADER]", 8) == 0) | ||
382 | { | ||
383 | header_t header = NULL; | ||
384 | stream_t stream = NULL; | ||
385 | char buffer[512]; | ||
386 | size_t size = 0, lines = 0, n = 0; | ||
387 | off_t off = 0; | ||
388 | message_get_header (msg, &header); | ||
389 | header_size (header, &size); | ||
390 | header_lines (header, &lines); | ||
391 | util_send (" BODY[HEADER] {%u}\r\n", size + lines); | ||
392 | header_get_stream (msg, &stream); | ||
393 | while (stream_readline (stream, buffer, sizeof (buffer), off, &n) == 0 | ||
394 | && n > 0) | ||
395 | { | ||
396 | /* Nuke the trainline newline. */ | ||
397 | if (buffer[n - 1] == '\n') | ||
398 | buffer[n - 1] = '\0'; | ||
399 | util_send ("%s\r\n", buffer); | ||
400 | off += n; | ||
401 | } | ||
402 | } | ||
403 | else if (strncasecmp (arg, "[TEXT]", 6) == 0) | ||
404 | { | ||
405 | body_t body = NULL; | ||
406 | stream_t stream = NULL; | ||
407 | char buffer[512]; | ||
408 | size_t size = 0, lines = 0, n = 0; | ||
409 | off_t off = 0; | ||
410 | message_get_body (msg, &body); | ||
411 | body_size (body, &size); | ||
412 | body_lines (body, &lines); | ||
413 | util_send (" BODY[TEXT] {%u}\r\n", size + lines); | ||
414 | body_get_stream (msg, &stream); | ||
415 | while (stream_readline (stream, buffer, sizeof (buffer), off, &n) == 0 | ||
416 | && n > 0) | ||
417 | { | ||
418 | /* Nuke the trainline newline. */ | ||
419 | if (buffer[n - 1] == '\n') | ||
420 | buffer[n - 1] = '\0'; | ||
421 | util_send ("%s\r\n", buffer); | ||
422 | off += n; | ||
423 | } | ||
424 | } | ||
425 | else | ||
426 | util_send (" Not supported"); | ||
427 | return 0; | ||
38 | } | 428 | } | ... | ... |
... | @@ -29,6 +29,7 @@ | ... | @@ -29,6 +29,7 @@ |
29 | #endif | 29 | #endif |
30 | 30 | ||
31 | #include <errno.h> | 31 | #include <errno.h> |
32 | #include <limits.h> | ||
32 | #include <stdio.h> | 33 | #include <stdio.h> |
33 | #include <stdlib.h> | 34 | #include <stdlib.h> |
34 | #include <unistd.h> | 35 | #include <unistd.h> |
... | @@ -121,14 +122,17 @@ int imap4d_uid __P ((struct imap4d_command *, char *)); | ... | @@ -121,14 +122,17 @@ int imap4d_uid __P ((struct imap4d_command *, char *)); |
121 | 122 | ||
122 | /* Helper functions. */ | 123 | /* Helper functions. */ |
123 | int util_out __P ((int rc, const char *f, ...)); | 124 | int util_out __P ((int rc, const char *f, ...)); |
125 | int util_send __P ((const char *f, ...)); | ||
124 | int util_start __P ((char *tag)); | 126 | int util_start __P ((char *tag)); |
125 | int util_finish __P ((struct imap4d_command *, int rc, const char *f, ...)); | 127 | int util_finish __P ((struct imap4d_command *, int sc, const char *f, ...)); |
126 | int util_getstate __P ((void)); | 128 | int util_getstate __P ((void)); |
127 | int util_do_command __P ((char *prompt)); | 129 | int util_do_command __P ((char *prompt)); |
128 | char *imap4d_readline __P ((int fd)); | 130 | char *imap4d_readline __P ((int fd)); |
129 | void util_quit __P ((int)); | 131 | void util_quit __P ((int)); |
130 | char *util_getword __P ((char *s, char **save_ptr)); | 132 | char *util_getword __P ((char *s, char **save_ptr)); |
131 | struct imap4d_command *util_getcommand __P ((char *cmd)); | 133 | int util_msgset __P ((char *s, int **set, int *n, int isuid)); |
134 | struct imap4d_command *util_getcommand __P ((char *cmd, | ||
135 | struct imap4d_command [])); | ||
132 | 136 | ||
133 | #ifdef __cplusplus | 137 | #ifdef __cplusplus |
134 | } | 138 | } | ... | ... |
... | @@ -17,9 +17,7 @@ | ... | @@ -17,9 +17,7 @@ |
17 | 17 | ||
18 | #include "imap4d.h" | 18 | #include "imap4d.h" |
19 | 19 | ||
20 | /* | 20 | /* select ::= "SELECT" SPACE mailbox */ |
21 | * argv[2] == mailbox | ||
22 | */ | ||
23 | 21 | ||
24 | int | 22 | int |
25 | imap4d_select (struct imap4d_command *command, char *arg) | 23 | imap4d_select (struct imap4d_command *command, char *arg) |
... | @@ -58,18 +56,32 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags) | ... | @@ -58,18 +56,32 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags) |
58 | if (mailbox_create_default (&mbox, mailbox_name) == 0 | 56 | if (mailbox_create_default (&mbox, mailbox_name) == 0 |
59 | && mailbox_open (mbox, flags) == 0) | 57 | && mailbox_open (mbox, flags) == 0) |
60 | { | 58 | { |
61 | const char *sflags = "\\Answered \\Flagged \\Deleted \\Seen \\Draft"; | 59 | const char *mflags = "\\Answered \\Flagged \\Deleted \\Seen \\Draft"; |
62 | int num = 0, recent = 0, uid = 0; | 60 | const char *pflags = "\\Answered \\Flagged \\Deleted \\Seen \\Draft"; |
61 | unsigned long uidvalidity = 0; | ||
62 | size_t count = 0, recent = 0, unseen = 0, uidnext = 0; | ||
63 | 63 | ||
64 | mailbox_messages_count (mbox, &num); | 64 | mailbox_uidvalidity (mbox, &uidvalidity); |
65 | mailbox_recent_count (mbox, &recent); | 65 | mailbox_uidnext (mbox, &uidnext); |
66 | util_out (RESP_NONE, "%d EXISTS", num); | 66 | mailbox_messages_count (mbox, &count); |
67 | mailbox_messages_recent (mbox, &recent); | ||
68 | mailbox_message_unseen (mbox, &unseen); | ||
69 | util_out (RESP_NONE, "%d EXISTS", count); | ||
67 | util_out (RESP_NONE, "%d RECENT", recent); | 70 | util_out (RESP_NONE, "%d RECENT", recent); |
68 | util_out (RESP_NONE, "FLAGS (%s)", sflags); | 71 | util_out (RESP_NONE, "FLAGS (%s)", mflags); |
69 | util_out (RESP_OK, "[UIDNEXT %d]", num + 1); | 72 | util_out (RESP_OK, "[UIDNEXT %d] Predicted next uid", uidnext); |
70 | /*util_out (RESP_OK, "[UIDVALIDITY (%d)]", uid);*/ | 73 | util_out (RESP_OK, "[UIDVALIDITY (%d)] UID valididy status", |
71 | /*util_out (RESP_OK, "[PERMANENTFLAGS (%s)]", flags);*/ | 74 | uidvalidity); |
72 | return util_finish (command, RESP_OK, "Complete"); | 75 | if (unseen) |
76 | util_out (RESP_OK, "[UNSEEN (%d)] %d is first unseen messsage ", | ||
77 | unseen, unseen); | ||
78 | /* FIXME: | ||
79 | - '\*' can be supported if we use the attribute_set userflag() | ||
80 | - Answered is still not set in the mailbox code. */ | ||
81 | util_out (RESP_OK, "[PERMANENTFLAGS (%s)]", pflags); | ||
82 | return util_send ("%s OK [%s] %s Complete\r\n", command->tag, | ||
83 | (MU_STREAM_READ == flags) ? | ||
84 | "READ-ONLY" : "READ-WRITE", command->name); | ||
73 | } | 85 | } |
74 | return util_finish (command, RESP_NO, "Couldn't open %s", mailbox_name); | 86 | return util_finish (command, RESP_NO, "Couldn't open %s", mailbox_name); |
75 | } | 87 | } | ... | ... |
... | @@ -17,34 +17,144 @@ | ... | @@ -17,34 +17,144 @@ |
17 | 17 | ||
18 | #include "imap4d.h" | 18 | #include "imap4d.h" |
19 | 19 | ||
20 | static const char * | 20 | static int add2set (int **set, int *n, unsigned long val, size_t max); |
21 | rc2string (int rc) | 21 | static const char * sc2string (int rc); |
22 | |||
23 | /* FIXME: Some words are: | ||
24 | between double quotes, between parenthesis. */ | ||
25 | char * | ||
26 | util_getword (char *s, char **save) | ||
22 | { | 27 | { |
23 | switch (rc) | 28 | return strtok_r (s, " \r\n", save); |
29 | } | ||
30 | |||
31 | /* Return in set an allocated array contain (n) numbers, for imap messsage set | ||
32 | |||
33 | set ::= sequence_num / (sequence_num ":" sequence_num) / (set "," set) | ||
34 | sequence_num ::= nz_number / "*" | ||
35 | ;; * is the largest number in use. For message | ||
36 | ;; sequence numbers, it is the number of messages | ||
37 | ;; in the mailbox. For unique identifiers, it is | ||
38 | ;; the unique identifier of the last message in | ||
39 | ;; the mailbox. | ||
40 | nz_number ::= digit_nz *digit | ||
41 | |||
42 | FIXME: The algo below is to relaxe, things like <,,,> or <:12> or <20:10> | ||
43 | will not generate an error. */ | ||
44 | int | ||
45 | util_msgset (char *s, int **set, int *n, int isuid) | ||
46 | { | ||
47 | unsigned long val = 0; | ||
48 | unsigned long low = 0; | ||
49 | int done = 0; | ||
50 | int status = 0; | ||
51 | size_t max = 0; | ||
52 | |||
53 | status = mailbox_messages_count (mbox, &max); | ||
54 | if (status != 0) | ||
55 | return status; | ||
56 | if (isuid) | ||
24 | { | 57 | { |
25 | case RESP_OK: | 58 | message_t msg = NULL; |
26 | return "OK "; | 59 | mailbox_get_message (mbox, max, &msg); |
60 | message_get_uid (msg, &max); | ||
61 | } | ||
27 | 62 | ||
28 | case RESP_BAD: | 63 | *n = 0; |
29 | return "BAD "; | 64 | *set = NULL; |
65 | while (*s) | ||
66 | { | ||
67 | switch (*s) | ||
68 | { | ||
69 | /* isdigit */ | ||
70 | case '0': case '1': case '2': case '3': case '4': | ||
71 | case '5': case '6': case '7': case '8': case '9': | ||
72 | { | ||
73 | errno = 0; | ||
74 | val = strtoul (s, &s, 10); | ||
75 | if (val == ULONG_MAX && errno == ERANGE) | ||
76 | { | ||
77 | if (*set) | ||
78 | free (*set); | ||
79 | *n = 0; | ||
80 | return EINVAL; | ||
81 | } | ||
82 | if (low) | ||
83 | { | ||
84 | for (;low && low <= val; low++) | ||
85 | { | ||
86 | status = add2set (set, n, low, max); | ||
87 | if (status != 0) | ||
88 | return status; | ||
89 | } | ||
90 | low = 0; | ||
91 | } | ||
92 | else | ||
93 | { | ||
94 | status = add2set(set, n, val, max); | ||
95 | if (status != 0) | ||
96 | return status; | ||
97 | } | ||
98 | break; | ||
99 | } | ||
30 | 100 | ||
31 | case RESP_NO: | 101 | case ':': |
32 | return "NO "; | 102 | low = val + 1; |
103 | s++; | ||
104 | break; | ||
33 | 105 | ||
34 | case RESP_BYE: | 106 | case '*': |
35 | return "BYE "; | 107 | { |
108 | if (status != 0) | ||
109 | { | ||
110 | if (*set) | ||
111 | free (*set); | ||
112 | *n = 0; | ||
113 | return status; | ||
36 | } | 114 | } |
37 | return ""; | 115 | val = max; |
116 | s++; | ||
117 | break; | ||
118 | } | ||
119 | |||
120 | case ',': | ||
121 | s++; | ||
122 | break; | ||
123 | |||
124 | default: | ||
125 | done = 1; | ||
126 | if (*set) | ||
127 | free (*set); | ||
128 | *n = 0; | ||
129 | return EINVAL; | ||
130 | |||
131 | } /* switch */ | ||
132 | |||
133 | if (done) | ||
134 | break; | ||
135 | } /* while */ | ||
136 | |||
137 | if (low) | ||
138 | { | ||
139 | for (;low && low <= val; low++) | ||
140 | { | ||
141 | status = add2set (set, n, low, max); | ||
142 | if (status != 0) | ||
143 | return status; | ||
144 | } | ||
145 | } | ||
146 | return 0; | ||
38 | } | 147 | } |
39 | 148 | ||
40 | /* FIXME: Some words are: | 149 | int |
41 | between double quotes, consider like one word. | 150 | util_send (const char *format, ...) |
42 | between parenthesis, consider line one word. */ | ||
43 | char * | ||
44 | util_getword (char *s, char **save) | ||
45 | { | 151 | { |
46 | static char *sp; | 152 | int status; |
47 | return strtok_r (s, " \r\n", ((save) ? save : &sp)); | 153 | va_list ap; |
154 | va_start (ap, format); | ||
155 | status = vfprintf (ofile, format, ap); | ||
156 | va_end (ap); | ||
157 | return status; | ||
48 | } | 158 | } |
49 | 159 | ||
50 | int | 160 | int |
... | @@ -57,7 +167,7 @@ util_out (int rc, const char *format, ...) | ... | @@ -57,7 +167,7 @@ util_out (int rc, const char *format, ...) |
57 | vasprintf (&buf, format, ap); | 167 | vasprintf (&buf, format, ap); |
58 | va_end (ap); | 168 | va_end (ap); |
59 | 169 | ||
60 | fprintf (ofile, "* %s%s\r\n", rc2string (rc), buf); | 170 | fprintf (ofile, "* %s%s\r\n", sc2string (rc), buf); |
61 | free (buf); | 171 | free (buf); |
62 | return 0; | 172 | return 0; |
63 | } | 173 | } |
... | @@ -73,7 +183,7 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...) | ... | @@ -73,7 +183,7 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...) |
73 | vasprintf (&buf, format, ap); | 183 | vasprintf (&buf, format, ap); |
74 | va_end(ap); | 184 | va_end(ap); |
75 | 185 | ||
76 | resp = rc2string (rc); | 186 | resp = sc2string (rc); |
77 | fprintf (ofile, "%s %s%s %s\r\n", command->tag, resp, command->name, buf); | 187 | fprintf (ofile, "%s %s%s %s\r\n", command->tag, resp, command->name, buf); |
78 | free (buf); | 188 | free (buf); |
79 | return 0; | 189 | return 0; |
... | @@ -86,6 +196,7 @@ imap4d_readline (int fd) | ... | @@ -86,6 +196,7 @@ imap4d_readline (int fd) |
86 | struct timeval tv; | 196 | struct timeval tv; |
87 | char buf[512], *ret = NULL; | 197 | char buf[512], *ret = NULL; |
88 | int nread; | 198 | int nread; |
199 | int total = 0; | ||
89 | int available; | 200 | int available; |
90 | 201 | ||
91 | FD_ZERO (&rfds); | 202 | FD_ZERO (&rfds); |
... | @@ -99,35 +210,35 @@ imap4d_readline (int fd) | ... | @@ -99,35 +210,35 @@ imap4d_readline (int fd) |
99 | { | 210 | { |
100 | available = select (fd + 1, &rfds, NULL, NULL, &tv); | 211 | available = select (fd + 1, &rfds, NULL, NULL, &tv); |
101 | if (!available) | 212 | if (!available) |
102 | util_quit (1); /* FIXME: Timeout. */ | 213 | util_quit (1); /* FIXME: Timeout, send a "* BYE". */ |
103 | } | 214 | } |
104 | nread = read (fd, buf, sizeof (buf) - 1); | 215 | nread = read (fd, buf, sizeof (buf) - 1); |
105 | if (nread < 1) | 216 | if (nread < 1) |
106 | util_quit (1); /* FIXME: dead socket */ | 217 | util_quit (1); /* FIXME: dead socket, need to do something? */ |
107 | 218 | ||
108 | buf[nread] = '\0'; | 219 | buf[nread] = '\0'; |
109 | 220 | ||
221 | ret = realloc (ret, (total + nread + 1) * sizeof (char)); | ||
110 | if (ret == NULL) | 222 | if (ret == NULL) |
111 | { | 223 | util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */ |
112 | ret = malloc ((nread + 1) * sizeof (char)); | 224 | memcpy (ret + total, buf, nread + 1); |
113 | strcpy (ret, buf); | 225 | total += nread; |
114 | } | 226 | |
115 | else | ||
116 | { | ||
117 | ret = realloc (ret, (strlen (ret) + nread + 1) * sizeof (char)); | ||
118 | strcat (ret, buf); | ||
119 | } | ||
120 | /* FIXME: handle literal strings here. */ | 227 | /* FIXME: handle literal strings here. */ |
228 | |||
121 | } | 229 | } |
122 | while (strchr (buf, '\n') == NULL); | 230 | while (memchr (buf, '\n', nread) == NULL); |
123 | 231 | ||
232 | for (nread = total; nread > 0; nread--) | ||
233 | if (ret[nread] == '\r' || ret[nread] == '\n') | ||
234 | ret[nread] = '\0'; | ||
124 | return ret; | 235 | return ret; |
125 | } | 236 | } |
126 | 237 | ||
127 | int | 238 | int |
128 | util_do_command (char *prompt) | 239 | util_do_command (char *prompt) |
129 | { | 240 | { |
130 | char *sp = NULL, *tag, *cmd, *arg; | 241 | char *sp = NULL, *tag, *cmd; |
131 | struct imap4d_command *command; | 242 | struct imap4d_command *command; |
132 | static struct imap4d_command nullcommand; | 243 | static struct imap4d_command nullcommand; |
133 | 244 | ||
... | @@ -148,7 +259,7 @@ util_do_command (char *prompt) | ... | @@ -148,7 +259,7 @@ util_do_command (char *prompt) |
148 | 259 | ||
149 | util_start (tag); | 260 | util_start (tag); |
150 | 261 | ||
151 | command = util_getcommand (cmd); | 262 | command = util_getcommand (cmd, imap4d_command_table); |
152 | if (command == NULL) | 263 | if (command == NULL) |
153 | { | 264 | { |
154 | nullcommand.name = ""; | 265 | nullcommand.name = ""; |
... | @@ -183,15 +294,54 @@ util_getstate (void) | ... | @@ -183,15 +294,54 @@ util_getstate (void) |
183 | } | 294 | } |
184 | 295 | ||
185 | struct imap4d_command * | 296 | struct imap4d_command * |
186 | util_getcommand (char *cmd) | 297 | util_getcommand (char *cmd, struct imap4d_command command_table[]) |
187 | { | 298 | { |
188 | size_t i, len = strlen (cmd); | 299 | size_t i, len = strlen (cmd); |
189 | 300 | ||
190 | for (i = 0; imap4d_command_table[i].name != 0; i++) | 301 | for (i = 0; command_table[i].name != 0; i++) |
191 | { | 302 | { |
192 | if (strlen (imap4d_command_table[i].name) == len && | 303 | if (strlen (command_table[i].name) == len && |
193 | !strcasecmp (imap4d_command_table[i].name, cmd)) | 304 | !strcasecmp (command_table[i].name, cmd)) |
194 | return &imap4d_command_table[i]; | 305 | return &command_table[i]; |
195 | } | 306 | } |
196 | return NULL; | 307 | return NULL; |
197 | } | 308 | } |
309 | |||
310 | /* Status Code to String. */ | ||
311 | static const char * | ||
312 | sc2string (int rc) | ||
313 | { | ||
314 | switch (rc) | ||
315 | { | ||
316 | case RESP_OK: | ||
317 | return "OK "; | ||
318 | |||
319 | case RESP_BAD: | ||
320 | return "BAD "; | ||
321 | |||
322 | case RESP_NO: | ||
323 | return "NO "; | ||
324 | |||
325 | case RESP_BYE: | ||
326 | return "BYE "; | ||
327 | } | ||
328 | return ""; | ||
329 | } | ||
330 | |||
331 | static int | ||
332 | add2set (int **set, int *n, unsigned long val, size_t max) | ||
333 | { | ||
334 | int *tmp; | ||
335 | if (val == 0 || val > max | ||
336 | || (tmp = realloc (*set, (*n + 1) * sizeof (**set))) == NULL) | ||
337 | { | ||
338 | if (*set) | ||
339 | free (*set); | ||
340 | *n = 0; | ||
341 | return ENOMEM; | ||
342 | } | ||
343 | *set = tmp; | ||
344 | (*set)[*n] = val; | ||
345 | (*n)++; | ||
346 | return 0; | ||
347 | } | ... | ... |
-
Please register or sign in to post a comment