Commit 5ec8063e 5ec8063eccd7552626991c977bcaa8574604009e by Alain Magloire

* 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.
1 parent 0412541c
...@@ -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 }
......