Commit dbfad7e1 dbfad7e18ddeadced961dcd12137ad2b12d4c42e by Alain Magloire

More cleanup in the fetch imap code.

1 parent bc49501d
1 2001-05-11 Alain Magloire
2
3 * imap4d/fetch.c: More cleanup in the bodystructure code,
4 arrange response indentation etc ...
5 * impa4d/utils.c (util_send_string): New helper function.
6
1 2001-05-10 Alain Magloire 7 2001-05-10 Alain Magloire
2 8
3 * imap4d/fetch.c: Implemented INTERNALDATE. 9 * imap4d/fetch.c: Implemented INTERNALDATE.
......
...@@ -51,7 +51,7 @@ static int bodystructure __P ((message_t, int)); ...@@ -51,7 +51,7 @@ static int bodystructure __P ((message_t, int));
51 static int fetch_body __P ((struct fetch_command *, char*)); 51 static int fetch_body __P ((struct fetch_command *, char*));
52 static int fetch_uid __P ((struct fetch_command *, char*)); 52 static int fetch_uid __P ((struct fetch_command *, char*));
53 53
54 static int fetch_operation __P ((size_t, char *, int)); 54 static int fetch_operation __P ((message_t, char *, int));
55 static int fetch_message __P ((message_t, unsigned long, unsigned long)); 55 static int fetch_message __P ((message_t, unsigned long, unsigned long));
56 static int fetch_header __P ((message_t, unsigned long, unsigned long)); 56 static int fetch_header __P ((message_t, unsigned long, unsigned long));
57 static int fetch_content __P ((message_t, unsigned long, unsigned long)); 57 static int fetch_content __P ((message_t, unsigned long, unsigned long));
...@@ -66,7 +66,7 @@ struct fetch_command ...@@ -66,7 +66,7 @@ struct fetch_command
66 { 66 {
67 const char *name; 67 const char *name;
68 int (*func) __P ((struct fetch_command *, char *)); 68 int (*func) __P ((struct fetch_command *, char *));
69 size_t msgno; 69 message_t msg;
70 } fetch_command_table [] = 70 } fetch_command_table [] =
71 { 71 {
72 #define F_ALL 0 72 #define F_ALL 0
...@@ -98,18 +98,7 @@ struct fetch_command ...@@ -98,18 +98,7 @@ struct fetch_command
98 { NULL, 0, 0} 98 { NULL, 0, 0}
99 }; 99 };
100 100
101 int 101 /* Go through the fetch array sub command and returns the the structure. */
102 imap4d_fetch (struct imap4d_command *command, char *arg)
103 {
104 int rc;
105 char buffer[64];
106
107 if (! (command->states & state))
108 return util_finish (command, RESP_BAD, "Wrong state");
109
110 rc = imap4d_fetch0 (arg, 0, buffer, sizeof buffer);
111 return util_finish (command, rc, buffer);
112 }
113 102
114 static struct fetch_command * 103 static struct fetch_command *
115 fetch_getcommand (char *cmd, struct fetch_command command_table[]) 104 fetch_getcommand (char *cmd, struct fetch_command command_table[])
...@@ -125,6 +114,24 @@ fetch_getcommand (char *cmd, struct fetch_command command_table[]) ...@@ -125,6 +114,24 @@ fetch_getcommand (char *cmd, struct fetch_command command_table[])
125 return NULL; 114 return NULL;
126 } 115 }
127 116
117 /* The FETCH command retrieves data associated with a message in the
118 mailbox. The data items to be fetched can be either a single atom
119 or a parenthesized list. */
120 int
121 imap4d_fetch (struct imap4d_command *command, char *arg)
122 {
123 int rc;
124 char buffer[64];
125
126 if (! (command->states & state))
127 return util_finish (command, RESP_BAD, "Wrong state");
128
129 rc = imap4d_fetch0 (arg, 0, buffer, sizeof buffer);
130 return util_finish (command, rc, buffer);
131 }
132
133 /* Where the real implementation is. It is here since UID command also
134 calls FETCH. */
128 int 135 int
129 imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen) 136 imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen)
130 { 137 {
...@@ -159,10 +166,10 @@ imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen) ...@@ -159,10 +166,10 @@ imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen)
159 char *p = items; 166 char *p = items;
160 size_t msgno; 167 size_t msgno;
161 int space = 0; 168 int space = 0;
162 int uid_sent = !isuid; /* Pretend we sent the uid if via fetch. */ 169 message_t msg = NULL;
163 170
164 msgno = (isuid) ? uid_to_msgno (set[i]) : set[i]; 171 msgno = (isuid) ? uid_to_msgno (set[i]) : set[i];
165 if (msgno) 172 if (msgno && mailbox_get_message (mbox, msgno, &msg) == 0)
166 { 173 {
167 fcmd = NULL; 174 fcmd = NULL;
168 util_send ("* %d FETCH (", msgno); 175 util_send ("* %d FETCH (", msgno);
...@@ -171,18 +178,18 @@ imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen) ...@@ -171,18 +178,18 @@ imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen)
171 include the UID message data item as part of any FETCH response 178 include the UID message data item as part of any FETCH response
172 caused by a UID command, regardless of whether a UID was specified 179 caused by a UID command, regardless of whether a UID was specified
173 as a message data item to the FETCH. */ 180 as a message data item to the FETCH. */
174 if (!uid_sent) 181 if (isuid)
175 { 182 {
176 fcmd = &fetch_command_table[F_UID]; 183 fcmd = &fetch_command_table[F_UID];
177 fcmd->msgno = msgno; 184 fcmd->msg = msg;
178 rc = fetch_uid (fcmd, p); 185 rc = fetch_uid (fcmd, p);
179 uid_sent = 1;
180 } 186 }
181 /* Get the fetch command names. */ 187 /* Get the fetch command names. */
182 while (*items && *items != ')') 188 while (*items && *items != ')')
183 { 189 {
184 util_token (item, sizeof (item), &items); 190 util_token (item, sizeof (item), &items);
185 if (uid_sent && strcasecmp (item, "UID") == 0) 191 /* Do not send the UID again. */
192 if (isuid && strcasecmp (item, "UID") == 0)
186 continue; 193 continue;
187 if (fcmd) 194 if (fcmd)
188 space = 1; 195 space = 1;
...@@ -195,7 +202,7 @@ imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen) ...@@ -195,7 +202,7 @@ imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen)
195 util_send (" "); 202 util_send (" ");
196 space = 0; 203 space = 0;
197 } 204 }
198 fcmd->msgno = msgno; 205 fcmd->msg = msg;
199 rc = fcmd->func (fcmd, items); 206 rc = fcmd->func (fcmd, items);
200 } 207 }
201 } 208 }
...@@ -208,7 +215,7 @@ imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen) ...@@ -208,7 +215,7 @@ imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen)
208 return rc; 215 return rc;
209 } 216 }
210 217
211 /* The Fetch comand retireves data associated with a message in the 218 /* The Fetch comand retrieves data associated with a message in the
212 mailbox, The data items to be fetched can be either a single atom 219 mailbox, The data items to be fetched can be either a single atom
213 or a parenthesized list. */ 220 or a parenthesized list. */
214 221
...@@ -220,7 +227,7 @@ fetch_all (struct fetch_command *command, char *arg) ...@@ -220,7 +227,7 @@ fetch_all (struct fetch_command *command, char *arg)
220 struct fetch_command c_env = fetch_command_table[F_ENVELOPE]; 227 struct fetch_command c_env = fetch_command_table[F_ENVELOPE];
221 fetch_fast (command, arg); 228 fetch_fast (command, arg);
222 util_send (" "); 229 util_send (" ");
223 c_env.msgno = command->msgno; 230 c_env.msg = command->msg;
224 fetch_envelope (&c_env, arg); 231 fetch_envelope (&c_env, arg);
225 return RESP_OK; 232 return RESP_OK;
226 } 233 }
...@@ -232,7 +239,7 @@ fetch_full (struct fetch_command *command, char *arg) ...@@ -232,7 +239,7 @@ fetch_full (struct fetch_command *command, char *arg)
232 struct fetch_command c_body = fetch_command_table[F_BODY]; 239 struct fetch_command c_body = fetch_command_table[F_BODY];
233 fetch_all (command, arg); 240 fetch_all (command, arg);
234 util_send (" "); 241 util_send (" ");
235 c_body.msgno = command->msgno; 242 c_body.msg = command->msg;
236 fetch_body (&c_body, arg); 243 fetch_body (&c_body, arg);
237 return RESP_OK; 244 return RESP_OK;
238 } 245 }
...@@ -244,13 +251,13 @@ fetch_fast (struct fetch_command *command, char *arg) ...@@ -244,13 +251,13 @@ fetch_fast (struct fetch_command *command, char *arg)
244 struct fetch_command c_idate = fetch_command_table[F_INTERNALDATE]; 251 struct fetch_command c_idate = fetch_command_table[F_INTERNALDATE];
245 struct fetch_command c_rfc = fetch_command_table[F_RFC822_SIZE]; 252 struct fetch_command c_rfc = fetch_command_table[F_RFC822_SIZE];
246 struct fetch_command c_flags = fetch_command_table[F_FLAGS]; 253 struct fetch_command c_flags = fetch_command_table[F_FLAGS];
247 c_flags.msgno = command->msgno; 254 c_flags.msg = command->msg;
248 fetch_flags (&c_flags, arg); 255 fetch_flags (&c_flags, arg);
249 util_send (" "); 256 util_send (" ");
250 c_idate.msgno = command->msgno; 257 c_idate.msg = command->msg;
251 fetch_internaldate (&c_idate, arg); 258 fetch_internaldate (&c_idate, arg);
252 util_send (" "); 259 util_send (" ");
253 c_rfc.msgno = command->msgno; 260 c_rfc.msg = command->msg;
254 fetch_rfc822_size (&c_rfc, arg); 261 fetch_rfc822_size (&c_rfc, arg);
255 return RESP_OK; 262 return RESP_OK;
256 } 263 }
...@@ -260,16 +267,14 @@ fetch_fast (struct fetch_command *command, char *arg) ...@@ -260,16 +267,14 @@ fetch_fast (struct fetch_command *command, char *arg)
260 static int 267 static int
261 fetch_envelope (struct fetch_command *command, char *arg) 268 fetch_envelope (struct fetch_command *command, char *arg)
262 { 269 {
263 message_t msg = NULL;
264 int status; 270 int status;
265 mailbox_get_message (mbox, command->msgno, &msg); 271 (void)arg;
266 util_send ("%s (", command->name); 272 util_send ("%s (", command->name);
267 status = fetch_envelope0 (msg); 273 status = fetch_envelope0 (command->msg);
268 util_send (")"); 274 util_send (")");
269 return status; 275 return status;
270 } 276 }
271 277
272 /* FIXME: - strings change to literals when detecting '"' */
273 static int 278 static int
274 fetch_envelope0 (message_t msg) 279 fetch_envelope0 (message_t msg)
275 { 280 {
...@@ -279,21 +284,15 @@ fetch_envelope0 (message_t msg) ...@@ -279,21 +284,15 @@ fetch_envelope0 (message_t msg)
279 284
280 message_get_header (msg, &header); 285 message_get_header (msg, &header);
281 286
282 /* FIXME: Incorrect Date. */ 287 /* Date. */
283 header_aget_value (header, "Date", &buffer); 288 header_aget_value (header, "Date", &buffer);
284 if (*buffer == '\0') 289 util_send_string (buffer);
285 util_send ("NIL");
286 else
287 util_send ("\"%s\"", buffer);
288 free (buffer); 290 free (buffer);
289 util_send (" "); 291 util_send (" ");
290 292
291 /* Subject. */ 293 /* Subject. */
292 header_aget_value (header, "Subject", &buffer); 294 header_aget_value (header, "Subject", &buffer);
293 if (*buffer == '\0') 295 util_send_string (buffer);
294 util_send ("NIL");
295 else
296 util_send ("\"%s\"", buffer);
297 free (buffer); 296 free (buffer);
298 util_send (" "); 297 util_send (" ");
299 298
...@@ -335,10 +334,7 @@ fetch_envelope0 (message_t msg) ...@@ -335,10 +334,7 @@ fetch_envelope0 (message_t msg)
335 util_send (" "); 334 util_send (" ");
336 335
337 header_aget_value (header, "Message-ID", &buffer); 336 header_aget_value (header, "Message-ID", &buffer);
338 if (*buffer == '\0') 337 util_send_string (buffer);
339 util_send ("NIL");
340 else
341 util_send ("\"%s\"", buffer);
342 338
343 free (buffer); 339 free (buffer);
344 free (from); 340 free (from);
...@@ -351,22 +347,43 @@ static int ...@@ -351,22 +347,43 @@ static int
351 fetch_flags (struct fetch_command *command, char *arg) 347 fetch_flags (struct fetch_command *command, char *arg)
352 { 348 {
353 attribute_t attr = NULL; 349 attribute_t attr = NULL;
354 message_t msg = NULL; 350 int space = 0;
355 (void)arg; 351 (void)arg;
356 mailbox_get_message (mbox, command->msgno, &msg); 352 message_get_attribute (command->msg, &attr);
357 message_get_attribute (msg, &attr);
358 util_send ("%s (", command->name); 353 util_send ("%s (", command->name);
359 if (attribute_is_deleted (attr)) 354 if (attribute_is_deleted (attr))
360 util_send (" \\Deleted"); 355 {
356 util_send ("\\Deleted");
357 space = 1;
358 }
361 if (attribute_is_answered (attr)) 359 if (attribute_is_answered (attr))
362 util_send (" \\Answered"); 360 {
361 if (space)
362 util_send (" ");
363 util_send ("\\Answered");
364 space = 1;
365 }
363 if (attribute_is_flagged (attr)) 366 if (attribute_is_flagged (attr))
364 util_send (" \\Flagged"); 367 {
368 if (space)
369 util_send (" ");
370 util_send ("\\Flagged");
371 space = 1;
372 }
365 if (attribute_is_seen (attr) && attribute_is_read (attr)) 373 if (attribute_is_seen (attr) && attribute_is_read (attr))
366 util_send (" \\Seen"); 374 {
375 if (space)
376 util_send (" ");
377 util_send ("\\Seen");
378 space = 1;
379 }
367 if (attribute_is_draft (attr)) 380 if (attribute_is_draft (attr))
368 util_send (" \\Draft"); 381 {
369 util_send (" )"); 382 if (space)
383 util_send (" ");
384 util_send (" \\Draft");
385 }
386 util_send (")");
370 return RESP_OK; 387 return RESP_OK;
371 } 388 }
372 389
...@@ -376,13 +393,6 @@ static const char *MONTHS[] = ...@@ -376,13 +393,6 @@ static const char *MONTHS[] =
376 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 393 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
377 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 394 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
378 }; 395 };
379 #if 0
380 /* The week day is recompute by mktime(). */
381 static const char *WEEKDAYS[] =
382 {
383 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
384 };
385 #endif
386 396
387 static const char * 397 static const char *
388 get_timezone (const struct tm *tptr) 398 get_timezone (const struct tm *tptr)
...@@ -419,12 +429,10 @@ fetch_internaldate (struct fetch_command *command, char *arg) ...@@ -419,12 +429,10 @@ fetch_internaldate (struct fetch_command *command, char *arg)
419 { 429 {
420 char date[512]; 430 char date[512];
421 envelope_t env = NULL; 431 envelope_t env = NULL;
422 message_t msg = NULL;
423 struct tm tm; 432 struct tm tm;
424 struct tm *tptr; 433 struct tm *tptr;
425 (void)arg; 434 (void)arg;
426 mailbox_get_message (mbox, command->msgno, &msg); 435 message_get_envelope (command->msg, &env);
427 message_get_envelope (msg, &env);
428 date[0] = '\0'; 436 date[0] = '\0';
429 envelope_date (env, date, sizeof (date), NULL); 437 envelope_date (env, date, sizeof (date), NULL);
430 { 438 {
...@@ -452,17 +460,6 @@ fetch_internaldate (struct fetch_command *command, char *arg) ...@@ -452,17 +460,6 @@ fetch_internaldate (struct fetch_command *command, char *arg)
452 break; 460 break;
453 } 461 }
454 } 462 }
455 /* No need the week day is recompute by mktime. */
456 #if 0
457 for (i = 0; i < 7; i++)
458 {
459 if (strncasecmp(wday, WEEKDAYS[i], 3) == 0)
460 {
461 /* day = i; */
462 break;
463 }
464 }
465 #endif
466 tm.tm_mday = day; 463 tm.tm_mday = day;
467 tm.tm_mon = mon; 464 tm.tm_mon = mon;
468 tm.tm_year = (year > 1900) ? year - 1900 : year; 465 tm.tm_year = (year > 1900) ? year - 1900 : year;
...@@ -482,8 +479,6 @@ fetch_internaldate (struct fetch_command *command, char *arg) ...@@ -482,8 +479,6 @@ fetch_internaldate (struct fetch_command *command, char *arg)
482 } 479 }
483 strftime (date, sizeof (date), "%d-%b-%Y %X", &tm); 480 strftime (date, sizeof (date), "%d-%b-%Y %X", &tm);
484 util_send ("%s", command->name); 481 util_send ("%s", command->name);
485 if (date[strlen (date) - 1] == '\n')
486 date[strlen (date) - 1] = '\0';
487 util_send (" \"%s %s\"", date, get_timezone (&tm)); 482 util_send (" \"%s %s\"", date, get_timezone (&tm));
488 return RESP_OK; 483 return RESP_OK;
489 } 484 }
...@@ -496,7 +491,7 @@ fetch_rfc822_header (struct fetch_command *command, char *arg) ...@@ -496,7 +491,7 @@ fetch_rfc822_header (struct fetch_command *command, char *arg)
496 (void)arg; 491 (void)arg;
497 util_send ("%s ", command->name); 492 util_send ("%s ", command->name);
498 strcpy (buffer, "[HEADER]"); 493 strcpy (buffer, "[HEADER]");
499 fetch_operation (command->msgno, buffer, 1); 494 fetch_operation (command->msg, buffer, 1);
500 return RESP_OK; 495 return RESP_OK;
501 } 496 }
502 497
...@@ -506,10 +501,8 @@ fetch_rfc822_text (struct fetch_command *command, char *arg) ...@@ -506,10 +501,8 @@ fetch_rfc822_text (struct fetch_command *command, char *arg)
506 { 501 {
507 char buffer[16]; 502 char buffer[16];
508 attribute_t attr = NULL; 503 attribute_t attr = NULL;
509 message_t msg = NULL;
510 (void)arg; 504 (void)arg;
511 mailbox_get_message (mbox, command->msgno, &msg); 505 message_get_attribute (command->msg, &attr);
512 message_get_attribute (msg, &attr);
513 if (!attribute_is_seen (attr) && !attribute_is_read (attr)) 506 if (!attribute_is_seen (attr) && !attribute_is_read (attr))
514 { 507 {
515 util_send ("FLAGS (\\Seen) "); 508 util_send ("FLAGS (\\Seen) ");
...@@ -518,7 +511,7 @@ fetch_rfc822_text (struct fetch_command *command, char *arg) ...@@ -518,7 +511,7 @@ fetch_rfc822_text (struct fetch_command *command, char *arg)
518 } 511 }
519 util_send ("%s ", command->name); 512 util_send ("%s ", command->name);
520 strcpy (buffer, "[TEXT]"); 513 strcpy (buffer, "[TEXT]");
521 fetch_operation (command->msgno, buffer, 1); 514 fetch_operation (command->msg, buffer, 1);
522 return RESP_OK; 515 return RESP_OK;
523 } 516 }
524 517
...@@ -528,11 +521,9 @@ fetch_rfc822_size (struct fetch_command *command, char *arg) ...@@ -528,11 +521,9 @@ fetch_rfc822_size (struct fetch_command *command, char *arg)
528 { 521 {
529 size_t size = 0; 522 size_t size = 0;
530 size_t lines = 0; 523 size_t lines = 0;
531 message_t msg = NULL;
532 (void)arg; 524 (void)arg;
533 mailbox_get_message (mbox, command->msgno, &msg); 525 message_size (command->msg, &size);
534 message_size (msg, &size); 526 message_lines (command->msg, &lines);
535 message_lines (msg, &lines);
536 util_send ("%s %u", command->name, size + lines); 527 util_send ("%s %u", command->name, size + lines);
537 return RESP_OK; 528 return RESP_OK;
538 } 529 }
...@@ -546,19 +537,19 @@ fetch_rfc822 (struct fetch_command *command, char *arg) ...@@ -546,19 +537,19 @@ fetch_rfc822 (struct fetch_command *command, char *arg)
546 if (strncasecmp (arg, ".SIZE", 5) == 0) 537 if (strncasecmp (arg, ".SIZE", 5) == 0)
547 { 538 {
548 struct fetch_command c_rfc= fetch_command_table[F_RFC822_SIZE]; 539 struct fetch_command c_rfc= fetch_command_table[F_RFC822_SIZE];
549 c_rfc.msgno = command->msgno; 540 c_rfc.msg = command->msg;
550 fetch_rfc822_size (&c_rfc, arg); 541 fetch_rfc822_size (&c_rfc, arg);
551 } 542 }
552 else if (strncasecmp (arg, ".TEXT", 5) == 0) 543 else if (strncasecmp (arg, ".TEXT", 5) == 0)
553 { 544 {
554 struct fetch_command c_rfc = fetch_command_table[F_RFC822_TEXT]; 545 struct fetch_command c_rfc = fetch_command_table[F_RFC822_TEXT];
555 c_rfc.msgno = command->msgno; 546 c_rfc.msg = command->msg;
556 fetch_rfc822_text (&c_rfc, arg); 547 fetch_rfc822_text (&c_rfc, arg);
557 } 548 }
558 else if (strncasecmp (arg, ".HEADER", 7) == 0) 549 else if (strncasecmp (arg, ".HEADER", 7) == 0)
559 { 550 {
560 struct fetch_command c_rfc = fetch_command_table[F_RFC822_HEADER]; 551 struct fetch_command c_rfc = fetch_command_table[F_RFC822_HEADER];
561 c_rfc.msgno = command->msgno; 552 c_rfc.msg = command->msg;
562 fetch_rfc822_header (&c_rfc, arg); 553 fetch_rfc822_header (&c_rfc, arg);
563 } 554 }
564 } 555 }
...@@ -566,9 +557,7 @@ fetch_rfc822 (struct fetch_command *command, char *arg) ...@@ -566,9 +557,7 @@ fetch_rfc822 (struct fetch_command *command, char *arg)
566 { 557 {
567 char buffer[16]; 558 char buffer[16];
568 attribute_t attr = NULL; 559 attribute_t attr = NULL;
569 message_t msg = NULL; 560 message_get_attribute (command->msg, &attr);
570 mailbox_get_message (mbox, command->msgno, &msg);
571 message_get_attribute (msg, &attr);
572 if (!attribute_is_seen (attr) && !attribute_is_read (attr)) 561 if (!attribute_is_seen (attr) && !attribute_is_read (attr))
573 { 562 {
574 util_send ("FLAGS (\\Seen) "); 563 util_send ("FLAGS (\\Seen) ");
...@@ -577,7 +566,7 @@ fetch_rfc822 (struct fetch_command *command, char *arg) ...@@ -577,7 +566,7 @@ fetch_rfc822 (struct fetch_command *command, char *arg)
577 } 566 }
578 util_send ("%s ", command->name); 567 util_send ("%s ", command->name);
579 strcpy (buffer, "[]"); 568 strcpy (buffer, "[]");
580 fetch_operation (command->msgno, buffer, 1); 569 fetch_operation (command->msg, buffer, 1);
581 } 570 }
582 return RESP_OK; 571 return RESP_OK;
583 } 572 }
...@@ -587,10 +576,8 @@ static int ...@@ -587,10 +576,8 @@ static int
587 fetch_uid (struct fetch_command *command, char *arg) 576 fetch_uid (struct fetch_command *command, char *arg)
588 { 577 {
589 size_t uid = 0; 578 size_t uid = 0;
590 message_t msg = NULL;
591 (void)arg; 579 (void)arg;
592 mailbox_get_message (mbox, command->msgno, &msg); 580 message_get_uid (command->msg, &uid);
593 message_get_uid (msg, &uid);
594 util_send ("%s %d", command->name, uid); 581 util_send ("%s %d", command->name, uid);
595 return RESP_OK; 582 return RESP_OK;
596 } 583 }
...@@ -598,11 +585,9 @@ fetch_uid (struct fetch_command *command, char *arg) ...@@ -598,11 +585,9 @@ fetch_uid (struct fetch_command *command, char *arg)
598 static int 585 static int
599 fetch_bodystructure (struct fetch_command *command, char *arg) 586 fetch_bodystructure (struct fetch_command *command, char *arg)
600 { 587 {
601 message_t message = NULL;
602 (void)arg; 588 (void)arg;
603 util_send ("%s (", command->name); 589 util_send ("%s (", command->name);
604 mailbox_get_message (mbox, command->msgno, &message); 590 fetch_bodystructure0 (command->msg, 1);
605 fetch_bodystructure0 (message, 1);
606 util_send (")"); 591 util_send (")");
607 return RESP_OK; 592 return RESP_OK;
608 } 593 }
...@@ -632,7 +617,7 @@ fetch_bodystructure0 (message_t message, int extension) ...@@ -632,7 +617,7 @@ fetch_bodystructure0 (message_t message, int extension)
632 char *buffer = NULL; 617 char *buffer = NULL;
633 char *sp = NULL; 618 char *sp = NULL;
634 char *s; 619 char *s;
635 /* The subtype. */ 620 /* The subtype. */
636 message_get_header (message, &header); 621 message_get_header (message, &header);
637 header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer); 622 header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer);
638 s = strtok_r (buffer, " \t\r\n;", &sp); 623 s = strtok_r (buffer, " \t\r\n;", &sp);
...@@ -647,39 +632,50 @@ fetch_bodystructure0 (message_t message, int extension) ...@@ -647,39 +632,50 @@ fetch_bodystructure0 (message_t message, int extension)
647 /* Content-type parameter list. */ 632 /* Content-type parameter list. */
648 util_send (" ("); 633 util_send (" (");
649 { 634 {
635 int space = 0;
650 while ((s = strtok_r (NULL, " \t\r\n;", &sp))) 636 while ((s = strtok_r (NULL, " \t\r\n;", &sp)))
651 { 637 {
652 char *p = strchr (s, '='); 638 char *p = strchr (s, '=');
653 if (p) 639 if (p)
654 *p++ = '\0'; 640 *p++ = '\0';
641 if (space)
642 util_send (" ");
655 util_send ("\"%s\"", s); 643 util_send ("\"%s\"", s);
656 util_send (" \"%s\"", (p) ? p : "NIL"); 644 if (p)
645 util_send (" \"%s\"", p);
646 space = 1;
657 } 647 }
658 } 648 }
649 util_send (")");
659 free (buffer); 650 free (buffer);
660 /* Content-Disposition. */ 651 /* Content-Disposition. */
661 header_aget_value (header, MU_HEADER_CONTENT_DISPOSITION, &buffer); 652 header_aget_value (header, MU_HEADER_CONTENT_DISPOSITION, &buffer);
662 if (*buffer) 653 if (*buffer)
663 { 654 {
655 char *t = buffer;
664 util_send (" ("); 656 util_send (" (");
665 while ((s = strtok_r (buffer, " \t\r\n;", &sp))) 657 while ((s = strtok_r (t, " \t\r\n;", &sp)))
666 { 658 {
667 char *p = strchr (s, '='); 659 char *p = strchr (s, '=');
668 if (p) 660 if (p)
669 *p++ = '\0'; 661 *p++ = '\0';
662 if (t == NULL)
663 util_send (" ");
670 util_send ("\"%s\"", s); 664 util_send ("\"%s\"", s);
671 util_send (" \"%s\"", (p) ? p : "NIL"); 665 if (p)
666 util_send (" \"%s\"", (p) ? p : "NIL");
667 t = NULL;
672 } 668 }
669 util_send (")");
673 } 670 }
674 else 671 else
675 util_send (" NIL"); 672 util_send (" NIL");
676 free (buffer); 673 free (buffer);
677 /* Content-Language. */ 674 /* Content-Language. */
678 header_aget_value (header, MU_HEADER_CONTENT_LANGUAGE, &buffer); 675 header_aget_value (header, MU_HEADER_CONTENT_LANGUAGE, &buffer);
679 if (*buffer) 676 util_send (" ");
680 util_send (" \"%s\"", buffer); 677 util_send_string (buffer);
681 else 678 free (buffer);
682 util_send (" NIL");
683 } /* extension */ 679 } /* extension */
684 } 680 }
685 else 681 else
...@@ -726,11 +722,14 @@ bodystructure (message_t msg, int extension) ...@@ -726,11 +722,14 @@ bodystructure (message_t msg, int extension)
726 util_send (" ("); 722 util_send (" (");
727 { 723 {
728 int have_charset = 0; 724 int have_charset = 0;
725 int space = 0;
729 while ((s = strtok_r (NULL, " \t\r\n;", &sp))) 726 while ((s = strtok_r (NULL, " \t\r\n;", &sp)))
730 { 727 {
731 char *p = strchr (s, '='); 728 char *p = strchr (s, '=');
732 if (p) 729 if (p)
733 *p++ = '\0'; 730 *p++ = '\0';
731 if (space)
732 util_send (" ");
734 util_send ("\"%s\"", s); 733 util_send ("\"%s\"", s);
735 util_send (" \"%s\"", (p) ? p : "NIL"); 734 util_send (" \"%s\"", (p) ? p : "NIL");
736 if (strcasecmp (s, "charset") == 0) 735 if (strcasecmp (s, "charset") == 0)
...@@ -748,23 +747,20 @@ bodystructure (message_t msg, int extension) ...@@ -748,23 +747,20 @@ bodystructure (message_t msg, int extension)
748 747
749 /* Content-ID. */ 748 /* Content-ID. */
750 header_aget_value (header, MU_HEADER_CONTENT_ID, &buffer); 749 header_aget_value (header, MU_HEADER_CONTENT_ID, &buffer);
751 if (*buffer) 750 util_send (" ");
752 util_send (" \"%s\"", buffer); 751 util_send_string (buffer);
753 else
754 util_send (" NIL");
755 free (buffer); 752 free (buffer);
756 753
757 /* Content-Description. */ 754 /* Content-Description. */
758 header_aget_value (header, MU_HEADER_CONTENT_DESCRIPTION, &buffer); 755 header_aget_value (header, MU_HEADER_CONTENT_DESCRIPTION, &buffer);
759 if (*buffer) 756 util_send (" ");
760 util_send (" \"%s\"", buffer); 757 util_send_string (buffer);
761 else
762 util_send (" NIL");
763 free (buffer); 758 free (buffer);
764 759
765 /* Content-Transfer-Encoding. */ 760 /* Content-Transfer-Encoding. */
766 header_aget_value (header, MU_HEADER_CONTENT_TRANSFER_ENCODING, &buffer); 761 header_aget_value (header, MU_HEADER_CONTENT_TRANSFER_ENCODING, &buffer);
767 util_send (" \"%s\"", (*buffer) ? buffer : "7bit"); 762 util_send (" ");
763 util_send_string ((*buffer) ? buffer : "7BIT");
768 free (buffer); 764 free (buffer);
769 765
770 /* Body size RFC822 format. */ 766 /* Body size RFC822 format. */
...@@ -803,34 +799,35 @@ bodystructure (message_t msg, int extension) ...@@ -803,34 +799,35 @@ bodystructure (message_t msg, int extension)
803 { 799 {
804 /* Content-MD5. */ 800 /* Content-MD5. */
805 header_aget_value (header, MU_HEADER_CONTENT_MD5, &buffer); 801 header_aget_value (header, MU_HEADER_CONTENT_MD5, &buffer);
806 if (*buffer) 802 util_send (" ");
807 util_send (" \"%s\"", buffer); 803 util_send_string (buffer);
808 else
809 util_send (" NIL");
810 free (buffer); 804 free (buffer);
811 /* Content-Disposition. */ 805 /* Content-Disposition. */
812 header_aget_value (header, MU_HEADER_CONTENT_DISPOSITION, &buffer); 806 header_aget_value (header, MU_HEADER_CONTENT_DISPOSITION, &buffer);
813 if (*buffer) 807 if (*buffer)
814 { 808 {
809 char *t = buffer;
815 util_send (" ("); 810 util_send (" (");
816 while ((s = strtok_r (buffer, " \t\r\n;", &sp))) 811 while ((s = strtok_r (t, " \t\r\n;", &sp)))
817 { 812 {
818 char *p = strchr (s, '='); 813 char *p = strchr (s, '=');
819 if (p) 814 if (p)
820 *p++ = '\0'; 815 *p++ = '\0';
816 if (t == NULL)
817 util_send (" ");
821 util_send ("\"%s\"", s); 818 util_send ("\"%s\"", s);
822 util_send (" \"%s\"", (p) ? p : "NIL"); 819 util_send (" \"%s\"", (p) ? p : "NIL");
820 t = NULL;
823 } 821 }
822 util_send (")");
824 } 823 }
825 else 824 else
826 util_send (" NIL"); 825 util_send (" NIL");
827 free (buffer); 826 free (buffer);
828 /* Content-Language. */ 827 /* Content-Language. */
829 header_aget_value (header, MU_HEADER_CONTENT_LANGUAGE, &buffer); 828 header_aget_value (header, MU_HEADER_CONTENT_LANGUAGE, &buffer);
830 if (*buffer) 829 util_send (" ");
831 util_send (" \"%s\"", buffer); 830 util_send_string (buffer);
832 else
833 util_send (" NIL");
834 free (buffer); 831 free (buffer);
835 } 832 }
836 return RESP_OK; 833 return RESP_OK;
...@@ -843,10 +840,8 @@ fetch_body (struct fetch_command *command, char *arg) ...@@ -843,10 +840,8 @@ fetch_body (struct fetch_command *command, char *arg)
843 /* It's BODY set the message as seen */ 840 /* It's BODY set the message as seen */
844 if (*arg == '[') 841 if (*arg == '[')
845 { 842 {
846 message_t msg = NULL;
847 attribute_t attr = NULL; 843 attribute_t attr = NULL;
848 mailbox_get_message (mbox, command->msgno, &msg); 844 message_get_attribute (command->msg, &attr);
849 message_get_attribute (msg, &attr);
850 if (!attribute_is_seen (attr) && !attribute_is_read (attr)) 845 if (!attribute_is_seen (attr) && !attribute_is_read (attr))
851 { 846 {
852 util_send ("FLAGS (\\Seen) "); 847 util_send ("FLAGS (\\Seen) ");
...@@ -863,24 +858,21 @@ fetch_body (struct fetch_command *command, char *arg) ...@@ -863,24 +858,21 @@ fetch_body (struct fetch_command *command, char *arg)
863 } 858 }
864 else if (*arg != '[' && *arg != '.') 859 else if (*arg != '[' && *arg != '.')
865 { 860 {
866 message_t message = NULL;
867 mailbox_get_message (mbox, command->msgno, &message);
868 /* Call body structure without the extension. */ 861 /* Call body structure without the extension. */
869 util_send ("%s (", command->name); 862 util_send ("%s (", command->name);
870 fetch_bodystructure0 (message, 0); 863 fetch_bodystructure0 (command->msg, 0);
871 util_send (")"); 864 util_send (")");
872 return RESP_OK; 865 return RESP_OK;
873 } 866 }
874 util_send ("%s", command->name); 867 util_send ("%s", command->name);
875 return fetch_operation (command->msgno, arg, 0); 868 return fetch_operation (command->msg, arg, 0);
876 } 869 }
877 870
878 static int 871 static int
879 fetch_operation (size_t msgno, char *arg, int silent) 872 fetch_operation (message_t msg, char *arg, int silent)
880 { 873 {
881 unsigned long start = ULONG_MAX; 874 unsigned long start = ULONG_MAX;
882 unsigned long end = ULONG_MAX; /* No limit. */ 875 unsigned long end = ULONG_MAX; /* No limit. */
883 message_t msg = NULL;
884 char *partial = strchr (arg, '<'); 876 char *partial = strchr (arg, '<');
885 877
886 /* Check for section specific offset. */ 878 /* Check for section specific offset. */
...@@ -898,8 +890,6 @@ fetch_operation (size_t msgno, char *arg, int silent) ...@@ -898,8 +890,6 @@ fetch_operation (size_t msgno, char *arg, int silent)
898 } 890 }
899 } 891 }
900 892
901 mailbox_get_message (mbox, msgno, &msg);
902
903 /* Retreive the sub message. */ 893 /* Retreive the sub message. */
904 for (arg++; isdigit ((unsigned)*arg) || *arg == '.'; arg++) 894 for (arg++; isdigit ((unsigned)*arg) || *arg == '.'; arg++)
905 { 895 {
......
...@@ -175,6 +175,7 @@ extern int imap4d_bye __P ((int)); ...@@ -175,6 +175,7 @@ extern int imap4d_bye __P ((int));
175 /* Helper functions. */ 175 /* Helper functions. */
176 extern int util_out __P ((int, const char *, ...)); 176 extern int util_out __P ((int, const char *, ...));
177 extern int util_send __P ((const char *, ...)); 177 extern int util_send __P ((const char *, ...));
178 extern int util_send_string __P ((const char *));
178 extern int util_start __P ((char *)); 179 extern int util_start __P ((char *));
179 extern int util_finish __P ((struct imap4d_command *, int, const char *, ...)); 180 extern int util_finish __P ((struct imap4d_command *, int, const char *, ...));
180 extern int util_getstate __P ((void)); 181 extern int util_getstate __P ((void));
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
18 #include "imap4d.h" 18 #include "imap4d.h"
19 #include <ctype.h> 19 #include <ctype.h>
20 20
21 static int add2set __P ((size_t **, int *, unsigned long, size_t)); 21 static int add2set __P ((size_t **, int *, unsigned long));
22 static const char *sc2string __P ((int)); 22 static const char *sc2string __P ((int));
23 23
24 /* Get the next space/CR/NL separated word, some words are between double 24 /* Get the next space/CR/NL separated word, some words are between double
...@@ -184,9 +184,6 @@ util_msgset (char *s, size_t **set, int *n, int isuid) ...@@ -184,9 +184,6 @@ util_msgset (char *s, size_t **set, int *n, int isuid)
184 status = mailbox_messages_count (mbox, &max); 184 status = mailbox_messages_count (mbox, &max);
185 if (status != 0) 185 if (status != 0)
186 return status; 186 return status;
187 /* The number after the "*" in an untagged FETCH response is always a
188 message sequence number, not a unique identifier, even for a UID
189 command response. But do what they meant not what they say. */
190 /* If it is a uid sequence, override max with the UID. */ 187 /* If it is a uid sequence, override max with the UID. */
191 if (isuid) 188 if (isuid)
192 { 189 {
...@@ -216,9 +213,23 @@ util_msgset (char *s, size_t **set, int *n, int isuid) ...@@ -216,9 +213,23 @@ util_msgset (char *s, size_t **set, int *n, int isuid)
216 } 213 }
217 if (low) 214 if (low)
218 { 215 {
216 /* Reverse it. */
217 if (low > val)
218 {
219 long tmp = low;
220 tmp -= 2;
221 if (tmp <= 0 || val == 0)
222 {
223 free (*set);
224 *n = 0;
225 return EINVAL;
226 }
227 low = val;
228 val = tmp;
229 }
219 for (;low && low <= val; low++) 230 for (;low && low <= val; low++)
220 { 231 {
221 status = add2set (set, n, low, max); 232 status = add2set (set, n, low);
222 if (status != 0) 233 if (status != 0)
223 return status; 234 return status;
224 } 235 }
...@@ -226,7 +237,7 @@ util_msgset (char *s, size_t **set, int *n, int isuid) ...@@ -226,7 +237,7 @@ util_msgset (char *s, size_t **set, int *n, int isuid)
226 } 237 }
227 else 238 else
228 { 239 {
229 status = add2set(set, n, val, max); 240 status = add2set(set, n, val);
230 if (status != 0) 241 if (status != 0)
231 return status; 242 return status;
232 } 243 }
...@@ -284,9 +295,23 @@ util_msgset (char *s, size_t **set, int *n, int isuid) ...@@ -284,9 +295,23 @@ util_msgset (char *s, size_t **set, int *n, int isuid)
284 295
285 if (low) 296 if (low)
286 { 297 {
298 /* Reverse it. */
299 if (low > val)
300 {
301 long tmp = low;
302 tmp -= 2;
303 if (tmp <= 0 || val == 0)
304 {
305 free (set);
306 *n = 0;
307 return EINVAL;
308 }
309 low = val;
310 val = tmp;
311 }
287 for (;low && low <= val; low++) 312 for (;low && low <= val; low++)
288 { 313 {
289 status = add2set (set, n, low, max); 314 status = add2set (set, n, low);
290 if (status != 0) 315 if (status != 0)
291 return status; 316 return status;
292 } 317 }
...@@ -306,6 +331,18 @@ util_send (const char *format, ...) ...@@ -306,6 +331,18 @@ util_send (const char *format, ...)
306 return status; 331 return status;
307 } 332 }
308 333
334 /* Send NIL if empty string, a literal if the string contains double quotes
335 or the string surrounded by double quotes. */
336 int
337 util_send_string (const char *buffer)
338 {
339 if (*buffer == '\0')
340 return util_send ("NIL");
341 if (strchr (buffer, '"'))
342 return util_send ("{%u}\r\n%s", strlen (buffer), buffer);
343 return util_send ("\"%s\"", buffer);
344 }
345
309 /* Send an unsolicited response. */ 346 /* Send an unsolicited response. */
310 int 347 int
311 util_out (int rc, const char *format, ...) 348 util_out (int rc, const char *format, ...)
...@@ -417,7 +454,7 @@ imap4d_readline (FILE *fp) ...@@ -417,7 +454,7 @@ imap4d_readline (FILE *fp)
417 } 454 }
418 } 455 }
419 while (number > 0); 456 while (number > 0);
420 /* syslog (LOG_INFO, "readline: %s", line); */ 457 syslog (LOG_INFO, "readline: %s", line);
421 return line; 458 return line;
422 } 459 }
423 460
...@@ -522,11 +559,11 @@ sc2string (int rc) ...@@ -522,11 +559,11 @@ sc2string (int rc)
522 } 559 }
523 560
524 static int 561 static int
525 add2set (size_t **set, int *n, unsigned long val, size_t max) 562 add2set (size_t **set, int *n, unsigned long val)
526 { 563 {
527 int *tmp; 564 int *tmp;
528 if (val == 0 || val > max 565 tmp = realloc (*set, (*n + 1) * sizeof (**set));
529 || (tmp = realloc (*set, (*n + 1) * sizeof (**set))) == NULL) 566 if (tmp == NULL)
530 { 567 {
531 if (*set) 568 if (*set)
532 free (*set); 569 free (*set);
......