Fix parsing universal time zone in mailmbox
[claws.git] / src / plugins / mailmbox / mailimf.c
1 /*
2  * libEtPan! -- a mail stuff library
3  *
4  * Copyright (C) 2001, 2002 - DINH Viet Hoa
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the libEtPan! project nor the names of its
16  *    contributors may be used to endorse or promote products derived
17  *    from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 /*
33  * $Id$
34  */
35
36 #include "mailimf.h"
37
38 /*
39   RFC 2822
40
41   RFC 2821 ... 
42    A message-originating SMTP system SHOULD NOT send a message that
43    already contains a Return-path header.  SMTP servers performing a
44    relay function MUST NOT inspect the message data, and especially not
45    to the extent needed to determine if Return-path headers are present.
46    SMTP servers making final delivery MAY remove Return-path headers
47    before adding their own.
48 */
49
50 #include <ctype.h>
51 #include <mmapstring.h>
52 #include <stdlib.h>
53 #include <string.h>
54
55 #ifndef TRUE
56 #define TRUE 1
57 #endif
58
59 #ifndef FALSE
60 #define FALSE 0
61 #endif
62
63
64
65
66
67
68
69 static inline int is_dtext(char ch);
70
71 static int mailimf_quoted_pair_parse(const char * message, size_t length,
72                                      size_t * index, char * result);
73
74 static int mailimf_ccontent_parse(const char * message, size_t length,
75                                   size_t * index);
76
77 static int
78 mailimf_comment_fws_ccontent_parse(const char * message, size_t length,
79                                    size_t * index);
80
81 static inline int mailimf_comment_parse(const char * message, size_t length,
82                                  size_t * index);
83
84 static int mailimf_qcontent_parse(const char * message, size_t length,
85                                   size_t * index, char * ch);
86
87 static int mailimf_phrase_parse(const char * message, size_t length,
88                                 size_t * index, char ** result);
89
90 static int mailimf_unstructured_parse(const char * message, size_t length,
91                                       size_t * index, char ** result);
92
93 static int mailimf_ignore_unstructured_parse(const char * message, size_t length,
94                                              size_t * index);
95
96 static int mailimf_day_of_week_parse(const char * message, size_t length,
97                                      size_t * index, int * result);
98
99 static int mailimf_day_name_parse(const char * message, size_t length,
100                                   size_t * index, int * result);
101
102 static int mailimf_date_parse(const char * message, size_t length,
103                               size_t * index,
104                               int * pday, int * pmonth, int * pyear);
105
106 static int mailimf_year_parse(const char * message, size_t length,
107                               size_t * index, int * result);
108
109 static int mailimf_month_parse(const char * message, size_t length,
110                                size_t * index, int * result);
111
112 static int mailimf_month_name_parse(const char * message, size_t length,
113                                     size_t * index, int * result);
114
115 static int mailimf_day_parse(const char * message, size_t length,
116                                   size_t * index, int * result);
117
118 static int mailimf_time_parse(const char * message, size_t length,
119                               size_t * index, 
120                               int * phour, int * pmin,
121                               int * psec,
122                               int * zone);
123 static int mailimf_time_of_day_parse(const char * message, size_t length,
124                                      size_t * index,
125                                      int * phour, int * pmin,
126                                      int * psec);
127
128 static int mailimf_hour_parse(const char * message, size_t length,
129                               size_t * index, int * result);
130
131 static int mailimf_minute_parse(const char * message, size_t length,
132                                 size_t * index, int * result);
133
134 static int mailimf_second_parse(const char * message, size_t length,
135                                 size_t * index, int * result);
136
137 static int mailimf_zone_parse(const char * message, size_t length,
138                               size_t * index, int * result);
139
140 static int mailimf_name_addr_parse(const char * message, size_t length,
141                                    size_t * index,
142                                    char ** pdisplay_name,
143                                    char ** pangle_addr);
144
145 static int mailimf_angle_addr_parse(const char * message, size_t length,
146                                     size_t * index, char ** result);
147
148 static int mailimf_group_parse(const char * message, size_t length,
149                                size_t * index,
150                                struct mailimf_group ** result);
151
152 static int mailimf_display_name_parse(const char * message, size_t length,
153                                       size_t * index, char ** result);
154
155 static int mailimf_addr_spec_parse(const char * message, size_t length,
156                                    size_t * index,
157                                    char ** address);
158
159 #if 0
160 static int mailimf_local_part_parse(const char * message, size_t length,
161                                     size_t * index,
162                                     char ** result);
163
164 static int mailimf_domain_parse(const char * message, size_t length,
165                                 size_t * index,
166                                 char ** result);
167 #endif
168
169 #if 0
170 static int mailimf_domain_literal_parse(const char * message, size_t length,
171                                         size_t * index, char ** result);
172 #endif
173
174 #if 0
175 static int mailimf_dcontent_parse(const char * message, size_t length,
176                                   size_t * index, char * result);
177 #endif
178
179 static int
180 mailimf_orig_date_parse(const char * message, size_t length,
181                         size_t * index, struct mailimf_orig_date ** result);
182
183 static int
184 mailimf_from_parse(const char * message, size_t length,
185                    size_t * index, struct mailimf_from ** result);
186
187 static int
188 mailimf_sender_parse(const char * message, size_t length,
189                      size_t * index, struct mailimf_sender ** result);
190
191 static int
192 mailimf_reply_to_parse(const char * message, size_t length,
193                        size_t * index, struct mailimf_reply_to ** result);
194
195 static int
196 mailimf_to_parse(const char * message, size_t length,
197                  size_t * index, struct mailimf_to ** result);
198
199 static int
200 mailimf_cc_parse(const char * message, size_t length,
201                  size_t * index, struct mailimf_cc ** result);
202
203 static int
204 mailimf_bcc_parse(const char * message, size_t length,
205                   size_t * index, struct mailimf_bcc ** result);
206
207 static int mailimf_message_id_parse(const char * message, size_t length,
208                                     size_t * index,
209                                     struct mailimf_message_id ** result);
210
211 static int
212 mailimf_in_reply_to_parse(const char * message, size_t length,
213                           size_t * index,
214                           struct mailimf_in_reply_to ** result);
215
216 #if 0
217 static int mailimf_references_parse(const char * message, size_t length,
218                                     size_t * index,
219                                     struct mailimf_references **
220                                     result);
221 #endif
222
223 static int mailimf_unstrict_msg_id_parse(const char * message, size_t length,
224                                          size_t * index,
225                                          char ** result);
226
227 #if 0
228 static int mailimf_id_left_parse(const char * message, size_t length,
229                                  size_t * index, char ** result);
230
231 static int mailimf_id_right_parse(const char * message, size_t length,
232                                   size_t * index, char ** result);
233 #endif
234
235 #if 0
236 static int mailimf_no_fold_quote_parse(const char * message, size_t length,
237                                        size_t * index, char ** result);
238
239 static int mailimf_no_fold_literal_parse(const char * message, size_t length,
240                                          size_t * index, char ** result);
241 #endif
242
243 static int mailimf_subject_parse(const char * message, size_t length,
244                                  size_t * index,
245                                  struct mailimf_subject ** result);
246
247 static int mailimf_comments_parse(const char * message, size_t length,
248                                   size_t * index,
249                                   struct mailimf_comments ** result);
250
251 static int mailimf_keywords_parse(const char * message, size_t length,
252                                   size_t * index,
253                                   struct mailimf_keywords ** result);
254
255 static int
256 mailimf_resent_date_parse(const char * message, size_t length,
257                           size_t * index, struct mailimf_orig_date ** result);
258
259 static int
260 mailimf_resent_from_parse(const char * message, size_t length,
261                           size_t * index, struct mailimf_from ** result);
262
263 static int
264 mailimf_resent_sender_parse(const char * message, size_t length,
265                             size_t * index, struct mailimf_sender ** result);
266
267 static int
268 mailimf_resent_to_parse(const char * message, size_t length,
269                         size_t * index, struct mailimf_to ** result);
270
271 static int
272 mailimf_resent_cc_parse(const char * message, size_t length,
273                         size_t * index, struct mailimf_cc ** result);
274
275 static int
276 mailimf_resent_bcc_parse(const char * message, size_t length,
277                          size_t * index, struct mailimf_bcc ** result);
278
279 static int
280 mailimf_resent_msg_id_parse(const char * message, size_t length,
281                             size_t * index,
282                             struct mailimf_message_id ** result);
283
284 static int mailimf_return_parse(const char * message, size_t length,
285                                 size_t * index,
286                                 struct mailimf_return ** result);
287
288 static int
289 mailimf_path_parse(const char * message, size_t length,
290                    size_t * index, struct mailimf_path ** result);
291
292 static int
293 mailimf_optional_field_parse(const char * message, size_t length,
294                              size_t * index,
295                              struct mailimf_optional_field ** result);
296
297 static int mailimf_field_name_parse(const char * message, size_t length,
298                                     size_t * index, char ** result);
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324 /* *************************************************************** */
325
326 static inline int is_digit(char ch)
327 {
328   return (ch >= '0') && (ch <= '9');
329 }
330
331 static int mailimf_digit_parse(const char * message, size_t length,
332                                size_t * index, int * result)
333 {
334   size_t cur_token;
335
336   cur_token = * index;
337   
338   if (cur_token >= length)
339     return MAILIMF_ERROR_PARSE;
340
341   if (is_digit(message[cur_token])) {
342     * result = message[cur_token] - '0';
343     cur_token ++;
344     * index = cur_token;
345     return MAILIMF_NO_ERROR;
346   }
347   else
348     return MAILIMF_ERROR_PARSE;
349 }
350
351 int
352 mailimf_number_parse(const char * message, size_t length,
353                      size_t * index, uint32_t * result)
354 {
355   size_t cur_token;
356   int digit;
357   uint32_t number;
358   int parsed;
359   int r;
360
361   cur_token = * index;
362   parsed = FALSE;
363
364   number = 0;
365   while (1) {
366     r = mailimf_digit_parse(message, length, &cur_token, &digit);
367     if (r != MAILIMF_NO_ERROR) {
368       if (r == MAILIMF_ERROR_PARSE)
369         break;
370       else
371         return r;
372     }
373     number *= 10;
374     number += digit;
375     parsed = TRUE;
376   }
377
378   if (!parsed)
379     return MAILIMF_ERROR_PARSE;
380
381   * result = number;
382   * index = cur_token;
383
384   return MAILIMF_NO_ERROR;
385 }
386
387 int mailimf_char_parse(const char * message, size_t length,
388                        size_t * index, char token)
389 {
390   size_t cur_token;
391
392   cur_token = * index;
393
394   if (cur_token >= length)
395     return MAILIMF_ERROR_PARSE;
396
397   if (message[cur_token] == token) {
398     cur_token ++;
399     * index = cur_token;
400     return MAILIMF_NO_ERROR;
401   }
402   else
403     return MAILIMF_ERROR_PARSE;
404 }
405
406 int mailimf_unstrict_char_parse(const char * message, size_t length,
407                                 size_t * index, char token)
408 {
409   size_t cur_token;
410   int r;
411
412   cur_token = * index;
413
414   r = mailimf_cfws_parse(message, length, &cur_token);
415   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
416     return r;
417
418   r = mailimf_char_parse(message, length, &cur_token, token);
419   if (r != MAILIMF_NO_ERROR)
420     return r;
421   
422   * index = cur_token;
423
424   return MAILIMF_NO_ERROR;
425 }
426
427 int
428 mailimf_token_case_insensitive_len_parse(const char * message, size_t length,
429                                          size_t * index, char * token,
430                                          size_t token_length)
431 {
432   size_t cur_token;
433
434   cur_token = * index;
435
436   if (cur_token + token_length - 1 >= length)
437     return MAILIMF_ERROR_PARSE;
438
439   if (strncasecmp(message + cur_token, token, token_length) == 0) {
440     cur_token += token_length;
441     * index = cur_token;
442     return MAILIMF_NO_ERROR;
443   }
444   else
445     return MAILIMF_ERROR_PARSE;
446 }
447
448 static int mailimf_oparenth_parse(const char * message, size_t length,
449                                   size_t * index)
450 {
451   return mailimf_char_parse(message, length, index, '(');
452 }
453
454 static int mailimf_cparenth_parse(const char * message, size_t length,
455                                   size_t * index)
456 {
457   return mailimf_char_parse(message, length, index, ')');
458 }
459
460 static int mailimf_comma_parse(const char * message, size_t length,
461                                size_t * index)
462 {
463   return mailimf_unstrict_char_parse(message, length, index, ',');
464 }
465
466 static int mailimf_dquote_parse(const char * message, size_t length,
467                                 size_t * index)
468 {
469   return mailimf_char_parse(message, length, index, '\"');
470 }
471
472 static int mailimf_colon_parse(const char * message, size_t length,
473                                size_t * index)
474 {
475   return mailimf_unstrict_char_parse(message, length, index, ':');
476 }
477
478 static int mailimf_semi_colon_parse(const char * message, size_t length,
479                                     size_t * index)
480 {
481   return mailimf_unstrict_char_parse(message, length, index, ';');
482 }
483
484 static int mailimf_plus_parse(const char * message, size_t length,
485                               size_t * index)
486 {
487   return mailimf_unstrict_char_parse(message, length, index, '+');
488 }
489
490 static int mailimf_minus_parse(const char * message, size_t length,
491                                size_t * index)
492 {
493   return mailimf_unstrict_char_parse(message, length, index, '-');
494 }
495
496 static int mailimf_lower_parse(const char * message, size_t length,
497                                size_t * index)
498 {
499   return mailimf_unstrict_char_parse(message, length, index, '<');
500 }
501
502 static int mailimf_greater_parse(const char * message, size_t length,
503                                       size_t * index)
504 {
505   return mailimf_unstrict_char_parse(message, length, index, '>');
506 }
507
508 #if 0
509 static int mailimf_obracket_parse(const char * message, size_t length,
510                                        size_t * index)
511 {
512   return mailimf_unstrict_char_parse(message, length, index, '[');
513 }
514
515 static int mailimf_cbracket_parse(const char * message, size_t length,
516                                        size_t * index)
517 {
518   return mailimf_unstrict_char_parse(message, length, index, ']');
519 }
520 #endif
521
522 static int mailimf_at_sign_parse(const char * message, size_t length,
523                                       size_t * index)
524 {
525   return mailimf_unstrict_char_parse(message, length, index, '@');
526 }
527
528 static int mailimf_point_parse(const char * message, size_t length,
529                                       size_t * index)
530 {
531   return mailimf_unstrict_char_parse(message, length, index, '.');
532 }
533
534 int
535 mailimf_custom_string_parse(const char * message, size_t length,
536                             size_t * index, char ** result,
537                             int (* is_custom_char)(char))
538 {
539   size_t begin;
540   size_t end;
541   char * gstr;
542
543   begin = * index;
544
545   end = begin;
546
547   if (end >= length)
548     return MAILIMF_ERROR_PARSE;
549
550   while (is_custom_char(message[end])) {
551     end ++;
552     if (end >= length)
553       break;
554   }
555
556   if (end != begin) {
557     /*
558     gstr = strndup(message + begin, end - begin);
559     */
560     gstr = malloc(end - begin + 1);
561     if (gstr == NULL)
562       return MAILIMF_ERROR_MEMORY;
563     strncpy(gstr, message + begin, end - begin);
564     gstr[end - begin] = '\0';
565
566     * index = end;
567     * result = gstr;
568     return MAILIMF_NO_ERROR;
569   }
570   else
571     return MAILIMF_ERROR_PARSE;
572 }
573
574
575
576
577
578
579
580 typedef int mailimf_struct_parser(const char * message, size_t length,
581                                   size_t * index, void * result);
582
583 typedef int mailimf_struct_destructor(void * result);
584
585
586 static int
587 mailimf_struct_multiple_parse(const char * message, size_t length,
588                               size_t * index, clist ** result,
589                               mailimf_struct_parser * parser,
590                               mailimf_struct_destructor * destructor)
591 {
592   clist * struct_list;
593   size_t cur_token;
594   void * value;
595   int r;
596   int res;
597
598   cur_token = * index;
599
600   r = parser(message, length, &cur_token, &value);
601   if (r != MAILIMF_NO_ERROR) {
602     res = r;
603     goto err;
604   }
605
606   struct_list = clist_new();
607   if (struct_list == NULL) {
608     destructor(value);
609     res = MAILIMF_ERROR_MEMORY;
610     goto err;
611   }
612
613   r = clist_append(struct_list, value);
614   if (r < 0) {
615     destructor(value);
616     res = MAILIMF_ERROR_MEMORY;
617     goto free;
618   }
619
620   while (1) {
621     r = parser(message, length, &cur_token, &value);
622     if (r != MAILIMF_NO_ERROR) {
623       if (r == MAILIMF_ERROR_PARSE)
624         break;
625       else {
626         res = r;
627         goto free;
628       }
629     }
630     r = clist_append(struct_list, value);
631     if (r < 0) {
632       (* destructor)(value);
633       res = MAILIMF_ERROR_MEMORY;
634       goto free;
635     }
636   }
637
638   * result = struct_list;
639   * index = cur_token;
640   
641   return MAILIMF_NO_ERROR;
642
643  free:
644   clist_foreach(struct_list, (clist_func) destructor, NULL);
645   clist_free(struct_list);
646  err:
647   return res;
648 }
649
650
651
652 static int
653 mailimf_struct_list_parse(const char * message, size_t length,
654                           size_t * index, clist ** result,
655                           char symbol,
656                           mailimf_struct_parser * parser,
657                           mailimf_struct_destructor * destructor)
658 {
659   clist * struct_list;
660   size_t cur_token;
661   void * value;
662   size_t final_token;
663   int r;
664   int res;
665
666   cur_token = * index;
667
668   r = parser(message, length, &cur_token, &value);
669   if (r != MAILIMF_NO_ERROR) {
670     res = r;
671     goto err;
672   }
673
674   struct_list = clist_new();
675   if (struct_list == NULL) {
676     destructor(value);
677     res = MAILIMF_ERROR_MEMORY;
678     goto err;
679   }
680
681   r = clist_append(struct_list, value);
682   if (r < 0) {
683     destructor(value);
684     res = MAILIMF_ERROR_MEMORY;
685     goto free;
686   }
687
688   final_token = cur_token;
689
690   while (1) {
691     r = mailimf_unstrict_char_parse(message, length, &cur_token, symbol);
692     if (r != MAILIMF_NO_ERROR) {
693       if (r == MAILIMF_ERROR_PARSE)
694         break;
695       else {
696         res = r;
697         goto free;
698       }
699     }
700
701     r = parser(message, length, &cur_token, &value);
702     if (r != MAILIMF_NO_ERROR) {
703       if (r == MAILIMF_ERROR_PARSE)
704         break;
705       else {
706         res = r;
707         goto free;
708       }
709     }
710
711     r = clist_append(struct_list, value);
712     if (r < 0) {
713       destructor(value);
714       res = MAILIMF_ERROR_MEMORY;
715       goto free;
716     }
717
718     final_token = cur_token;
719   }
720   
721   * result = struct_list;
722   * index = final_token;
723   
724   return MAILIMF_NO_ERROR;
725   
726  free:
727   clist_foreach(struct_list, (clist_func) destructor, NULL);
728   clist_free(struct_list);
729  err:
730   return res;
731 }
732
733 static inline int mailimf_wsp_parse(const char * message, size_t length,
734                                     size_t * index)
735 {
736   size_t cur_token;
737
738   cur_token = * index;
739
740   if (cur_token >= length)
741     return MAILIMF_ERROR_PARSE;
742
743   if ((message[cur_token] != ' ') && (message[cur_token] != '\t'))
744     return MAILIMF_ERROR_PARSE;
745
746   cur_token ++;
747   * index = cur_token;
748
749   return MAILIMF_NO_ERROR;
750 }
751
752
753 int mailimf_crlf_parse(const char * message, size_t length, size_t * index)
754 {
755   size_t cur_token;
756   int r;
757
758   cur_token = * index;
759
760   r = mailimf_char_parse(message, length, &cur_token, '\r');
761   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
762     return r;
763
764   r = mailimf_char_parse(message, length, &cur_token, '\n');
765   if (r != MAILIMF_NO_ERROR)
766     return r;
767
768   * index = cur_token;
769   return MAILIMF_NO_ERROR;
770 }
771
772 static int mailimf_unstrict_crlf_parse(const char * message,
773                                        size_t length, size_t * index)
774 {
775   size_t cur_token;
776   int r;
777
778   cur_token = * index;
779
780   mailimf_cfws_parse(message, length, &cur_token);
781
782   r = mailimf_char_parse(message, length, &cur_token, '\r');
783   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
784     return r;
785
786   r = mailimf_char_parse(message, length, &cur_token, '\n');
787   if (r != MAILIMF_NO_ERROR)
788     return r;
789
790   * index = cur_token;
791   return MAILIMF_NO_ERROR;
792 }
793
794 /* ************************************************************************ */
795
796
797
798 /* RFC 2822 grammar */
799
800 /*
801 NO-WS-CTL       =       %d1-8 /         ; US-ASCII control characters
802                         %d11 /          ;  that do not include the
803                         %d12 /          ;  carriage return, line feed,
804                         %d14-31 /       ;  and white space characters
805                         %d127
806 */
807
808 static inline int is_no_ws_ctl(char ch)
809 {
810   if ((ch == 9) || (ch == 10) || (ch == 13))
811     return FALSE;
812
813   if (ch == 127)
814      return TRUE;
815
816   return (ch >= 1) && (ch <= 31);
817 }
818
819 /*
820 text            =       %d1-9 /         ; Characters excluding CR and LF
821                         %d11 /
822                         %d12 /
823                         %d14-127 /
824                         obs-text
825 */
826
827 /*
828 specials        =       "(" / ")" /     ; Special characters used in
829                         "<" / ">" /     ;  other parts of the syntax
830                         "[" / "]" /
831                         ":" / ";" /
832                         "@" / "\" /
833                         "," / "." /
834                         DQUOTE
835 */
836
837 /*
838 quoted-pair     =       ("\" text) / obs-qp
839 */
840
841 static inline int mailimf_quoted_pair_parse(const char * message, size_t length,
842                                             size_t * index, char * result)
843 {
844   size_t cur_token;
845
846   cur_token = * index;
847   
848   if (cur_token + 1 >= length)
849     return MAILIMF_ERROR_PARSE;
850
851   if (message[cur_token] != '\\')
852     return MAILIMF_ERROR_PARSE;
853
854   cur_token ++;
855   * result = message[cur_token];
856   cur_token ++;
857   * index = cur_token;
858
859   return MAILIMF_NO_ERROR;
860 }
861
862 /*
863 FWS             =       ([*WSP CRLF] 1*WSP) /   ; Folding white space
864                         obs-FWS
865 */
866
867 int mailimf_fws_parse(const char * message, size_t length, size_t * index)
868 {
869   size_t cur_token;
870   size_t final_token;
871   int fws_1;
872   int fws_2;
873   int fws_3;
874   int r;
875   
876   cur_token = * index;
877
878   fws_1 = FALSE;
879   while (1) {
880     r = mailimf_wsp_parse(message, length, &cur_token);
881     if (r != MAILIMF_NO_ERROR) {
882       if (r == MAILIMF_ERROR_PARSE)
883         break;
884       else
885         return r;
886     }
887     fws_1 = TRUE;
888   }
889   final_token = cur_token;
890
891   r = mailimf_crlf_parse(message, length, &cur_token);
892   switch (r) {
893   case MAILIMF_NO_ERROR:
894     fws_2 = TRUE;
895     break;
896   case MAILIMF_ERROR_PARSE:
897     fws_2 = FALSE;
898     break;
899   default:
900       return r;
901   }
902   
903   fws_3 = FALSE;
904   if (fws_2) {
905     while (1) {
906       r = mailimf_wsp_parse(message, length, &cur_token);
907       if (r != MAILIMF_NO_ERROR) {
908         if (r == MAILIMF_ERROR_PARSE)
909           break;
910         else
911           return r;
912       }
913       fws_3 = TRUE;
914     }
915   }
916
917   if ((!fws_1) && (!fws_3))
918     return MAILIMF_ERROR_PARSE;
919
920   if (!fws_3)
921     cur_token = final_token;
922
923   * index = cur_token;
924
925   return MAILIMF_NO_ERROR;
926 }
927
928
929 /*
930 ctext           =       NO-WS-CTL /     ; Non white space controls
931
932                         %d33-39 /       ; The rest of the US-ASCII
933                         %d42-91 /       ;  characters not including "(",
934                         %d93-126        ;  ")", or "\"
935 */
936
937 static inline int is_ctext(char ch)
938 {
939   unsigned char uch = (unsigned char) ch;
940
941   if (is_no_ws_ctl(ch))
942     return TRUE;
943
944   if (uch < 33)
945     return FALSE;
946
947   if ((uch == 40) || (uch == 41))
948     return FALSE;
949   
950   if (uch == 92)
951     return FALSE;
952
953   if (uch == 127)
954     return FALSE;
955
956   return TRUE;
957 }
958
959 /*
960 ccontent        =       ctext / quoted-pair / comment
961 */
962
963 static inline int mailimf_ccontent_parse(const char * message, size_t length,
964                                          size_t * index)
965 {
966   size_t cur_token;
967   char ch;
968   int r;
969   
970   cur_token = * index;
971
972   if (cur_token >= length)
973     return MAILIMF_ERROR_PARSE;
974
975   if (is_ctext(message[cur_token])) {
976     cur_token ++;
977   }
978   else {
979     r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
980     
981     if (r == MAILIMF_ERROR_PARSE)
982       r = mailimf_comment_parse(message, length, &cur_token);
983     
984     if (r == MAILIMF_ERROR_PARSE)
985       return r;
986   }
987
988   * index = cur_token;
989
990   return MAILIMF_NO_ERROR;
991 }
992
993 /*
994 [FWS] ccontent
995 */
996
997 static inline int
998 mailimf_comment_fws_ccontent_parse(const char * message, size_t length,
999                                    size_t * index)
1000 {
1001   size_t cur_token;
1002   int r;
1003
1004   cur_token = * index;
1005
1006   r = mailimf_fws_parse(message, length, &cur_token);
1007   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
1008     return r;
1009
1010   r = mailimf_ccontent_parse(message, length, &cur_token);
1011   if (r != MAILIMF_NO_ERROR)
1012     return r;
1013
1014   * index = cur_token;
1015
1016   return MAILIMF_NO_ERROR;
1017 }
1018
1019 /*
1020 comment         =       "(" *([FWS] ccontent) [FWS] ")"
1021 */
1022
1023 static inline int mailimf_comment_parse(const char * message, size_t length,
1024                                  size_t * index)
1025 {
1026   size_t cur_token;
1027   int r;
1028
1029   cur_token = * index;
1030
1031   r = mailimf_oparenth_parse(message, length, &cur_token);
1032   if (r != MAILIMF_NO_ERROR)
1033     return r;
1034
1035   while (1) {
1036     r = mailimf_comment_fws_ccontent_parse(message, length, &cur_token);
1037     if (r != MAILIMF_NO_ERROR) {
1038       if (r == MAILIMF_ERROR_PARSE)
1039         break;
1040       else
1041         return r;
1042     }
1043   }
1044
1045   r = mailimf_fws_parse(message, length, &cur_token);
1046   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
1047     return r;
1048
1049   r = mailimf_cparenth_parse(message, length, &cur_token);
1050   if (r != MAILIMF_NO_ERROR)
1051     return r;
1052
1053   * index = cur_token;
1054
1055   return MAILIMF_NO_ERROR;
1056 }
1057
1058 /*
1059 [FWS] comment
1060 */
1061
1062 static inline int mailimf_cfws_fws_comment_parse(const char * message, size_t length,
1063                                                  size_t * index)
1064 {
1065   size_t cur_token;
1066   int r;
1067
1068   cur_token = * index;
1069
1070   r = mailimf_fws_parse(message, length, &cur_token);
1071   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
1072     return r;
1073
1074   r = mailimf_comment_parse(message, length, &cur_token);
1075   if (r != MAILIMF_NO_ERROR)
1076     return r;
1077
1078   * index = cur_token;
1079
1080   return MAILIMF_NO_ERROR;
1081 }
1082
1083 /*
1084 CFWS            =       *([FWS] comment) (([FWS] comment) / FWS)
1085 */
1086
1087 int mailimf_cfws_parse(const char * message, size_t length,
1088                        size_t * index)
1089 {
1090   size_t cur_token;
1091   int has_comment;
1092   int r;
1093
1094   cur_token = * index;
1095
1096   has_comment = FALSE;
1097   while (1) {
1098     r = mailimf_cfws_fws_comment_parse(message, length, &cur_token);
1099     if (r != MAILIMF_NO_ERROR) {
1100       if (r == MAILIMF_ERROR_PARSE)
1101         break;
1102       else
1103         return r;
1104     }
1105     has_comment = TRUE;
1106   }
1107
1108   if (!has_comment) {
1109     r = mailimf_fws_parse(message, length, &cur_token);
1110     if (r != MAILIMF_NO_ERROR)
1111       return r;
1112   }
1113
1114   * index = cur_token;
1115
1116   return MAILIMF_NO_ERROR;
1117 }
1118
1119 /*
1120 atext           =       ALPHA / DIGIT / ; Any character except controls,
1121                         "!" / "#" /     ;  SP, and specials.
1122                         "$" / "%" /     ;  Used for atoms
1123                         "&" / "'" /
1124                         "*" / "+" /
1125                         "-" / "/" /
1126                         "=" / "?" /
1127                         "^" / "_" /
1128                         "`" / "{" /
1129                         "|" / "}" /
1130                         "~"
1131 */
1132
1133 static inline int is_atext(char ch)
1134 {
1135   switch (ch) {
1136   case ' ':
1137   case '\t':
1138   case '\n':
1139   case '\r':
1140 #if 0
1141   case '(':
1142   case ')':
1143 #endif
1144   case '<':
1145   case '>':
1146 #if 0
1147   case '@':
1148 #endif
1149   case ',':
1150   case '"':
1151   case ':':
1152   case ';':
1153     return FALSE;
1154   default:
1155     return TRUE;
1156   }
1157 }
1158
1159 /*
1160 atom            =       [CFWS] 1*atext [CFWS]
1161 */
1162
1163 int mailimf_atom_parse(const char * message, size_t length,
1164                        size_t * index, char ** result)
1165 {
1166   size_t cur_token;
1167   int r;
1168   int res;
1169   char * atom;
1170   size_t end;
1171
1172   cur_token = * index;
1173
1174   r = mailimf_cfws_parse(message, length, &cur_token);
1175   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
1176     res = r;
1177     goto err;
1178   }
1179   
1180   end = cur_token;
1181   if (end >= length) {
1182     res = MAILIMF_ERROR_PARSE;
1183     goto err;
1184   }
1185
1186   while (is_atext(message[end])) {
1187     end ++;
1188     if (end >= length)
1189       break;
1190   }
1191   if (end == cur_token) {
1192     res = MAILIMF_ERROR_PARSE;
1193     goto err;
1194   }
1195
1196   atom = malloc(end - cur_token + 1);
1197   if (atom == NULL) {
1198     res = MAILIMF_ERROR_MEMORY;
1199     goto err;
1200   }
1201   strncpy(atom, message + cur_token, end - cur_token);
1202   atom[end - cur_token] = '\0';
1203
1204   cur_token = end;
1205
1206   * index = cur_token;
1207   * result = atom;
1208
1209   return MAILIMF_NO_ERROR;
1210
1211  err:
1212   return res;
1213 }
1214
1215 int mailimf_fws_atom_parse(const char * message, size_t length,
1216                            size_t * index, char ** result)
1217 {
1218   size_t cur_token;
1219   int r;
1220   int res;
1221   char * atom;
1222   size_t end;
1223
1224   cur_token = * index;
1225
1226   r = mailimf_fws_parse(message, length, &cur_token);
1227   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
1228     res = r;
1229     goto err;
1230   }
1231
1232   end = cur_token;
1233   if (end >= length) {
1234     res = MAILIMF_ERROR_PARSE;
1235     goto err;
1236   }
1237
1238   while (is_atext(message[end])) {
1239     end ++;
1240     if (end >= length)
1241       break;
1242   }
1243   if (end == cur_token) {
1244     res = MAILIMF_ERROR_PARSE;
1245     goto err;
1246   }
1247
1248   atom = malloc(end - cur_token + 1);
1249   if (atom == NULL) {
1250     res = MAILIMF_ERROR_MEMORY;
1251     goto err;
1252   }
1253   strncpy(atom, message + cur_token, end - cur_token);
1254   atom[end - cur_token] = '\0';
1255
1256   cur_token = end;
1257
1258   * index = cur_token;
1259   * result = atom;
1260
1261   return MAILIMF_NO_ERROR;
1262
1263  err:
1264   return res;
1265 }
1266
1267 /*
1268 dot-atom        =       [CFWS] dot-atom-text [CFWS]
1269 */
1270
1271 #if 0
1272 static int mailimf_dot_atom_parse(const char * message, size_t length,
1273                                   size_t * index, char ** result)
1274 {
1275   return mailimf_atom_parse(message, length, index, result);
1276 }
1277 #endif
1278
1279 /*
1280 dot-atom-text   =       1*atext *("." 1*atext)
1281 */
1282
1283 #if 0
1284 static int
1285 mailimf_dot_atom_text_parse(const char * message, size_t length,
1286                             size_t * index, char ** result)
1287 {
1288   return mailimf_atom_parse(message, length, index, result);
1289 }
1290 #endif
1291
1292 /*
1293 qtext           =       NO-WS-CTL /     ; Non white space controls
1294
1295                         %d33 /          ; The rest of the US-ASCII
1296                         %d35-91 /       ;  characters not including "\"
1297                         %d93-126        ;  or the quote character
1298 */
1299
1300 static inline int is_qtext(char ch)
1301 {
1302   unsigned char uch = (unsigned char) ch;
1303
1304   if (is_no_ws_ctl(ch))
1305     return TRUE;
1306
1307   if (uch < 33)
1308     return FALSE;
1309
1310   if (uch == 34)
1311     return FALSE;
1312
1313   if (uch == 92)
1314     return FALSE;
1315
1316   if (uch == 127)
1317     return FALSE;
1318
1319   return TRUE;
1320 }
1321
1322 /*
1323 qcontent        =       qtext / quoted-pair
1324 */
1325
1326 static int mailimf_qcontent_parse(const char * message, size_t length,
1327                                   size_t * index, char * result)
1328 {
1329   size_t cur_token;
1330   char ch;
1331   int r;
1332
1333   cur_token = * index;
1334
1335   if (cur_token >= length)
1336     return MAILIMF_ERROR_PARSE;
1337
1338   if (is_qtext(message[cur_token])) {
1339     ch = message[cur_token];
1340     cur_token ++;
1341   }
1342   else {
1343     r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
1344     
1345     if (r != MAILIMF_NO_ERROR)
1346       return r;
1347   }
1348   
1349   * result = ch;
1350   * index = cur_token;
1351
1352   return MAILIMF_NO_ERROR;
1353 }
1354
1355 /*
1356 quoted-string   =       [CFWS]
1357                         DQUOTE *([FWS] qcontent) [FWS] DQUOTE
1358                         [CFWS]
1359 */
1360
1361 int mailimf_quoted_string_parse(const char * message, size_t length,
1362                                 size_t * index, char ** result)
1363 {
1364   size_t cur_token;
1365   MMAPString * gstr;
1366   char ch;
1367   char * str;
1368   int r;
1369   int res;
1370
1371   cur_token = * index;
1372
1373   r = mailimf_cfws_parse(message, length, &cur_token);
1374   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
1375     res = r;
1376     goto err;
1377   }
1378
1379   r = mailimf_dquote_parse(message, length, &cur_token);
1380   if (r != MAILIMF_NO_ERROR) {
1381     res = r;
1382     goto err;
1383   }
1384
1385   gstr = mmap_string_new("");
1386   if (gstr == NULL) {
1387     res = MAILIMF_ERROR_MEMORY;
1388     goto err;
1389   }
1390
1391 #if 0
1392   if (mmap_string_append_c(gstr, '\"') == NULL) {
1393     res = MAILIMF_ERROR_MEMORY;
1394     goto free_gstr;
1395   }
1396 #endif
1397
1398   while (1) {
1399     r = mailimf_fws_parse(message, length, &cur_token);
1400     if (r == MAILIMF_NO_ERROR) {
1401       if (mmap_string_append_c(gstr, ' ') == NULL) {
1402         res = MAILIMF_ERROR_MEMORY;
1403         goto free_gstr;
1404       }
1405     }
1406     else if (r != MAILIMF_ERROR_PARSE) {
1407       res = r;
1408       goto free_gstr;
1409     }
1410
1411     r = mailimf_qcontent_parse(message, length, &cur_token, &ch);
1412     if (r == MAILIMF_NO_ERROR) {
1413       if (mmap_string_append_c(gstr, ch) == NULL) {
1414         res = MAILIMF_ERROR_MEMORY;
1415         goto free_gstr;
1416       }
1417     }
1418     else if (r == MAILIMF_ERROR_PARSE)
1419       break;
1420     else {
1421       res = r;
1422       goto free_gstr;
1423     }
1424   }
1425
1426   r = mailimf_dquote_parse(message, length, &cur_token);
1427   if (r != MAILIMF_NO_ERROR) {
1428     res = r;
1429     goto free_gstr;
1430   }
1431
1432 #if 0
1433   if (mmap_string_append_c(gstr, '\"') == NULL) {
1434     res = MAILIMF_ERROR_MEMORY;
1435     goto free_gstr;
1436   }
1437 #endif
1438
1439   str = strdup(gstr->str);
1440   if (str == NULL) {
1441     res = MAILIMF_ERROR_MEMORY;
1442     goto free_gstr;
1443   }
1444   mmap_string_free(gstr);
1445
1446   * index = cur_token;
1447   * result = str;
1448
1449   return MAILIMF_NO_ERROR;
1450
1451  free_gstr:
1452   mmap_string_free(gstr);
1453  err:
1454   return res;
1455 }
1456
1457 int mailimf_fws_quoted_string_parse(const char * message, size_t length,
1458                                     size_t * index, char ** result)
1459 {
1460   size_t cur_token;
1461   MMAPString * gstr;
1462   char ch;
1463   char * str;
1464   int r;
1465   int res;
1466
1467   cur_token = * index;
1468
1469   r = mailimf_fws_parse(message, length, &cur_token);
1470   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
1471     res = r;
1472     goto err;
1473   }
1474
1475   r = mailimf_dquote_parse(message, length, &cur_token);
1476   if (r != MAILIMF_NO_ERROR) {
1477     res = r;
1478     goto err;
1479   }
1480
1481   gstr = mmap_string_new("");
1482   if (gstr == NULL) {
1483     res = MAILIMF_ERROR_MEMORY;
1484     goto err;
1485   }
1486
1487 #if 0
1488   if (mmap_string_append_c(gstr, '\"') == NULL) {
1489     res = MAILIMF_ERROR_MEMORY;
1490     goto free_gstr;
1491   }
1492 #endif
1493
1494   while (1) {
1495     r = mailimf_fws_parse(message, length, &cur_token);
1496     if (r == MAILIMF_NO_ERROR) {
1497       if (mmap_string_append_c(gstr, ' ') == NULL) {
1498         res = MAILIMF_ERROR_MEMORY;
1499         goto free_gstr;
1500       }
1501     }
1502     else if (r != MAILIMF_ERROR_PARSE) {
1503       res = r;
1504       goto free_gstr;
1505     }
1506
1507     r = mailimf_qcontent_parse(message, length, &cur_token, &ch);
1508     if (r == MAILIMF_NO_ERROR) {
1509       if (mmap_string_append_c(gstr, ch) == NULL) {
1510         res = MAILIMF_ERROR_MEMORY;
1511         goto free_gstr;
1512       }
1513     }
1514     else if (r == MAILIMF_ERROR_PARSE)
1515       break;
1516     else {
1517       res = r;
1518       goto free_gstr;
1519     }
1520   }
1521
1522   r = mailimf_dquote_parse(message, length, &cur_token);
1523   if (r != MAILIMF_NO_ERROR) {
1524     res = r;
1525     goto free_gstr;
1526   }
1527
1528 #if 0
1529   if (mmap_string_append_c(gstr, '\"') == NULL) {
1530     res = MAILIMF_ERROR_MEMORY;
1531     goto free_gstr;
1532   }
1533 #endif
1534
1535   str = strdup(gstr->str);
1536   if (str == NULL) {
1537     res = MAILIMF_ERROR_MEMORY;
1538     goto free_gstr;
1539   }
1540   mmap_string_free(gstr);
1541
1542   * index = cur_token;
1543   * result = str;
1544
1545   return MAILIMF_NO_ERROR;
1546
1547  free_gstr:
1548   mmap_string_free(gstr);
1549  err:
1550   return res;
1551 }
1552
1553 /*
1554 word            =       atom / quoted-string
1555 */
1556
1557 int mailimf_word_parse(const char * message, size_t length,
1558                        size_t * index, char ** result)
1559 {
1560   size_t cur_token;
1561   char * word;
1562   int r;
1563
1564   cur_token = * index;
1565
1566   r = mailimf_atom_parse(message, length, &cur_token, &word);
1567
1568   if (r == MAILIMF_ERROR_PARSE)
1569     r = mailimf_quoted_string_parse(message, length, &cur_token, &word);
1570
1571   if (r != MAILIMF_NO_ERROR)
1572     return r;
1573
1574   * result = word;
1575   * index = cur_token;
1576
1577   return MAILIMF_NO_ERROR;
1578 }
1579
1580 int mailimf_fws_word_parse(const char * message, size_t length,
1581                            size_t * index, char ** result)
1582 {
1583   size_t cur_token;
1584   char * word;
1585   int r;
1586
1587   cur_token = * index;
1588
1589   r = mailimf_fws_atom_parse(message, length, &cur_token, &word);
1590
1591   if (r == MAILIMF_ERROR_PARSE)
1592     r = mailimf_fws_quoted_string_parse(message, length, &cur_token, &word);
1593
1594   if (r != MAILIMF_NO_ERROR)
1595     return r;
1596
1597   * result = word;
1598   * index = cur_token;
1599
1600   return MAILIMF_NO_ERROR;
1601 }
1602
1603 /*
1604 phrase          =       1*word / obs-phrase
1605 */
1606
1607 static int mailimf_phrase_parse(const char * message, size_t length,
1608                                 size_t * index, char ** result)
1609 {
1610   MMAPString * gphrase;
1611   char * word;
1612   int first;
1613   size_t cur_token;
1614   int r;
1615   int res;
1616   char * str;
1617
1618   cur_token = * index;
1619
1620   gphrase = mmap_string_new("");
1621   if (gphrase == NULL) {
1622     res = MAILIMF_ERROR_MEMORY;
1623     goto err;
1624   }
1625
1626   first = TRUE;
1627
1628   while (1) {
1629     r = mailimf_fws_word_parse(message, length, &cur_token, &word);
1630     if (r == MAILIMF_NO_ERROR) {
1631       if (!first) {
1632         if (mmap_string_append_c(gphrase, ' ') == NULL) {
1633           mailimf_word_free(word);
1634           res = MAILIMF_ERROR_MEMORY;
1635           goto free;
1636         }
1637       }
1638       if (mmap_string_append(gphrase, word) == NULL) {
1639         mailimf_word_free(word);
1640         res = MAILIMF_ERROR_MEMORY;
1641         goto free;
1642       }
1643       mailimf_word_free(word);
1644       first = FALSE;
1645     }
1646     else if (r == MAILIMF_ERROR_PARSE)
1647       break;
1648     else {
1649       res = r;
1650       goto free;
1651     }
1652   }
1653
1654   if (first) {
1655     res = MAILIMF_ERROR_PARSE;
1656     goto free;
1657   }
1658
1659   str = strdup(gphrase->str);
1660   if (str == NULL) {
1661     res = MAILIMF_ERROR_MEMORY;
1662     goto free;
1663   }
1664   mmap_string_free(gphrase);
1665
1666   * result = str;
1667   * index = cur_token;
1668
1669   return MAILIMF_NO_ERROR;
1670
1671  free:
1672   mmap_string_free(gphrase);
1673  err:
1674   return res;
1675 }
1676
1677 /*
1678 utext           =       NO-WS-CTL /     ; Non white space controls
1679                         %d33-126 /      ; The rest of US-ASCII
1680                         obs-utext
1681
1682 added : WSP
1683 */
1684
1685 enum {
1686   UNSTRUCTURED_START,
1687   UNSTRUCTURED_CR,
1688   UNSTRUCTURED_LF,
1689   UNSTRUCTURED_WSP,
1690   UNSTRUCTURED_OUT
1691 };
1692
1693 static int mailimf_unstructured_parse(const char * message, size_t length,
1694                                       size_t * index, char ** result)
1695 {
1696   size_t cur_token;
1697   int state;
1698   size_t begin;
1699   size_t terminal;
1700   char * str;
1701
1702   cur_token = * index;
1703
1704
1705   while (1) {
1706     int r;
1707
1708     r = mailimf_wsp_parse(message, length, &cur_token);
1709     if (r == MAILIMF_NO_ERROR) {
1710       /* do nothing */
1711     }
1712     else if (r == MAILIMF_ERROR_PARSE)
1713       break;
1714     else {
1715       return r;
1716     }
1717   }
1718
1719   state = UNSTRUCTURED_START;
1720   begin = cur_token;
1721   terminal = cur_token;
1722
1723   while (state != UNSTRUCTURED_OUT) {
1724
1725     switch(state) {
1726     case UNSTRUCTURED_START:
1727       if (cur_token >= length)
1728         return MAILIMF_ERROR_PARSE;
1729
1730       terminal = cur_token;
1731       switch(message[cur_token]) {
1732       case '\r':
1733         state = UNSTRUCTURED_CR;
1734         break;
1735       case '\n':
1736         state = UNSTRUCTURED_LF;
1737         break;
1738       default:
1739         state = UNSTRUCTURED_START;
1740         break;
1741       }
1742       break;
1743     case UNSTRUCTURED_CR:
1744       if (cur_token >= length)
1745         return MAILIMF_ERROR_PARSE;
1746
1747       switch(message[cur_token]) {
1748       case '\n':
1749         state = UNSTRUCTURED_LF;
1750         break;
1751       default:
1752         state = UNSTRUCTURED_START;
1753         break;
1754       }
1755       break;
1756
1757     case UNSTRUCTURED_LF:
1758       if (cur_token >= length) {
1759         state = UNSTRUCTURED_OUT;
1760         break;
1761       }
1762
1763       switch(message[cur_token]) {
1764       case '\t':
1765       case ' ':
1766         state = UNSTRUCTURED_WSP;
1767         break;
1768       default:
1769         state = UNSTRUCTURED_OUT;
1770         break;
1771       }
1772       break;
1773     case UNSTRUCTURED_WSP:
1774       if (cur_token >= length)
1775         return MAILIMF_ERROR_PARSE;
1776
1777       switch(message[cur_token]) {
1778       case '\r':
1779         state = UNSTRUCTURED_CR;
1780         break;
1781       case '\n':
1782         state = UNSTRUCTURED_LF;
1783         break;
1784       default:
1785         state = UNSTRUCTURED_START;
1786         break;
1787       }
1788       break;
1789     }
1790
1791     cur_token ++;
1792   }
1793
1794   str = malloc(terminal - begin + 1);
1795   if (str == NULL)
1796     return MAILIMF_ERROR_MEMORY;
1797   strncpy(str, message + begin,  terminal - begin);
1798   str[terminal - begin] = '\0';
1799
1800   * index = terminal;
1801   * result = str;
1802
1803   return MAILIMF_NO_ERROR;
1804 }
1805
1806
1807 static int mailimf_ignore_unstructured_parse(const char * message, size_t length,
1808                                              size_t * index)
1809 {
1810   size_t cur_token;
1811   int state;
1812   size_t terminal;
1813
1814   cur_token = * index;
1815
1816   state = UNSTRUCTURED_START;
1817   terminal = cur_token;
1818
1819   while (state != UNSTRUCTURED_OUT) {
1820
1821     switch(state) {
1822     case UNSTRUCTURED_START:
1823       if (cur_token >= length)
1824         return MAILIMF_ERROR_PARSE;
1825       terminal = cur_token;
1826       switch(message[cur_token]) {
1827       case '\r':
1828         state = UNSTRUCTURED_CR;
1829         break;
1830       case '\n':
1831         state = UNSTRUCTURED_LF;
1832         break;
1833       default:
1834         state = UNSTRUCTURED_START;
1835         break;
1836       }
1837       break;
1838     case UNSTRUCTURED_CR:
1839       if (cur_token >= length)
1840         return MAILIMF_ERROR_PARSE;
1841       switch(message[cur_token]) {
1842       case '\n':
1843         state = UNSTRUCTURED_LF;
1844         break;
1845       default:
1846         state = UNSTRUCTURED_START;
1847         break;
1848       }
1849       break;
1850     case UNSTRUCTURED_LF:
1851       if (cur_token >= length) {
1852         state = UNSTRUCTURED_OUT;
1853         break;
1854       }
1855       switch(message[cur_token]) {
1856       case '\t':
1857       case ' ':
1858         state = UNSTRUCTURED_WSP;
1859         break;
1860       default:
1861         state = UNSTRUCTURED_OUT;
1862         break;
1863       }
1864       break;
1865     case UNSTRUCTURED_WSP:
1866       if (cur_token >= length)
1867         return MAILIMF_ERROR_PARSE;
1868       switch(message[cur_token]) {
1869       case '\r':
1870         state = UNSTRUCTURED_CR;
1871         break;
1872       case '\n':
1873         state = UNSTRUCTURED_LF;
1874         break;
1875       default:
1876         state = UNSTRUCTURED_START;
1877         break;
1878       }
1879       break;
1880     }
1881
1882     cur_token ++;
1883   }
1884
1885   * index = terminal;
1886
1887   return MAILIMF_NO_ERROR;
1888 }
1889
1890
1891 int mailimf_ignore_field_parse(const char * message, size_t length,
1892                                size_t * index)
1893 {
1894   int has_field;
1895   size_t cur_token;
1896   int state;
1897   size_t terminal;
1898
1899   has_field = FALSE;
1900   cur_token = * index;
1901
1902   terminal = cur_token;
1903   state = UNSTRUCTURED_START;
1904
1905   /* check if this is not a beginning CRLF */
1906
1907   if (cur_token >= length)
1908     return MAILIMF_ERROR_PARSE;
1909
1910   switch (message[cur_token]) {
1911   case '\r':
1912     return MAILIMF_ERROR_PARSE;
1913   case '\n':
1914     return MAILIMF_ERROR_PARSE;
1915   }
1916
1917   while (state != UNSTRUCTURED_OUT) {
1918
1919     switch(state) {
1920     case UNSTRUCTURED_START:
1921       if (cur_token >= length)
1922         return MAILIMF_ERROR_PARSE;
1923
1924       switch(message[cur_token]) {
1925       case '\r':
1926         state = UNSTRUCTURED_CR;
1927         break;
1928       case '\n':
1929         state = UNSTRUCTURED_LF;
1930         break;
1931       case ':':
1932         has_field = TRUE;
1933         state = UNSTRUCTURED_START;
1934         break;
1935       default:
1936         state = UNSTRUCTURED_START;
1937         break;
1938       }
1939       break;
1940     case UNSTRUCTURED_CR:
1941       if (cur_token >= length)
1942         return MAILIMF_ERROR_PARSE;
1943
1944       switch(message[cur_token]) {
1945       case '\n':
1946         state = UNSTRUCTURED_LF;
1947         break;
1948       case ':':
1949         has_field = TRUE;
1950         state = UNSTRUCTURED_START;
1951         break;
1952       default:
1953         state = UNSTRUCTURED_START;
1954         break;
1955       }
1956       break;
1957     case UNSTRUCTURED_LF:
1958       if (cur_token >= length) {
1959         terminal = cur_token;
1960         state = UNSTRUCTURED_OUT;
1961         break;
1962       }
1963
1964       switch(message[cur_token]) {
1965       case '\t':
1966       case ' ':
1967         state = UNSTRUCTURED_WSP;
1968         break;
1969       default:
1970         terminal = cur_token;
1971         state = UNSTRUCTURED_OUT;
1972         break;
1973       }
1974       break;
1975     case UNSTRUCTURED_WSP:
1976       if (cur_token >= length)
1977         return MAILIMF_ERROR_PARSE;
1978
1979       switch(message[cur_token]) {
1980       case '\r':
1981         state = UNSTRUCTURED_CR;
1982         break;
1983       case '\n':
1984         state = UNSTRUCTURED_LF;
1985         break;
1986       case ':':
1987         has_field = TRUE;
1988         state = UNSTRUCTURED_START;
1989         break;
1990       default:
1991         state = UNSTRUCTURED_START;
1992         break;
1993       }
1994       break;
1995     }
1996
1997     cur_token ++;
1998   }
1999
2000   if (!has_field)
2001     return MAILIMF_ERROR_PARSE;
2002
2003   * index = terminal;
2004
2005   return MAILIMF_NO_ERROR;
2006 }
2007
2008
2009 /*
2010 date-time       =       [ day-of-week "," ] date FWS time [CFWS]
2011 */
2012
2013 int mailimf_date_time_parse(const char * message, size_t length,
2014                             size_t * index,
2015                             struct mailimf_date_time ** result)
2016 {
2017   size_t cur_token;
2018   int day_of_week;
2019   struct mailimf_date_time * date_time;
2020   int day;
2021   int month;
2022   int year;
2023   int hour;
2024   int min;
2025   int sec;
2026   int zone;
2027   int r;
2028
2029   cur_token = * index;
2030
2031   day_of_week = -1;
2032   r = mailimf_day_of_week_parse(message, length, &cur_token, &day_of_week);
2033   if (r == MAILIMF_NO_ERROR) {
2034     r = mailimf_comma_parse(message, length, &cur_token);
2035     if (r != MAILIMF_NO_ERROR)
2036       return r;
2037   }
2038   else if (r != MAILIMF_ERROR_PARSE)
2039     return r;
2040
2041   r = mailimf_date_parse(message, length, &cur_token, &day, &month, &year);
2042   if (r != MAILIMF_NO_ERROR)
2043     return r;
2044
2045   r = mailimf_fws_parse(message, length, &cur_token);
2046   if (r != MAILIMF_NO_ERROR)
2047     return r;
2048
2049   r = mailimf_time_parse(message, length, &cur_token,
2050                          &hour, &min, &sec, &zone);
2051   if (r != MAILIMF_NO_ERROR)
2052     return r;
2053
2054   date_time = mailimf_date_time_new(day, month, year, hour, min, sec, zone);
2055   if (date_time == NULL)
2056     return MAILIMF_ERROR_MEMORY;
2057
2058   * index = cur_token;
2059   * result = date_time;
2060
2061   return MAILIMF_NO_ERROR;
2062 }
2063
2064 /*
2065 day-of-week     =       ([FWS] day-name) / obs-day-of-week
2066 */
2067
2068 static int mailimf_day_of_week_parse(const char * message, size_t length,
2069                                      size_t * index, int * result)
2070 {
2071   size_t cur_token;
2072   int day_of_week;
2073   int r;
2074
2075   cur_token = * index;
2076
2077   r = mailimf_cfws_parse(message, length, &cur_token);
2078   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
2079     return r;
2080
2081   r = mailimf_day_name_parse(message, length, &cur_token, &day_of_week);
2082   if (r != MAILIMF_NO_ERROR)
2083     return r;
2084
2085   * index = cur_token;
2086   * result = day_of_week;
2087
2088   return MAILIMF_NO_ERROR;
2089 }
2090
2091 /*
2092 day-name        =       "Mon" / "Tue" / "Wed" / "Thu" /
2093                         "Fri" / "Sat" / "Sun"
2094 */
2095
2096 struct mailimf_token_value {
2097   int value;
2098   char * str;
2099 };
2100
2101 static struct mailimf_token_value day_names[] = {
2102   {1, "Mon"},
2103   {2, "Tue"},
2104   {3, "Wed"},
2105   {4, "Thu"},
2106   {5, "Fri"},
2107   {6, "Sat"},
2108   {7, "Sun"},
2109 };
2110
2111 enum {
2112   DAY_NAME_START,
2113   DAY_NAME_T,
2114   DAY_NAME_S
2115 };
2116
2117 static int guess_day_name(const char * message, size_t length, size_t index)
2118 {
2119   int state;
2120
2121   state = DAY_NAME_START;
2122
2123   while (1) {
2124
2125     if (index >= length)
2126       return -1;
2127
2128     switch(state) {
2129     case DAY_NAME_START:
2130       switch((char) toupper((unsigned char) message[index])) {
2131       case 'M': /* Mon */
2132         return 1;
2133         break;
2134       case 'T': /* Tue Thu */
2135         state = DAY_NAME_T;
2136         break;
2137       case 'W': /* Wed */
2138         return 3;
2139       case 'F':
2140         return 5;
2141       case 'S': /* Sat Sun */
2142         state = DAY_NAME_S;
2143         break;
2144       default:
2145         return -1;
2146       }
2147       break;
2148     case DAY_NAME_T:
2149       switch((char) toupper((unsigned char) message[index])) {
2150       case 'U':
2151         return 2;
2152       case 'H':
2153         return 4;
2154       default:
2155         return -1;
2156       }
2157       break;
2158     case DAY_NAME_S:
2159       switch((char) toupper((unsigned char) message[index])) {
2160       case 'A':
2161         return 6;
2162       case 'U':
2163         return 7;
2164       default:
2165         return -1;
2166       }
2167       break;
2168     }
2169
2170     index ++;
2171   }
2172 }
2173
2174 static int mailimf_day_name_parse(const char * message, size_t length,
2175                                   size_t * index, int * result)
2176 {
2177   size_t cur_token;
2178   int day_of_week;
2179   int guessed_day;
2180   int r;
2181
2182   cur_token = * index;
2183
2184   guessed_day = guess_day_name(message, length, cur_token);
2185   if (guessed_day == -1)
2186     return MAILIMF_ERROR_PARSE;
2187
2188   r = mailimf_token_case_insensitive_parse(message, length,
2189                                            &cur_token,
2190                                            day_names[guessed_day - 1].str);
2191   if (r != MAILIMF_NO_ERROR)
2192     return r;
2193
2194   day_of_week = guessed_day;
2195
2196   * result = day_of_week;
2197   * index = cur_token;
2198
2199   return MAILIMF_NO_ERROR;
2200 }
2201
2202 /*
2203 date            =       day month year
2204 */
2205
2206 static int mailimf_date_parse(const char * message, size_t length,
2207                               size_t * index,
2208                               int * pday, int * pmonth, int * pyear)
2209 {
2210   size_t cur_token;
2211   int day;
2212   int month;
2213   int year;
2214   int r;
2215
2216   cur_token = * index;
2217
2218   r = mailimf_day_parse(message, length, &cur_token, &day);
2219   if (r != MAILIMF_NO_ERROR)
2220     return r;
2221
2222   r = mailimf_month_parse(message, length, &cur_token, &month);
2223   if (r != MAILIMF_NO_ERROR)
2224     return r;
2225
2226   r = mailimf_year_parse(message, length, &cur_token, &year);
2227   if (r != MAILIMF_NO_ERROR)
2228     return r;
2229
2230   * pday = day;
2231   * pmonth = month;
2232   * pyear = year;
2233
2234   * index = cur_token;
2235
2236   return MAILIMF_NO_ERROR;
2237 }
2238
2239 /*
2240 year            =       4*DIGIT / obs-year
2241 */
2242
2243 static int mailimf_year_parse(const char * message, size_t length,
2244                               size_t * index, int * result)
2245 {
2246   uint32_t number;
2247   size_t cur_token;
2248   int r;
2249
2250   cur_token = * index;
2251
2252   r = mailimf_cfws_parse(message, length, &cur_token);
2253   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
2254     return r;
2255
2256   r = mailimf_number_parse(message, length, &cur_token, &number);
2257   if (r != MAILIMF_NO_ERROR)
2258     return r;
2259
2260   * index = cur_token;
2261   * result = number;
2262
2263   return MAILIMF_NO_ERROR;
2264 }
2265
2266 /*
2267 month           =       (FWS month-name FWS) / obs-month
2268 */
2269
2270 static int mailimf_month_parse(const char * message, size_t length,
2271                                size_t * index, int * result)
2272 {
2273   size_t cur_token;
2274   int month;
2275   int r;
2276
2277   cur_token = * index;
2278
2279   r = mailimf_cfws_parse(message, length, &cur_token);
2280   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
2281     return r;
2282
2283   r = mailimf_month_name_parse(message, length, &cur_token, &month);
2284   if (r != MAILIMF_NO_ERROR)
2285     return r;
2286
2287   * result = month;
2288   * index = cur_token;
2289
2290   return MAILIMF_NO_ERROR;
2291 }
2292
2293 /*
2294 month-name      =       "Jan" / "Feb" / "Mar" / "Apr" /
2295                         "May" / "Jun" / "Jul" / "Aug" /
2296                         "Sep" / "Oct" / "Nov" / "Dec"
2297 */
2298
2299 static struct mailimf_token_value month_names[] = {
2300   {1, "Jan"},
2301   {2, "Feb"},
2302   {3, "Mar"},
2303   {4, "Apr"},
2304   {5, "May"},
2305   {6, "Jun"},
2306   {7, "Jul"},
2307   {8, "Aug"},
2308   {9, "Sep"},
2309   {10, "Oct"},
2310   {11, "Nov"},
2311   {12, "Dec"},
2312 };
2313
2314 enum {
2315   MONTH_START,
2316   MONTH_J,
2317   MONTH_JU,
2318   MONTH_M,
2319   MONTH_MA,
2320   MONTH_A
2321 };
2322
2323 static int guess_month(const char * message, size_t length, size_t index)
2324 {
2325   int state;
2326
2327   state = MONTH_START;
2328
2329   while (1) {
2330
2331     if (index >= length)
2332       return -1;
2333
2334     switch(state) {
2335     case MONTH_START:
2336       switch((char) toupper((unsigned char) message[index])) {
2337       case 'J': /* Jan Jun Jul */
2338         state = MONTH_J;
2339         break;
2340       case 'F': /* Feb */
2341         return 2;
2342       case 'M': /* Mar May */
2343         state = MONTH_M;
2344         break;
2345       case 'A': /* Apr Aug */
2346         state = MONTH_A;
2347         break;
2348       case 'S': /* Sep */
2349         return 9;
2350       case 'O': /* Oct */
2351         return 10;
2352       case 'N': /* Nov */
2353         return 11;
2354       case 'D': /* Dec */
2355         return 12;
2356       default:
2357         return -1;
2358       }
2359       break;
2360     case MONTH_J:
2361       switch((char) toupper((unsigned char) message[index])) {
2362       case 'A':
2363         return 1;
2364       case 'U':
2365         state = MONTH_JU;
2366         break;
2367       default:
2368         return -1;
2369       }
2370       break;
2371     case MONTH_JU:
2372       switch((char) toupper((unsigned char) message[index])) {
2373       case 'N':
2374         return 6;
2375       case 'L':
2376         return 7;
2377       default:
2378         return -1;
2379       }
2380       break;
2381     case MONTH_M:
2382       switch((char) toupper((unsigned char) message[index])) {
2383       case 'A':
2384         state = MONTH_MA;
2385         break;
2386       default:
2387         return -1;
2388       }
2389       break;
2390     case MONTH_MA:
2391       switch((char) toupper((unsigned char) message[index])) {
2392       case 'Y':
2393         return 5;
2394       case 'R':
2395         return 3;
2396       default:
2397         return -1;
2398       }
2399       break;
2400     case MONTH_A:
2401       switch((char) toupper((unsigned char) message[index])) {
2402       case 'P':
2403         return 4;
2404       case 'U':
2405         return 8;
2406       default:
2407         return -1;
2408       }
2409       break;
2410     }
2411
2412     index ++;
2413   }
2414 }
2415
2416 static int mailimf_month_name_parse(const char * message, size_t length,
2417                                     size_t * index, int * result)
2418 {
2419   size_t cur_token;
2420   int month;
2421   int guessed_month;
2422   int r;
2423
2424   cur_token = * index;
2425
2426   guessed_month = guess_month(message, length, cur_token);
2427   if (guessed_month == -1)
2428     return MAILIMF_ERROR_PARSE;
2429
2430   r = mailimf_token_case_insensitive_parse(message, length,
2431                                            &cur_token,
2432                                            month_names[guessed_month - 1].str);
2433   if (r != MAILIMF_NO_ERROR)
2434     return r;
2435
2436   month = guessed_month;
2437
2438   * result = month;
2439   * index = cur_token;
2440
2441   return MAILIMF_NO_ERROR;
2442 }
2443
2444 /*
2445 day             =       ([FWS] 1*2DIGIT) / obs-day
2446 */
2447
2448 static int mailimf_day_parse(const char * message, size_t length,
2449                              size_t * index, int * result)
2450 {
2451   size_t cur_token;
2452   uint32_t day;
2453   int r;
2454
2455   cur_token = * index;
2456
2457   r = mailimf_cfws_parse(message, length, &cur_token);
2458   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
2459     return r;
2460
2461   r = mailimf_number_parse(message, length, &cur_token, &day);
2462   if (r != MAILIMF_NO_ERROR)
2463     return r;
2464
2465   * result = day;
2466   * index = cur_token;
2467
2468   return MAILIMF_NO_ERROR;
2469 }
2470
2471 /*
2472 time            =       time-of-day FWS zone
2473 */
2474
2475 static int mailimf_time_parse(const char * message, size_t length,
2476                               size_t * index, 
2477                               int * phour, int * pmin,
2478                               int * psec,
2479                               int * pzone)
2480 {
2481   size_t cur_token;
2482   int hour;
2483   int min;
2484   int sec;
2485   int zone;
2486   int r;
2487
2488   cur_token = * index;
2489
2490   r = mailimf_cfws_parse(message, length, &cur_token);
2491   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
2492     return r;
2493
2494   r = mailimf_time_of_day_parse(message, length, &cur_token,
2495                                 &hour, &min, &sec);
2496   if (r != MAILIMF_NO_ERROR)
2497     return r;
2498
2499   r = mailimf_fws_parse(message, length, &cur_token);
2500   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
2501     return r;
2502
2503   r = mailimf_zone_parse(message, length, &cur_token, &zone);
2504   if (r == MAILIMF_NO_ERROR) {
2505     /* do nothing */
2506   }
2507   else if (r == MAILIMF_ERROR_PARSE) {
2508     zone = 0;
2509   }
2510   else {
2511     return r;
2512   }
2513
2514   * phour = hour;
2515   * pmin = min;
2516   * psec = sec;
2517   * pzone = zone;
2518
2519   * index = cur_token;
2520
2521   return MAILIMF_NO_ERROR;
2522 }
2523
2524 /*
2525 time-of-day     =       hour ":" minute [ ":" second ]
2526 */
2527
2528 static int mailimf_time_of_day_parse(const char * message, size_t length,
2529                                      size_t * index,
2530                                      int * phour, int * pmin,
2531                                      int * psec)
2532 {
2533   int hour;
2534   int min;
2535   int sec;
2536   size_t cur_token;
2537   int r;
2538
2539   cur_token = * index;
2540
2541   r = mailimf_hour_parse(message, length, &cur_token, &hour);
2542   if (r != MAILIMF_NO_ERROR)
2543     return r;
2544
2545   r = mailimf_colon_parse(message, length, &cur_token);
2546   if (r != MAILIMF_NO_ERROR)
2547     return r;
2548
2549   r = mailimf_minute_parse(message, length, &cur_token, &min);
2550   if (r != MAILIMF_NO_ERROR)
2551     return r;
2552
2553   r = mailimf_colon_parse(message, length, &cur_token);
2554   if (r == MAILIMF_NO_ERROR) {
2555     r = mailimf_second_parse(message, length, &cur_token, &sec);
2556     if (r != MAILIMF_NO_ERROR)
2557       return r;
2558   }
2559   else if (r == MAILIMF_ERROR_PARSE)
2560     sec = 0;
2561   else
2562     return r;
2563
2564   * phour = hour;
2565   * pmin = min;
2566   * psec = sec;
2567   * index = cur_token;
2568
2569   return MAILIMF_NO_ERROR;
2570 }
2571
2572 /*
2573 hour            =       2DIGIT / obs-hour
2574 */
2575
2576 static int mailimf_hour_parse(const char * message, size_t length,
2577                               size_t * index, int * result)
2578 {
2579   uint32_t hour;
2580   int r;
2581
2582   r = mailimf_number_parse(message, length, index, &hour);
2583   if (r != MAILIMF_NO_ERROR)
2584     return r;
2585
2586   * result = hour;
2587
2588   return MAILIMF_NO_ERROR;
2589 }
2590
2591 /*
2592 minute          =       2DIGIT / obs-minute
2593 */
2594
2595 static int mailimf_minute_parse(const char * message, size_t length,
2596                                 size_t * index, int * result)
2597 {
2598   uint32_t minute;
2599   int r;
2600
2601   r = mailimf_number_parse(message, length, index, &minute);
2602   if (r != MAILIMF_NO_ERROR)
2603     return r;
2604
2605   * result = minute;
2606
2607   return MAILIMF_NO_ERROR;
2608 }
2609
2610 /*
2611 second          =       2DIGIT / obs-second
2612 */
2613
2614 static int mailimf_second_parse(const char * message, size_t length,
2615                                 size_t * index, int * result)
2616 {
2617   uint32_t second;
2618   int r;
2619
2620   r = mailimf_number_parse(message, length, index, &second);
2621   if (r != MAILIMF_NO_ERROR)
2622     return r;
2623
2624   * result = second;
2625
2626   return MAILIMF_NO_ERROR;
2627 }
2628
2629 /*
2630 zone            =       (( "+" / "-" ) 4DIGIT) / obs-zone
2631 */
2632
2633 /*
2634 obs-zone        =       "UT" / "GMT" /          ; Universal Time
2635                                                 ; North American UT
2636                                                 ; offsets
2637                         "EST" / "EDT" /         ; Eastern:  - 5/ - 4
2638                         "CST" / "CDT" /         ; Central:  - 6/ - 5
2639                         "MST" / "MDT" /         ; Mountain: - 7/ - 6
2640                         "PST" / "PDT" /         ; Pacific:  - 8/ - 7
2641
2642                         %d65-73 /               ; Military zones - "A"
2643                         %d75-90 /               ; through "I" and "K"
2644                         %d97-105 /              ; through "Z", both
2645                         %d107-122               ; upper and lower case
2646 */
2647
2648 enum {
2649   STATE_ZONE_1 = 0,
2650   STATE_ZONE_2 = 1,
2651   STATE_ZONE_3 = 2,
2652   STATE_ZONE_OK  = 3,
2653   STATE_ZONE_ERR = 4,
2654   STATE_ZONE_CONT = 5,
2655 };
2656
2657 static int mailimf_zone_parse(const char * message, size_t length,
2658                               size_t * index, int * result)
2659 {
2660   uint32_t zone;
2661   int sign;
2662   size_t cur_token;
2663   int r;
2664
2665   cur_token = * index;
2666
2667   if (cur_token + 1 < length) {
2668     if ((message[cur_token] == 'U') && (message[cur_token + 1] == 'T')) {
2669       * result = TRUE;
2670       * index = cur_token + 2;
2671
2672       return MAILIMF_NO_ERROR;
2673     }
2674   }
2675
2676   if (cur_token + 2 < length) {
2677     int state;
2678
2679     state = STATE_ZONE_1;
2680     
2681     while (state <= 2) {
2682       switch (state) {
2683       case STATE_ZONE_1:
2684         switch (message[cur_token]) {
2685         case 'G':
2686           if (message[cur_token + 1] == 'M' && message[cur_token + 2] == 'T') {
2687             zone = 0;
2688             state = STATE_ZONE_OK;
2689           }
2690           else {
2691             state = STATE_ZONE_ERR;
2692           }
2693           break;
2694         case 'E':
2695           zone = -5;
2696           state = STATE_ZONE_2;
2697           break;
2698         case 'C':
2699           zone = -6;
2700           state = STATE_ZONE_2;
2701           break;
2702         case 'M':
2703           zone = -7;
2704           state = STATE_ZONE_2;
2705           break;
2706         case 'P':
2707           zone = -8;
2708           state = STATE_ZONE_2;
2709           break;
2710         default:
2711           state = STATE_ZONE_CONT;
2712           break;
2713         }
2714         break;
2715       case STATE_ZONE_2:
2716         switch (message[cur_token + 1]) {
2717         case 'S':
2718           state = STATE_ZONE_3;
2719           break;
2720         case 'D':
2721           zone ++;
2722           state = STATE_ZONE_3;
2723           break;
2724         default:
2725           state = STATE_ZONE_ERR;
2726           break;
2727         }
2728         break;
2729       case STATE_ZONE_3:
2730         if (message[cur_token + 2] == 'T') {
2731           zone *= 100;
2732           state = STATE_ZONE_OK;
2733         }
2734         else
2735           state = STATE_ZONE_ERR;
2736         break;
2737       }
2738     }
2739
2740     switch (state) {
2741     case STATE_ZONE_OK:
2742       * result = zone;
2743       * index = cur_token + 3;
2744       return MAILIMF_NO_ERROR;
2745       
2746     case STATE_ZONE_ERR:
2747       return MAILIMF_ERROR_PARSE;
2748     }
2749   }
2750
2751   sign = 1;
2752   r = mailimf_plus_parse(message, length, &cur_token);
2753   if (r == MAILIMF_NO_ERROR)
2754     sign = 1;
2755
2756   if (r == MAILIMF_ERROR_PARSE) {
2757     r = mailimf_minus_parse(message, length, &cur_token);
2758     if (r == MAILIMF_NO_ERROR)
2759       sign = -1;
2760   }
2761
2762   if (r == MAILIMF_NO_ERROR) {
2763     /* do nothing */
2764   }
2765   else if (r == MAILIMF_ERROR_PARSE)
2766     sign = 1;
2767   else
2768     return r;
2769
2770   r = mailimf_number_parse(message, length, &cur_token, &zone);
2771   if (r != MAILIMF_NO_ERROR)
2772     return r;
2773
2774   zone = zone * sign;
2775
2776   * index = cur_token;
2777   * result = zone;
2778
2779   return MAILIMF_NO_ERROR;
2780 }
2781
2782 /*
2783 address         =       mailbox / group
2784 */
2785
2786 int mailimf_address_parse(const char * message, size_t length,
2787                           size_t * index,
2788                           struct mailimf_address ** result)
2789 {
2790   int type;
2791   size_t cur_token;
2792   struct mailimf_mailbox * mailbox;
2793   struct mailimf_group * group;
2794   struct mailimf_address * address;
2795   int r;
2796   int res;
2797
2798   cur_token = * index;
2799
2800   mailbox = NULL;
2801   group = NULL;
2802
2803   type = MAILIMF_ADDRESS_ERROR; /* XXX - removes a gcc warning */
2804   r = mailimf_group_parse(message, length, &cur_token, &group);
2805   if (r == MAILIMF_NO_ERROR)
2806     type = MAILIMF_ADDRESS_GROUP;
2807   
2808   if (r == MAILIMF_ERROR_PARSE) {
2809     r = mailimf_mailbox_parse(message, length, &cur_token, &mailbox);
2810     if (r == MAILIMF_NO_ERROR)
2811       type = MAILIMF_ADDRESS_MAILBOX;
2812   }
2813
2814   if (r != MAILIMF_NO_ERROR) {
2815     res = r;
2816     goto err;
2817   }
2818
2819   address = mailimf_address_new(type, mailbox, group);
2820   if (address == NULL) {
2821     res = MAILIMF_ERROR_MEMORY;
2822     goto free;
2823   }
2824
2825   * result = address;
2826   * index = cur_token;
2827
2828   return MAILIMF_NO_ERROR;
2829   
2830  free:
2831   if (mailbox != NULL)
2832     mailimf_mailbox_free(mailbox);
2833   if (group != NULL)
2834     mailimf_group_free(group);
2835  err:
2836   return res;
2837 }
2838
2839
2840 /*
2841 mailbox         =       name-addr / addr-spec
2842 */
2843
2844
2845 int mailimf_mailbox_parse(const char * message, size_t length,
2846                           size_t * index,
2847                           struct mailimf_mailbox ** result)
2848 {
2849   size_t cur_token;
2850   char * display_name;
2851   struct mailimf_mailbox * mailbox;
2852   char * addr_spec;
2853   int r;
2854   int res;
2855
2856   cur_token = * index;
2857   display_name = NULL;
2858   addr_spec = NULL;
2859
2860   r = mailimf_name_addr_parse(message, length, &cur_token,
2861                               &display_name, &addr_spec);
2862   if (r == MAILIMF_ERROR_PARSE)
2863     r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec);
2864
2865   if (r != MAILIMF_NO_ERROR) {
2866     res = r;
2867     goto err;
2868   }
2869
2870   mailbox = mailimf_mailbox_new(display_name, addr_spec);
2871   if (mailbox == NULL) {
2872     res = MAILIMF_ERROR_MEMORY;
2873     goto free;
2874   }
2875
2876   * result = mailbox;
2877   * index = cur_token;
2878
2879   return MAILIMF_NO_ERROR;
2880
2881  free:
2882   if (display_name != NULL)
2883     mailimf_display_name_free(display_name);
2884   if (addr_spec != NULL)
2885     mailimf_addr_spec_free(addr_spec);
2886  err:
2887   return res;
2888 }
2889
2890 /*
2891 name-addr       =       [display-name] angle-addr
2892 */
2893
2894 static int mailimf_name_addr_parse(const char * message, size_t length,
2895                                    size_t * index,
2896                                    char ** pdisplay_name,
2897                                    char ** pangle_addr)
2898 {
2899   char * display_name;
2900   char * angle_addr;
2901   size_t cur_token;
2902   int r;
2903   int res;
2904
2905   cur_token = * index;
2906
2907   display_name = NULL;
2908   angle_addr = NULL;
2909
2910   r = mailimf_display_name_parse(message, length, &cur_token, &display_name);
2911   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
2912     res = r;
2913     goto err;
2914   }
2915
2916   r = mailimf_angle_addr_parse(message, length, &cur_token, &angle_addr);
2917   if (r != MAILIMF_NO_ERROR) {
2918     res = r;
2919     goto free_display_name;
2920   }
2921
2922   * pdisplay_name = display_name;
2923   * pangle_addr = angle_addr;
2924   * index = cur_token;
2925
2926   return MAILIMF_NO_ERROR;
2927
2928  free_display_name:
2929   if (display_name != NULL)
2930     mailimf_display_name_free(display_name);
2931  err:
2932   return res;
2933 }
2934
2935 /*
2936 angle-addr      =       [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
2937 */
2938
2939 static int mailimf_angle_addr_parse(const char * message, size_t length,
2940                                     size_t * index, char ** result)
2941 {
2942   size_t cur_token;
2943   char * addr_spec;
2944   int r;
2945   
2946   cur_token = * index;
2947   
2948   r = mailimf_cfws_parse(message, length, &cur_token);
2949   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
2950     return r;
2951   
2952   r = mailimf_lower_parse(message, length, &cur_token);
2953   if (r != MAILIMF_NO_ERROR)
2954     return r;
2955   
2956   r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec);
2957   if (r != MAILIMF_NO_ERROR)
2958     return r;
2959   
2960   r = mailimf_greater_parse(message, length, &cur_token);
2961   if (r != MAILIMF_NO_ERROR) {
2962     free(addr_spec);
2963     return r;
2964   }
2965
2966   * result = addr_spec;
2967   * index = cur_token;
2968
2969   return MAILIMF_NO_ERROR;
2970 }
2971
2972 /*
2973 group           =       display-name ":" [mailbox-list / CFWS] ";"
2974                         [CFWS]
2975 */
2976
2977 static int mailimf_group_parse(const char * message, size_t length,
2978                                size_t * index,
2979                                struct mailimf_group ** result)
2980 {
2981   size_t cur_token;
2982   char * display_name;
2983   struct mailimf_mailbox_list * mailbox_list;
2984   struct mailimf_group * group;
2985   int r;
2986   int res;
2987
2988   cur_token = * index;
2989
2990   mailbox_list = NULL;
2991
2992   r = mailimf_display_name_parse(message, length, &cur_token, &display_name);
2993   if (r != MAILIMF_NO_ERROR) {
2994     res = r;
2995     goto err;
2996   }
2997
2998   r = mailimf_colon_parse(message, length, &cur_token);
2999   if (r != MAILIMF_NO_ERROR) {
3000     res = r;
3001     goto free_display_name;
3002   }
3003
3004   r = mailimf_mailbox_list_parse(message, length, &cur_token, &mailbox_list);
3005   switch (r) {
3006   case MAILIMF_NO_ERROR:
3007     break;
3008   case MAILIMF_ERROR_PARSE:
3009     r = mailimf_cfws_parse(message, length, &cur_token);
3010     if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
3011       return r;
3012     break;
3013   default:
3014     return r;
3015   }
3016
3017   r = mailimf_semi_colon_parse(message, length, &cur_token);
3018   if (r != MAILIMF_NO_ERROR) {
3019     res = r;
3020     goto free_mailbox_list;
3021   }
3022
3023   group = mailimf_group_new(display_name, mailbox_list);
3024   if (group == NULL) {
3025     res = MAILIMF_ERROR_MEMORY;
3026     goto free_mailbox_list;
3027   }
3028
3029   * index = cur_token;
3030   * result = group;
3031
3032   return MAILIMF_NO_ERROR;
3033
3034  free_mailbox_list:
3035   mailimf_mailbox_list_free(mailbox_list);
3036  free_display_name:
3037   mailimf_display_name_free(display_name);
3038  err:
3039   return res;
3040 }
3041
3042 /*
3043 display-name    =       phrase
3044 */
3045
3046 static int mailimf_display_name_parse(const char * message, size_t length,
3047                                       size_t * index, char ** result)
3048 {
3049   return mailimf_phrase_parse(message, length, index, result);
3050 }
3051
3052 /*
3053 mailbox-list    =       (mailbox *("," mailbox)) / obs-mbox-list
3054 */
3055
3056 int
3057 mailimf_mailbox_list_parse(const char * message, size_t length,
3058                            size_t * index,
3059                            struct mailimf_mailbox_list ** result)
3060 {
3061   size_t cur_token;
3062   clist * list;
3063   struct mailimf_mailbox_list * mailbox_list;
3064   int r;
3065   int res;
3066
3067   cur_token = * index;
3068
3069   r = mailimf_struct_list_parse(message, length, 
3070                                 &cur_token, &list, ',',
3071                                 (mailimf_struct_parser *)
3072                                 mailimf_mailbox_parse,
3073                                 (mailimf_struct_destructor *)
3074                                 mailimf_mailbox_free);
3075   if (r != MAILIMF_NO_ERROR) {
3076     res = r;
3077     goto err;
3078   }
3079
3080   mailbox_list = mailimf_mailbox_list_new(list);
3081   if (mailbox_list == NULL) {
3082     res = MAILIMF_ERROR_MEMORY;
3083     goto free_list;
3084   }
3085
3086   * result = mailbox_list;
3087   * index = cur_token;
3088
3089   return MAILIMF_NO_ERROR;
3090
3091  free_list:
3092   clist_foreach(list, (clist_func) mailimf_mailbox_free, NULL);
3093   clist_free(list);
3094  err:
3095   return res;
3096 }                                  
3097
3098 /*
3099 address-list    =       (address *("," address)) / obs-addr-list
3100 */
3101
3102
3103 int
3104 mailimf_address_list_parse(const char * message, size_t length,
3105                            size_t * index,
3106                            struct mailimf_address_list ** result)
3107 {
3108   size_t cur_token;
3109   clist * list;
3110   struct mailimf_address_list * address_list;
3111   int r;
3112   int res;
3113
3114   cur_token = * index;
3115
3116   r = mailimf_struct_list_parse(message, length,
3117                                 &cur_token, &list, ',',
3118                                 (mailimf_struct_parser *)
3119                                 mailimf_address_parse,
3120                                 (mailimf_struct_destructor *)
3121                                 mailimf_address_free);
3122   if (r != MAILIMF_NO_ERROR) {
3123     res = r;
3124     goto err;
3125   }
3126
3127   address_list = mailimf_address_list_new(list);
3128   if (address_list == NULL) {
3129     res = MAILIMF_ERROR_MEMORY;
3130     goto free_list;
3131   }
3132
3133   * result = address_list;
3134   * index = cur_token;
3135
3136   return MAILIMF_NO_ERROR;
3137
3138  free_list:
3139   clist_foreach(list, (clist_func) mailimf_address_free, NULL);
3140   clist_free(list);
3141  err:
3142   return res;
3143 }                                  
3144
3145 /*
3146 addr-spec       =       local-part "@" domain
3147 */
3148
3149
3150 static int mailimf_addr_spec_parse(const char * message, size_t length,
3151                                    size_t * index,
3152                                    char ** result)
3153 {
3154   size_t cur_token;
3155 #if 0
3156   char * local_part;
3157   char * domain;
3158 #endif
3159   char * addr_spec;
3160   int r;
3161   int res;
3162   size_t begin;
3163   size_t end;
3164   int final;
3165   size_t count;
3166   const char * src;
3167   char * dest;
3168   size_t i;
3169   
3170   cur_token = * index;
3171   
3172   r = mailimf_cfws_parse(message, length, &cur_token);
3173   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
3174     res = r;
3175     goto err;
3176   }
3177
3178   end = cur_token;
3179   if (end >= length) {
3180     res = MAILIMF_ERROR_PARSE;
3181     goto err;
3182   }
3183
3184   begin = cur_token;
3185
3186   final = FALSE;
3187   while (1) {
3188     switch (message[end]) {
3189     case '>':
3190     case ',':
3191     case '\r':
3192     case '\n':
3193     case '(':
3194     case ')':
3195     case ':':
3196     case ';':
3197       final = TRUE;
3198       break;
3199     }
3200
3201     if (final)
3202       break;
3203
3204     end ++;
3205     if (end >= length)
3206       break;
3207   }
3208
3209   if (end == begin) {
3210     res = MAILIMF_ERROR_PARSE;
3211     goto err;
3212   }
3213   
3214   addr_spec = malloc(end - cur_token + 1);
3215   if (addr_spec == NULL) {
3216     res = MAILIMF_ERROR_MEMORY;
3217     goto err;
3218   }
3219   
3220   count = end - cur_token;
3221   src = message + cur_token;
3222   dest = addr_spec;
3223   for(i = 0 ; i < count ; i ++) {
3224     if ((* src != ' ') && (* src != '\t')) {
3225       * dest = * src;
3226       dest ++;
3227     }
3228     src ++;
3229   }
3230   * dest = '\0';
3231   
3232 #if 0
3233   strncpy(addr_spec, message + cur_token, end - cur_token);
3234   addr_spec[end - cur_token] = '\0';
3235 #endif
3236
3237   cur_token = end;
3238
3239 #if 0
3240   r = mailimf_local_part_parse(message, length, &cur_token, &local_part);
3241   if (r != MAILIMF_NO_ERROR) {
3242     res = r;
3243     goto err;
3244   }
3245
3246   r = mailimf_at_sign_parse(message, length, &cur_token);
3247   switch (r) {
3248   case MAILIMF_NO_ERROR:
3249     r = mailimf_domain_parse(message, length, &cur_token, &domain);
3250     if (r != MAILIMF_NO_ERROR) {
3251       res = r;
3252       goto free_local_part;
3253     }
3254     break;
3255
3256   case MAILIMF_ERROR_PARSE:
3257     domain = NULL;
3258     break;
3259
3260   default:
3261     res = r;
3262     goto free_local_part;
3263   }
3264
3265   if (domain) {
3266     addr_spec = malloc(strlen(local_part) + strlen(domain) + 2);
3267     if (addr_spec == NULL) {
3268       res = MAILIMF_ERROR_MEMORY;
3269       goto free_domain;
3270     }
3271     
3272     strcpy(addr_spec, local_part);
3273     strcat(addr_spec, "@");
3274     strcat(addr_spec, domain);
3275
3276     mailimf_domain_free(domain);
3277     mailimf_local_part_free(local_part);
3278   }
3279   else {
3280     addr_spec = local_part;
3281   }
3282 #endif
3283
3284   * result = addr_spec;
3285   * index = cur_token;
3286
3287   return MAILIMF_NO_ERROR;
3288
3289 #if 0
3290  free_domain:
3291   mailimf_domain_free(domain);
3292  free_local_part:
3293   mailimf_local_part_free(local_part);
3294 #endif
3295  err:
3296   return res;
3297 }
3298
3299 /*
3300 local-part      =       dot-atom / quoted-string / obs-local-part
3301 */
3302
3303 #if 0
3304 static int mailimf_local_part_parse(const char * message, size_t length,
3305                                     size_t * index,
3306                                     char ** result)
3307 {
3308   int r;
3309
3310   r = mailimf_dot_atom_parse(message, length, index, result);
3311   switch (r) {
3312   case MAILIMF_NO_ERROR:
3313     return r;
3314   case MAILIMF_ERROR_PARSE:
3315     break;
3316   default:
3317     return r;
3318   }
3319
3320   r = mailimf_quoted_string_parse(message, length, index, result);
3321   if (r != MAILIMF_NO_ERROR)
3322     return r;
3323
3324   return MAILIMF_NO_ERROR;
3325 }
3326 #endif
3327
3328 /*
3329 domain          =       dot-atom / domain-literal / obs-domain
3330 */
3331
3332 #if 0
3333 static int mailimf_domain_parse(const char * message, size_t length,
3334                                 size_t * index,
3335                                 char ** result)
3336 {
3337   int r;
3338
3339   r = mailimf_dot_atom_parse(message, length, index, result);
3340   switch (r) {
3341   case MAILIMF_NO_ERROR:
3342     return r;
3343   case MAILIMF_ERROR_PARSE:
3344     break;
3345   default:
3346     return r;
3347   }
3348
3349   r = mailimf_domain_literal_parse(message, length, index, result);
3350   if (r != MAILIMF_NO_ERROR)
3351     return r;
3352
3353   return MAILIMF_NO_ERROR;
3354 }
3355 #endif
3356
3357 /*
3358 [FWS] dcontent
3359 */
3360
3361 #if 0
3362 static int
3363 mailimf_domain_literal_fws_dcontent_parse(const char * message, size_t length,
3364                                           size_t * index)
3365 {
3366   size_t cur_token;
3367   char ch;
3368   int r;
3369
3370   cur_token = * index;
3371
3372   r = mailimf_cfws_parse(message, length, &cur_token);
3373   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
3374     return r;
3375   
3376   r = mailimf_dcontent_parse(message, length, &cur_token, &ch);
3377   if (r != MAILIMF_NO_ERROR)
3378     return r;
3379
3380   * index = cur_token;
3381
3382   return MAILIMF_NO_ERROR;
3383 }
3384 #endif
3385
3386 /*
3387 domain-literal  =       [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
3388 */
3389
3390 #if 0
3391 static int mailimf_domain_literal_parse(const char * message, size_t length,
3392                                         size_t * index, char ** result)
3393 {
3394   size_t cur_token;
3395   int len;
3396   int begin;
3397   char * domain_literal;
3398   int r;
3399
3400   cur_token = * index;
3401
3402   r = mailimf_cfws_parse(message, length, &cur_token);
3403   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
3404     return r;
3405
3406   begin = cur_token;
3407   r = mailimf_obracket_parse(message, length, &cur_token);
3408   if (r != MAILIMF_NO_ERROR)
3409     return r;
3410
3411   while (1) {
3412     r = mailimf_domain_literal_fws_dcontent_parse(message, length,
3413                                                   &cur_token);
3414     if (r == MAILIMF_NO_ERROR) {
3415       /* do nothing */
3416     }
3417     else if (r == MAILIMF_ERROR_PARSE)
3418       break;
3419     else
3420       return r;
3421   }
3422
3423   r = mailimf_fws_parse(message, length, &cur_token);
3424   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
3425     return r;
3426
3427   r = mailimf_cbracket_parse(message, length, &cur_token);
3428   if (r != MAILIMF_NO_ERROR)
3429     return r;
3430
3431   len = cur_token - begin;
3432
3433   domain_literal = malloc(len + 1);
3434   if (domain_literal == NULL)
3435     return MAILIMF_ERROR_MEMORY;
3436   strncpy(domain_literal, message + begin, len);
3437   domain_literal[len] = '\0';
3438
3439   * result = domain_literal;
3440   * index = cur_token;
3441
3442   return MAILIMF_NO_ERROR;
3443 }
3444 #endif
3445
3446 /*
3447 dcontent        =       dtext / quoted-pair
3448 */
3449
3450 #if 0
3451 static int mailimf_dcontent_parse(const char * message, size_t length,
3452                                   size_t * index, char * result)
3453 {
3454   size_t cur_token;
3455   char ch;
3456   int r;
3457   
3458   cur_token = * index;
3459
3460   if (cur_token >= length)
3461     return MAILIMF_ERROR_PARSE;
3462
3463   if (is_dtext(message[cur_token])) {
3464     ch = message[cur_token];
3465     cur_token ++;
3466   }
3467   else {
3468     r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
3469     
3470     if (r != MAILIMF_NO_ERROR)
3471       return r;
3472   }
3473     
3474   * index = cur_token;
3475   * result = ch;
3476
3477   return MAILIMF_NO_ERROR;
3478 }
3479 #endif
3480
3481
3482 /*
3483 dtext           =       NO-WS-CTL /     ; Non white space controls
3484
3485                         %d33-90 /       ; The rest of the US-ASCII
3486                         %d94-126        ;  characters not including "[",
3487                                         ;  "]", or "\"
3488 */
3489
3490 static inline int is_dtext(char ch)
3491 {
3492   unsigned char uch = (unsigned char) ch;
3493
3494   if (is_no_ws_ctl(ch))
3495     return TRUE;
3496
3497   if (uch < 33)
3498     return FALSE;
3499
3500   if ((uch >= 91) && (uch <= 93))
3501     return FALSE;
3502
3503   if (uch == 127)
3504     return FALSE;
3505
3506   return TRUE;
3507 }
3508
3509 /*
3510 message         =       (fields / obs-fields)
3511                         [CRLF body]
3512 */
3513
3514 int mailimf_message_parse(const char * message, size_t length,
3515                           size_t * index,
3516                           struct mailimf_message ** result)
3517 {
3518   struct mailimf_fields * fields;
3519   struct mailimf_body * body;
3520   struct mailimf_message * msg;
3521   size_t cur_token;
3522   int r;
3523   int res;
3524
3525   cur_token = * index;
3526
3527   r = mailimf_fields_parse(message, length, &cur_token, &fields);
3528   if (r != MAILIMF_NO_ERROR) {
3529     res = r;
3530     goto err;
3531   }
3532
3533   r = mailimf_crlf_parse(message, length, &cur_token);
3534   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
3535     res = r;
3536     goto err;
3537   }
3538
3539   r = mailimf_body_parse(message, length, &cur_token, &body);
3540   if (r != MAILIMF_NO_ERROR) {
3541     res = r;
3542     goto free_fields;
3543   }
3544
3545   msg = mailimf_message_new(fields, body);
3546   if (msg == NULL) {
3547     res = MAILIMF_ERROR_MEMORY;
3548     goto free_body;
3549   }
3550
3551   * index = cur_token;
3552   * result = msg;
3553
3554   return MAILIMF_NO_ERROR;
3555
3556  free_body:
3557   mailimf_body_free(body);
3558  free_fields:
3559   mailimf_fields_free(fields);
3560  err:
3561   return res;
3562 }
3563
3564 /*
3565 body            =       *(*998text CRLF) *998text
3566 */
3567
3568 int mailimf_body_parse(const char * message, size_t length,
3569                        size_t * index,
3570                        struct mailimf_body ** result)
3571 {
3572   size_t cur_token;
3573   struct mailimf_body * body;
3574
3575   cur_token = * index;
3576
3577   body = mailimf_body_new(message + cur_token, length - cur_token);
3578   if (body == NULL)
3579     return MAILIMF_ERROR_MEMORY;
3580
3581   cur_token = length;
3582
3583   * result = body;
3584   * index = cur_token;
3585
3586   return MAILIMF_NO_ERROR;
3587 }
3588
3589 /*
3590 CHANGE TO THE RFC 2822
3591
3592 original :
3593
3594 fields          =       *(trace
3595                           *(resent-date /
3596                            resent-from /
3597                            resent-sender /
3598                            resent-to /
3599                            resent-cc /
3600                            resent-bcc /
3601                            resent-msg-id))
3602                         *(orig-date /
3603                         from /
3604                         sender /
3605                         reply-to /
3606                         to /
3607                         cc /
3608                         bcc /
3609                         message-id /
3610                         in-reply-to /
3611                         references /
3612                         subject /
3613                         comments /
3614                         keywords /
3615                         optional-field)
3616
3617 INTO THE FOLLOWING :
3618 */
3619
3620 /*
3621 resent-fields-list =      *(resent-date /
3622                            resent-from /
3623                            resent-sender /
3624                            resent-to /
3625                            resent-cc /
3626                            resent-bcc /
3627                            resent-msg-id))
3628 */
3629
3630 #if 0
3631 enum {
3632   RESENT_HEADER_START,
3633 };
3634
3635 static int guess_resent_header_type(char * message,
3636                                     size_t length, size_t index)
3637 {
3638   int r;
3639
3640   r = mailimf_token_case_insensitive_parse(message,
3641                                            length, &index, "Resent-");
3642   if (r != MAILIMF_NO_ERROR)
3643     return MAILIMF_RESENT_FIELD_NONE;
3644   
3645   if (index >= length)
3646     return MAILIMF_RESENT_FIELD_NONE;
3647
3648   switch(toupper(message[index])) {
3649   case 'D':
3650     return MAILIMF_RESENT_FIELD_DATE;
3651   case 'F':
3652     return MAILIMF_RESENT_FIELD_FROM;
3653   case 'S':
3654     return MAILIMF_RESENT_FIELD_SENDER;
3655   case 'T':
3656     return MAILIMF_RESENT_FIELD_TO;
3657   case 'C':
3658     return MAILIMF_RESENT_FIELD_CC;
3659   case 'B':
3660     return MAILIMF_RESENT_FIELD_BCC;
3661   case 'M':
3662     return MAILIMF_RESENT_FIELD_MSG_ID;
3663   default:
3664     return MAILIMF_RESENT_FIELD_NONE;
3665   }
3666 }
3667 #endif
3668
3669 #if 0
3670 static int
3671 mailimf_resent_field_parse(const char * message, size_t length,
3672                            size_t * index,
3673                            struct mailimf_resent_field ** result)
3674 {
3675   struct mailimf_orig_date * resent_date;
3676   struct mailimf_from * resent_from;
3677   struct mailimf_sender * resent_sender;
3678   struct mailimf_to* resent_to;
3679   struct mailimf_cc * resent_cc;
3680   struct mailimf_bcc * resent_bcc;
3681   struct mailimf_message_id * resent_msg_id;
3682   size_t cur_token;
3683   int type;
3684   struct mailimf_resent_field * resent_field;
3685   int r;
3686   int res;
3687
3688   cur_token = * index;
3689
3690   resent_date = NULL;
3691   resent_from = NULL;
3692   resent_sender = NULL;
3693   resent_to = NULL;
3694   resent_cc = NULL;
3695   resent_bcc = NULL;
3696   resent_msg_id = NULL;
3697
3698   type = guess_resent_header_type(message, length, cur_token);
3699
3700   switch(type) {
3701   case MAILIMF_RESENT_FIELD_DATE:
3702     r = mailimf_resent_date_parse(message, length, &cur_token,
3703                                   &resent_date);
3704     if (r != MAILIMF_NO_ERROR) {
3705       res = r;
3706       goto err;
3707     }
3708     break;
3709   case MAILIMF_RESENT_FIELD_FROM:
3710     r = mailimf_resent_from_parse(message, length, &cur_token,
3711                                   &resent_from);
3712     if (r != MAILIMF_NO_ERROR) {
3713       res = r;
3714       goto err;
3715     }
3716     break;
3717   case MAILIMF_RESENT_FIELD_SENDER:
3718     r = mailimf_resent_sender_parse(message, length, &cur_token,
3719                                     &resent_sender);
3720     if (r != MAILIMF_NO_ERROR) {
3721       res = r;
3722       goto err;
3723     }
3724     break;
3725   case MAILIMF_RESENT_FIELD_TO:
3726     r = mailimf_resent_to_parse(message, length, &cur_token,
3727                                 &resent_to);
3728     if (r != MAILIMF_NO_ERROR) {
3729       res = r;
3730       goto err;
3731     }
3732     break;
3733   case MAILIMF_RESENT_FIELD_CC:
3734     r= mailimf_resent_cc_parse(message, length, &cur_token,
3735                                &resent_cc);
3736     if (r != MAILIMF_NO_ERROR) {
3737       res = r;
3738       goto err;
3739     }
3740     break;
3741   case MAILIMF_RESENT_FIELD_BCC:
3742     r = mailimf_resent_bcc_parse(message, length, &cur_token,
3743                                  &resent_bcc);
3744     if (r != MAILIMF_NO_ERROR) {
3745       res = r;
3746       goto err;
3747     }
3748     break;
3749   case MAILIMF_RESENT_FIELD_MSG_ID:
3750     r = mailimf_resent_msg_id_parse(message, length, &cur_token,
3751                                     &resent_msg_id);
3752     if (r != MAILIMF_NO_ERROR) {
3753       res = r;
3754       goto err;
3755     }
3756     break;
3757   default:
3758     res = MAILIMF_ERROR_PARSE;
3759     goto err;
3760   }
3761
3762   resent_field = mailimf_resent_field_new(type, resent_date,
3763                                           resent_from, resent_sender,
3764                                           resent_to, resent_cc,
3765                                           resent_bcc, resent_msg_id);
3766   if (resent_field == NULL) {
3767     res = MAILIMF_ERROR_MEMORY;
3768     goto free_resent;
3769   }
3770
3771   * result = resent_field;
3772   * index = cur_token;
3773
3774   return MAILIMF_NO_ERROR;
3775
3776  free_resent:
3777   if (resent_msg_id != NULL)
3778     mailimf_message_id_free(resent_msg_id);
3779   if (resent_bcc != NULL)
3780     mailimf_bcc_free(resent_bcc);
3781   if (resent_cc != NULL)
3782     mailimf_cc_free(resent_cc);
3783   if (resent_to != NULL)
3784     mailimf_to_free(resent_to);
3785   if (resent_sender != NULL)
3786     mailimf_sender_free(resent_sender);
3787   if (resent_from != NULL)
3788     mailimf_from_free(resent_from);
3789   if (resent_date != NULL)
3790     mailimf_orig_date_free(resent_date);
3791  err:
3792   return res;
3793 }
3794 #endif
3795
3796 #if 0
3797 static int
3798 mailimf_resent_fields_list_parse(const char * message, size_t length,
3799                                  size_t * index,
3800                                  struct mailimf_resent_fields_list ** result)
3801 {
3802   clist * list;
3803   size_t cur_token;
3804   struct mailimf_resent_fields_list * resent_fields_list;
3805   int r;
3806   int res;
3807
3808   cur_token = * index;
3809   list = NULL;
3810
3811   r = mailimf_struct_multiple_parse(message, length, &cur_token, &list,
3812                                     (mailimf_struct_parser *)
3813                                     mailimf_resent_field_parse,
3814                                     (mailimf_struct_destructor *)
3815                                     mailimf_resent_field_free);
3816   if (r != MAILIMF_NO_ERROR) {
3817     res = r;
3818     goto err;
3819   }
3820
3821   resent_fields_list = mailimf_resent_fields_list_new(list);
3822   if (resent_fields_list == NULL) {
3823     res = MAILIMF_ERROR_MEMORY;
3824     goto free_list;
3825   }
3826
3827   * result = resent_fields_list;
3828   * index = cur_token;
3829
3830   return MAILIMF_NO_ERROR;
3831
3832  free_list:
3833   clist_foreach(list, (clist_func) mailimf_resent_field_free, NULL);
3834   clist_free(list);
3835  err:
3836   return res;
3837 }
3838 #endif
3839
3840 /*
3841  ([trace]
3842   [resent-fields-list])
3843 */
3844
3845 #if 0
3846 static int
3847 mailimf_trace_resent_fields_parse(const char * message, size_t length,
3848                                   size_t * index,
3849                                   struct mailimf_trace_resent_fields ** result)
3850 {
3851   size_t cur_token;
3852   struct mailimf_return * return_path;
3853   struct mailimf_resent_fields_list * resent_fields;
3854   struct mailimf_trace_resent_fields * trace_resent_fields;
3855   int res;
3856   int r;
3857
3858   cur_token = * index;
3859
3860   return_path = NULL;
3861   resent_fields = NULL;
3862
3863   r = mailimf_return_parse(message, length, &cur_token,
3864                            &return_path);
3865   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
3866     res = r;
3867     goto err;
3868   }
3869
3870   r = mailimf_resent_fields_list_parse(message, length, &cur_token,
3871                                        &resent_fields);
3872   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
3873     res = r;
3874     goto err;
3875   }
3876
3877   if ((return_path == NULL) && (resent_fields == NULL)) {
3878     res = MAILIMF_ERROR_PARSE;
3879     goto err;
3880   }
3881
3882   trace_resent_fields = mailimf_trace_resent_fields_new(return_path,
3883                                                         resent_fields);
3884   if (trace_resent_fields == NULL) {
3885     res = MAILIMF_ERROR_MEMORY;
3886     goto free_resent_fields;
3887   }
3888
3889   * result = trace_resent_fields;
3890   * index = cur_token;
3891
3892   return MAILIMF_NO_ERROR;
3893
3894  free_resent_fields:
3895   if (resent_fields != NULL)
3896     mailimf_resent_fields_list_free(resent_fields);
3897   if (return_path != NULL)
3898     mailimf_return_free(return_path);
3899  err:
3900   return res;
3901 }
3902 #endif
3903
3904 /*
3905 delivering-info =       *([trace]
3906                           [resent-fields-list])
3907 */
3908
3909 #if 0
3910 static int
3911 mailimf_delivering_info_parse(const char * message, size_t length,
3912                               size_t * index,
3913                               struct mailimf_delivering_info ** result)
3914 {
3915   size_t cur_token;
3916   clist * list;
3917   struct mailimf_delivering_info * delivering_info;
3918   int r;
3919   int res;
3920
3921   cur_token = * index;
3922
3923   r = mailimf_struct_multiple_parse(message, length, &cur_token,
3924                                     &list,
3925                                     (mailimf_struct_parser *)
3926                                     mailimf_trace_resent_fields_parse,
3927                                     (mailimf_struct_destructor *)
3928                                     mailimf_trace_resent_fields_free);
3929   if (r != MAILIMF_NO_ERROR) {
3930     res = r;
3931     goto err;
3932   }
3933
3934   delivering_info = mailimf_delivering_info_new(list);
3935   if (delivering_info == NULL) {
3936     res = MAILIMF_ERROR_MEMORY;
3937     goto free_list;
3938   }
3939
3940   * result = delivering_info;
3941   * index = cur_token;
3942
3943   return MAILIMF_NO_ERROR;
3944
3945  free_list:
3946   clist_foreach(list, (clist_func) mailimf_trace_resent_fields_free, NULL);
3947   clist_free(list);
3948  err:
3949   return res;
3950 }
3951 #endif
3952
3953 /*
3954 field           =       delivering-info /
3955                         orig-date /
3956                         from /
3957                         sender /
3958                         reply-to /
3959                         to /
3960                         cc /
3961                         bcc /
3962                         message-id /
3963                         in-reply-to /
3964                         references /
3965                         subject /
3966                         comments /
3967                         keywords /
3968                         optional-field
3969 */
3970
3971 enum {
3972   HEADER_START,
3973   HEADER_C,
3974   HEADER_R,
3975   HEADER_RE,
3976   HEADER_S,
3977   HEADER_RES,
3978 };
3979
3980 static int guess_header_type(const char * message, size_t length, size_t index)
3981 {
3982   int state;
3983   int r;
3984
3985   state = HEADER_START;
3986   
3987   while (1) {
3988
3989     if (index >= length)
3990       return MAILIMF_FIELD_NONE;
3991
3992     switch(state) {
3993     case HEADER_START:
3994       switch((char) toupper((unsigned char) message[index])) {
3995       case 'B':
3996         return MAILIMF_FIELD_BCC;
3997       case 'C':
3998         state = HEADER_C;
3999         break;
4000       case 'D':
4001         return MAILIMF_FIELD_ORIG_DATE;
4002       case 'F':
4003         return MAILIMF_FIELD_FROM;
4004       case 'I':
4005         return MAILIMF_FIELD_IN_REPLY_TO;
4006       case 'K':
4007         return MAILIMF_FIELD_KEYWORDS;
4008       case 'M':
4009         return MAILIMF_FIELD_MESSAGE_ID;
4010       case 'R':
4011         state = HEADER_R;
4012         break;
4013       case 'T':
4014         return MAILIMF_FIELD_TO;
4015         break;
4016       case 'S':
4017         state = HEADER_S;
4018         break;
4019       default:
4020         return MAILIMF_FIELD_NONE;
4021       }
4022       break;
4023     case HEADER_C:
4024       switch((char) toupper((unsigned char) message[index])) {
4025       case 'O':
4026         return MAILIMF_FIELD_COMMENTS;
4027       case 'C':
4028         return MAILIMF_FIELD_CC;
4029       default:
4030         return MAILIMF_FIELD_NONE;
4031       }
4032       break;
4033     case HEADER_R:
4034       switch((char) toupper((unsigned char) message[index])) {
4035       case 'E':
4036         state = HEADER_RE;
4037         break;
4038       default:
4039         return MAILIMF_FIELD_NONE;
4040       }
4041       break;
4042     case HEADER_RE:
4043       switch((char) toupper((unsigned char) message[index])) {
4044       case 'F':
4045         return MAILIMF_FIELD_REFERENCES;
4046       case 'P':
4047         return MAILIMF_FIELD_REPLY_TO;
4048       case 'S':
4049         state = HEADER_RES;
4050         break;
4051       case 'T':
4052         return MAILIMF_FIELD_RETURN_PATH;
4053       default:
4054         return MAILIMF_FIELD_NONE;
4055       }
4056       break;
4057     case HEADER_S:
4058       switch((char) toupper((unsigned char) message[index])) {
4059       case 'E':
4060         return MAILIMF_FIELD_SENDER;
4061       case 'U':
4062         return MAILIMF_FIELD_SUBJECT;
4063       default:
4064         return MAILIMF_FIELD_NONE;
4065       }
4066       break;
4067
4068     case HEADER_RES:
4069       r = mailimf_token_case_insensitive_parse(message,
4070           length, &index, "ent-");
4071       if (r != MAILIMF_NO_ERROR)
4072         return MAILIMF_FIELD_NONE;
4073       
4074       if (index >= length)
4075         return MAILIMF_FIELD_NONE;
4076       
4077       switch((char) toupper((unsigned char) message[index])) {
4078       case 'D':
4079         return MAILIMF_FIELD_RESENT_DATE;
4080       case 'F':
4081         return MAILIMF_FIELD_RESENT_FROM;
4082       case 'S':
4083         return MAILIMF_FIELD_RESENT_SENDER;
4084       case 'T':
4085         return MAILIMF_FIELD_RESENT_TO;
4086       case 'C':
4087         return MAILIMF_FIELD_RESENT_CC;
4088       case 'B':
4089         return MAILIMF_FIELD_RESENT_BCC;
4090       case 'M':
4091         return MAILIMF_FIELD_RESENT_MSG_ID;
4092       default:
4093         return MAILIMF_FIELD_NONE;
4094       }
4095       break;
4096     }
4097     index ++;
4098   }
4099 }
4100
4101 static int mailimf_field_parse(const char * message, size_t length,
4102                                size_t * index,
4103                                struct mailimf_field ** result)
4104 {
4105   size_t cur_token;
4106   int type;
4107   struct mailimf_return * return_path;
4108   struct mailimf_orig_date * resent_date;
4109   struct mailimf_from * resent_from;
4110   struct mailimf_sender * resent_sender;
4111   struct mailimf_to* resent_to;
4112   struct mailimf_cc * resent_cc;
4113   struct mailimf_bcc * resent_bcc;
4114   struct mailimf_message_id * resent_msg_id;
4115   struct mailimf_orig_date * orig_date;
4116   struct mailimf_from * from;
4117   struct mailimf_sender * sender;
4118   struct mailimf_reply_to * reply_to;
4119   struct mailimf_to * to;
4120   struct mailimf_cc * cc;
4121   struct mailimf_bcc * bcc;
4122   struct mailimf_message_id * message_id;
4123   struct mailimf_in_reply_to * in_reply_to;
4124   struct mailimf_references * references;
4125   struct mailimf_subject * subject;
4126   struct mailimf_comments * comments;
4127   struct mailimf_keywords * keywords;
4128   struct mailimf_optional_field * optional_field;
4129   struct mailimf_field * field;
4130   int guessed_type;
4131   int r;
4132   int res;
4133   
4134   cur_token = * index;
4135
4136   return_path = NULL;
4137   resent_date = NULL;
4138   resent_from = NULL;
4139   resent_sender = NULL;
4140   resent_to = NULL;
4141   resent_cc = NULL;
4142   resent_bcc = NULL;
4143   resent_msg_id = NULL;
4144   orig_date = NULL;
4145   from = NULL;
4146   sender = NULL;
4147   reply_to = NULL;
4148   to = NULL;
4149   cc = NULL;
4150   bcc = NULL;
4151   message_id = NULL;
4152   in_reply_to = NULL;
4153   references = NULL;
4154   subject = NULL;
4155   comments = NULL;
4156   keywords = NULL;
4157   optional_field = NULL;
4158
4159   guessed_type = guess_header_type(message, length, cur_token);
4160   type = MAILIMF_FIELD_NONE;
4161
4162   switch (guessed_type) {
4163   case MAILIMF_FIELD_ORIG_DATE:
4164     r = mailimf_orig_date_parse(message, length, &cur_token,
4165                                 &orig_date);
4166     if (r == MAILIMF_NO_ERROR)
4167       type = MAILIMF_FIELD_ORIG_DATE;
4168     else if (r == MAILIMF_ERROR_PARSE) {
4169       /* do nothing */
4170     }
4171     else {
4172       res = r;
4173       goto err;
4174     }
4175     break;
4176   case MAILIMF_FIELD_FROM:
4177     r = mailimf_from_parse(message, length, &cur_token,
4178                            &from);
4179     if (r == MAILIMF_NO_ERROR)
4180       type = guessed_type;
4181     else if (r == MAILIMF_ERROR_PARSE) {
4182       /* do nothing */
4183     }
4184     else {
4185       res = r;
4186       goto err;
4187     }
4188     break;
4189   case MAILIMF_FIELD_SENDER:
4190     r = mailimf_sender_parse(message, length, &cur_token,
4191                              &sender);
4192     if (r == MAILIMF_NO_ERROR)
4193       type = guessed_type;
4194     else if (r == MAILIMF_ERROR_PARSE) {
4195       /* do nothing */
4196     }
4197     else {
4198       res = r;
4199       goto err;
4200     }
4201     break;
4202   case MAILIMF_FIELD_REPLY_TO:
4203     r = mailimf_reply_to_parse(message, length, &cur_token,
4204                                &reply_to);
4205     if (r == MAILIMF_NO_ERROR)
4206       type = guessed_type;
4207     else if (r == MAILIMF_ERROR_PARSE) {
4208       /* do nothing */
4209     }
4210     else {
4211       res = r;
4212       goto err;
4213     }
4214     break;
4215   case MAILIMF_FIELD_TO:
4216     r = mailimf_to_parse(message, length, &cur_token,
4217                          &to);
4218     if (r == MAILIMF_NO_ERROR)
4219       type = guessed_type;
4220     else if (r == MAILIMF_ERROR_PARSE) {
4221       /* do nothing */
4222     }
4223     else {
4224       res = r;
4225       goto err;
4226     }
4227     break;
4228   case MAILIMF_FIELD_CC:
4229     r = mailimf_cc_parse(message, length, &cur_token,
4230                          &cc);
4231     if (r == MAILIMF_NO_ERROR)
4232       type = guessed_type;
4233     else if (r == MAILIMF_ERROR_PARSE) {
4234       /* do nothing */
4235     }
4236     else {
4237       res = r;
4238       goto err;
4239     }
4240     break;
4241   case MAILIMF_FIELD_BCC:
4242     r = mailimf_bcc_parse(message, length, &cur_token,
4243                           &bcc);
4244     if (r == MAILIMF_NO_ERROR)
4245       type = guessed_type;
4246     else if (r == MAILIMF_ERROR_PARSE) {
4247       /* do nothing */
4248     }
4249     else {
4250       res = r;
4251       goto err;
4252     }
4253     break;
4254   case MAILIMF_FIELD_MESSAGE_ID:
4255     r = mailimf_message_id_parse(message, length, &cur_token,
4256                                  &message_id);
4257     if (r == MAILIMF_NO_ERROR)
4258       type = guessed_type;
4259     else if (r == MAILIMF_ERROR_PARSE) {
4260       /* do nothing */
4261     }
4262     else {
4263       res = r;
4264       goto err;
4265     }
4266     break;
4267   case MAILIMF_FIELD_IN_REPLY_TO:
4268     r = mailimf_in_reply_to_parse(message, length, &cur_token,
4269                                   &in_reply_to);
4270     if (r == MAILIMF_NO_ERROR)
4271       type = guessed_type;
4272     else if (r == MAILIMF_ERROR_PARSE) {
4273       /* do nothing */
4274     }
4275     else {
4276       res = r;
4277       goto err;
4278     }
4279     break;
4280   case MAILIMF_FIELD_REFERENCES:
4281     r = mailimf_references_parse(message, length, &cur_token,
4282                                  &references);
4283     if (r == MAILIMF_NO_ERROR)
4284       type = guessed_type;
4285     else if (r == MAILIMF_ERROR_PARSE) {
4286       /* do nothing */
4287     }
4288     else {
4289       res = r;
4290       goto err;
4291     }
4292     break;
4293   case MAILIMF_FIELD_SUBJECT:
4294     r = mailimf_subject_parse(message, length, &cur_token,
4295                               &subject);
4296     if (r == MAILIMF_NO_ERROR)
4297       type = guessed_type;
4298     else if (r == MAILIMF_ERROR_PARSE) {
4299       /* do nothing */
4300     }
4301     else {
4302       res = r;
4303       goto err;
4304     }
4305     break;
4306   case MAILIMF_FIELD_COMMENTS:
4307     r = mailimf_comments_parse(message, length, &cur_token,
4308                                &comments);
4309     if (r == MAILIMF_NO_ERROR)
4310       type = guessed_type;
4311     else if (r == MAILIMF_ERROR_PARSE) {
4312       /* do nothing */
4313     }
4314     else {
4315       res = r;
4316       goto err;
4317     }
4318     break;
4319   case MAILIMF_FIELD_KEYWORDS:
4320     r = mailimf_keywords_parse(message, length, &cur_token,
4321                                &keywords);
4322     if (r == MAILIMF_NO_ERROR)
4323       type = guessed_type;
4324     else if (r == MAILIMF_ERROR_PARSE) {
4325       /* do nothing */
4326     }
4327     else {
4328       res = r;
4329       goto err;
4330     }
4331     break;
4332   case MAILIMF_FIELD_RETURN_PATH:
4333     r = mailimf_return_parse(message, length, &cur_token,
4334         &return_path);
4335     if (r == MAILIMF_NO_ERROR)
4336       type = guessed_type;
4337     else if (r == MAILIMF_ERROR_PARSE) {
4338       /* do nothing */
4339     }
4340     else {
4341       res = r;
4342       goto err;
4343     }
4344     break;
4345   case MAILIMF_FIELD_RESENT_DATE:
4346     r = mailimf_resent_date_parse(message, length, &cur_token,
4347                                   &resent_date);
4348     if (r == MAILIMF_NO_ERROR)
4349       type = guessed_type;
4350     else if (r == MAILIMF_ERROR_PARSE) {
4351       /* do nothing */
4352     }
4353     else {
4354       res = r;
4355       goto err;
4356     }
4357     break;
4358   case MAILIMF_FIELD_RESENT_FROM:
4359     r = mailimf_resent_from_parse(message, length, &cur_token,
4360                                   &resent_from);
4361     if (r == MAILIMF_NO_ERROR)
4362       type = guessed_type;
4363     else if (r == MAILIMF_ERROR_PARSE) {
4364       /* do nothing */
4365     }
4366     else {
4367       res = r;
4368       goto err;
4369     }
4370     break;
4371   case MAILIMF_FIELD_RESENT_SENDER:
4372     r = mailimf_resent_sender_parse(message, length, &cur_token,
4373                                     &resent_sender);
4374     if (r == MAILIMF_NO_ERROR)
4375       type = guessed_type;
4376     else if (r == MAILIMF_ERROR_PARSE) {
4377       /* do nothing */
4378     }
4379     else {
4380       res = r;
4381       goto err;
4382     }
4383     break;
4384   case MAILIMF_FIELD_RESENT_TO:
4385     r = mailimf_resent_to_parse(message, length, &cur_token,
4386                                 &resent_to);
4387     if (r == MAILIMF_NO_ERROR)
4388       type = guessed_type;
4389     else if (r == MAILIMF_ERROR_PARSE) {
4390       /* do nothing */
4391     }
4392     else {
4393       res = r;
4394       goto err;
4395     }
4396     break;
4397   case MAILIMF_FIELD_RESENT_CC:
4398     r= mailimf_resent_cc_parse(message, length, &cur_token,
4399                                &resent_cc);
4400     if (r == MAILIMF_NO_ERROR)
4401       type = guessed_type;
4402     else if (r == MAILIMF_ERROR_PARSE) {
4403       /* do nothing */
4404     }
4405     else {
4406       res = r;
4407       goto err;
4408     }
4409     break;
4410   case MAILIMF_FIELD_RESENT_BCC:
4411     r = mailimf_resent_bcc_parse(message, length, &cur_token,
4412                                  &resent_bcc);
4413     if (r == MAILIMF_NO_ERROR)
4414       type = guessed_type;
4415     else if (r == MAILIMF_ERROR_PARSE) {
4416       /* do nothing */
4417     }
4418     else {
4419       res = r;
4420       goto err;
4421     }
4422     break;
4423   case MAILIMF_FIELD_RESENT_MSG_ID:
4424     r = mailimf_resent_msg_id_parse(message, length, &cur_token,
4425                                     &resent_msg_id);
4426     if (r == MAILIMF_NO_ERROR)
4427       type = guessed_type;
4428     else if (r == MAILIMF_ERROR_PARSE) {
4429       /* do nothing */
4430     }
4431     else {
4432       res = r;
4433       goto err;
4434     }
4435     break;
4436   }
4437
4438   if (type == MAILIMF_FIELD_NONE) {
4439     r = mailimf_optional_field_parse(message, length, &cur_token,
4440         &optional_field);
4441     if (r != MAILIMF_NO_ERROR) {
4442       res = r;
4443       goto err;
4444     }
4445
4446     type = MAILIMF_FIELD_OPTIONAL_FIELD;
4447   }
4448
4449   field = mailimf_field_new(type, return_path, resent_date,
4450       resent_from, resent_sender, resent_to, resent_cc, resent_bcc,
4451       resent_msg_id, orig_date, from, sender, reply_to, to,
4452       cc, bcc, message_id, in_reply_to, references,
4453       subject, comments, keywords, optional_field);
4454   if (field == NULL) {
4455     res = MAILIMF_ERROR_MEMORY;
4456     goto free_field;
4457   }
4458
4459   * result = field;
4460   * index = cur_token;
4461
4462   return MAILIMF_NO_ERROR;
4463
4464  free_field:
4465   if (return_path != NULL)
4466     mailimf_return_free(return_path);
4467   if (resent_date != NULL)
4468     mailimf_orig_date_free(resent_date);
4469   if (resent_from != NULL)
4470     mailimf_from_free(resent_from);
4471   if (resent_sender != NULL)
4472     mailimf_sender_free(resent_sender);
4473   if (resent_to != NULL)
4474     mailimf_to_free(resent_to);
4475   if (resent_cc != NULL)
4476     mailimf_cc_free(resent_cc);
4477   if (resent_bcc != NULL)
4478     mailimf_bcc_free(resent_bcc);
4479   if (resent_msg_id != NULL)
4480     mailimf_message_id_free(resent_msg_id);
4481   if (orig_date != NULL)
4482     mailimf_orig_date_free(orig_date);
4483   if (from != NULL)
4484     mailimf_from_free(from);
4485   if (sender != NULL)
4486     mailimf_sender_free(sender);
4487   if (reply_to != NULL)
4488     mailimf_reply_to_free(reply_to);
4489   if (to != NULL)
4490     mailimf_to_free(to);
4491   if (cc != NULL)
4492     mailimf_cc_free(cc);
4493   if (bcc != NULL)
4494     mailimf_bcc_free(bcc);
4495   if (message_id != NULL)
4496     mailimf_message_id_free(message_id);
4497   if (in_reply_to != NULL)
4498     mailimf_in_reply_to_free(in_reply_to);
4499   if (references != NULL)
4500     mailimf_references_free(references);
4501   if (subject != NULL)
4502     mailimf_subject_free(subject);
4503   if (comments != NULL)
4504     mailimf_comments_free(comments);
4505   if (keywords != NULL)
4506     mailimf_keywords_free(keywords);
4507   if (optional_field != NULL)
4508     mailimf_optional_field_free(optional_field);
4509  err:
4510   return res;
4511 }
4512
4513
4514 /*
4515 fields          =       *(delivering-info /
4516                         orig-date /
4517                         from /
4518                         sender /
4519                         reply-to /
4520                         to /
4521                         cc /
4522                         bcc /
4523                         message-id /
4524                         in-reply-to /
4525                         references /
4526                         subject /
4527                         comments /
4528                         keywords /
4529                         optional-field)
4530 */
4531
4532 #if 0
4533 int
4534 mailimf_unparsed_fields_parse(const char * message, size_t length,
4535                               size_t * index,
4536                               struct mailimf_unparsed_fields ** result)
4537 {
4538   size_t cur_token;
4539   clist * list;
4540   struct mailimf_unparsed_fields * fields;
4541   int r;
4542   int res;
4543
4544   cur_token = * index;
4545
4546   list = NULL;
4547
4548   r = mailimf_struct_multiple_parse(message, length, &cur_token,
4549                                     &list,
4550                                     (mailimf_struct_parser *)
4551                                     mailimf_optional_field_parse,
4552                                     (mailimf_struct_destructor *)
4553                                     mailimf_optional_field_free);
4554   /*
4555   if ((r = MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
4556     res = r;
4557     goto err;
4558   }
4559   */
4560
4561   switch (r) {
4562   case MAILIMF_NO_ERROR:
4563     /* do nothing */
4564     break;
4565
4566   case MAILIMF_ERROR_PARSE:
4567     list = clist_new();
4568     if (list == NULL) {
4569       res = MAILIMF_ERROR_MEMORY;
4570       goto err;
4571     }
4572     break;
4573
4574   default:
4575     res = r;
4576     goto err;
4577   }
4578
4579   fields = mailimf_unparsed_fields_new(list);
4580   if (fields == NULL) {
4581     res = MAILIMF_ERROR_MEMORY;
4582     goto free;
4583   }
4584
4585   * result = fields;
4586   * index = cur_token;
4587
4588   return MAILIMF_NO_ERROR;
4589
4590  free:
4591   if (list != NULL) {
4592     clist_foreach(list, (clist_func) mailimf_optional_field_free, NULL);
4593     clist_free(list);
4594   }
4595  err:
4596   return res;
4597 }
4598 #endif
4599
4600 int mailimf_fields_parse(const char * message, size_t length,
4601                          size_t * index,
4602                          struct mailimf_fields ** result)
4603 {
4604   size_t cur_token;
4605   clist * list;
4606   struct mailimf_fields * fields;
4607   int r;
4608   int res;
4609
4610   cur_token = * index;
4611
4612   list = NULL;
4613
4614   r = mailimf_struct_multiple_parse(message, length, &cur_token,
4615                                     &list,
4616                                     (mailimf_struct_parser *)
4617                                     mailimf_field_parse,
4618                                     (mailimf_struct_destructor *)
4619                                     mailimf_field_free);
4620   /*
4621   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
4622     res = r;
4623     goto err;
4624   }
4625   */
4626
4627   switch (r) {
4628   case MAILIMF_NO_ERROR:
4629     /* do nothing */
4630     break;
4631
4632   case MAILIMF_ERROR_PARSE:
4633     list = clist_new();
4634     if (list == NULL) {
4635       res = MAILIMF_ERROR_MEMORY;
4636       goto err;
4637     }
4638     break;
4639
4640   default:
4641     res = r;
4642     goto err;
4643   }
4644
4645   fields = mailimf_fields_new(list);
4646   if (fields == NULL) {
4647     res = MAILIMF_ERROR_MEMORY;
4648     goto free;
4649   }
4650
4651   * result = fields;
4652   * index = cur_token;
4653
4654   return MAILIMF_NO_ERROR;
4655
4656  free:
4657   if (list != NULL) {
4658     clist_foreach(list, (clist_func) mailimf_field_free, NULL);
4659     clist_free(list);
4660   }
4661  err:
4662   return res;
4663 }
4664
4665 /*
4666 orig-date       =       "Date:" date-time CRLF
4667 */
4668
4669
4670 static int
4671 mailimf_orig_date_parse(const char * message, size_t length,
4672                         size_t * index, struct mailimf_orig_date ** result)
4673 {
4674   struct mailimf_date_time * date_time;
4675   struct mailimf_orig_date * orig_date;
4676   size_t cur_token;
4677   int r;
4678   int res;
4679
4680   cur_token = * index;
4681
4682   r = mailimf_token_case_insensitive_parse(message, length,
4683                                            &cur_token, "Date:");
4684   if (r != MAILIMF_NO_ERROR) {
4685     res = r;
4686     goto err;
4687   }
4688
4689   r = mailimf_date_time_parse(message, length, &cur_token, &date_time);
4690   if (r != MAILIMF_NO_ERROR) {
4691     res = r;
4692     goto err;
4693   }
4694
4695   r = mailimf_ignore_unstructured_parse(message, length, &cur_token);
4696   if (r != MAILIMF_NO_ERROR) {
4697     res = r;
4698     goto free_date_time;
4699   }
4700
4701   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
4702   if (r != MAILIMF_NO_ERROR) {
4703     res = r;
4704     goto free_date_time;
4705   }
4706
4707   orig_date = mailimf_orig_date_new(date_time);
4708   if (orig_date == NULL) {
4709     res = MAILIMF_ERROR_MEMORY;
4710     goto free_date_time;
4711   }
4712
4713   * result = orig_date;
4714   * index = cur_token;
4715
4716   return MAILIMF_NO_ERROR;
4717
4718  free_date_time:
4719   mailimf_date_time_free(date_time);
4720  err:
4721   return res;
4722 }
4723
4724 /*
4725 from            =       "From:" mailbox-list CRLF
4726 */
4727
4728 static int
4729 mailimf_from_parse(const char * message, size_t length,
4730                    size_t * index, struct mailimf_from ** result)
4731 {
4732   struct mailimf_mailbox_list * mb_list;
4733   struct mailimf_from * from;
4734   size_t cur_token;
4735   int r;
4736   int res;
4737
4738   cur_token =  * index;
4739
4740   r = mailimf_token_case_insensitive_parse(message, length,
4741                                            &cur_token, "From");
4742   if (r != MAILIMF_NO_ERROR) {
4743     res = r;
4744     goto err;
4745   }
4746
4747   r = mailimf_colon_parse(message, length, &cur_token);
4748   if (r != MAILIMF_NO_ERROR) {
4749     res = r;
4750     goto err;
4751   }
4752
4753   r = mailimf_mailbox_list_parse(message, length, &cur_token, &mb_list);
4754
4755   if (r != MAILIMF_NO_ERROR) {
4756     res = r;
4757     goto err;
4758   }
4759
4760   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
4761   if (r != MAILIMF_NO_ERROR) {
4762     res = r;
4763     goto free_mb_list;
4764   }
4765
4766   from = mailimf_from_new(mb_list);
4767   if (from == NULL) {
4768     res = MAILIMF_ERROR_MEMORY;
4769     goto free_mb_list;
4770   }
4771
4772   * result = from;
4773   * index = cur_token;
4774
4775   return MAILIMF_NO_ERROR;
4776
4777  free_mb_list:
4778   mailimf_mailbox_list_free(mb_list);
4779  err:
4780   return res;
4781 }
4782
4783 /*
4784 sender          =       "Sender:" mailbox CRLF
4785 */
4786
4787 static int
4788 mailimf_sender_parse(const char * message, size_t length,
4789                      size_t * index, struct mailimf_sender ** result)
4790 {
4791   struct mailimf_mailbox * mb;
4792   struct mailimf_sender * sender;
4793   size_t cur_token;
4794   int r;
4795   int res;
4796
4797   cur_token = * index;
4798
4799   r = mailimf_token_case_insensitive_parse(message, length,
4800                                            &cur_token, "Sender");
4801   if (r != MAILIMF_NO_ERROR) {
4802     res = r;
4803     goto err;
4804   }
4805
4806   r = mailimf_colon_parse(message, length, &cur_token);
4807   if (r != MAILIMF_NO_ERROR) {
4808     res = r;
4809     goto err;
4810   }
4811
4812   r = mailimf_mailbox_parse(message, length, &cur_token, &mb);
4813   if (r != MAILIMF_NO_ERROR) {
4814     res = r;
4815     goto err;
4816   }
4817
4818   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
4819   if (r != MAILIMF_NO_ERROR) {
4820     res = r;
4821     goto free_mb;
4822   }
4823
4824   sender = mailimf_sender_new(mb);
4825   if (sender == NULL) {
4826     res = MAILIMF_ERROR_MEMORY;
4827     goto free_mb;
4828   }
4829
4830   * result = sender;
4831   * index = cur_token;
4832
4833   return MAILIMF_NO_ERROR;
4834
4835  free_mb:
4836   mailimf_mailbox_free(mb);
4837  err:
4838   return res;
4839 }
4840
4841 /*
4842 reply-to        =       "Reply-To:" address-list CRLF
4843 */
4844
4845
4846 static int
4847 mailimf_reply_to_parse(const char * message, size_t length,
4848                        size_t * index, struct mailimf_reply_to ** result)
4849 {
4850   struct mailimf_address_list * addr_list;
4851   struct mailimf_reply_to * reply_to;
4852   size_t cur_token;
4853   int r;
4854   int res;
4855
4856   cur_token = * index;
4857
4858   r = mailimf_token_case_insensitive_parse(message, length,
4859                                            &cur_token, "Reply-To");
4860   if (r != MAILIMF_NO_ERROR) {
4861     res = r;
4862     goto err;
4863   }
4864
4865   r = mailimf_colon_parse(message, length, &cur_token);
4866   if (r != MAILIMF_NO_ERROR) {
4867     res = r;
4868     goto err;
4869   }
4870
4871   r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
4872   if (r != MAILIMF_NO_ERROR) {
4873     res = r;
4874     goto err;
4875   }
4876
4877   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
4878   if (r != MAILIMF_NO_ERROR) {
4879     res = r;
4880     goto free_addr_list;
4881   }
4882
4883   reply_to = mailimf_reply_to_new(addr_list);
4884   if (reply_to == NULL) {
4885     res = MAILIMF_ERROR_MEMORY;
4886     goto free_addr_list;
4887   }
4888
4889   * result = reply_to;
4890   * index = cur_token;
4891
4892   return MAILIMF_NO_ERROR;
4893
4894  free_addr_list:
4895   mailimf_address_list_free(addr_list);
4896  err:
4897   return res;
4898 }
4899
4900 /*
4901 to              =       "To:" address-list CRLF
4902 */
4903
4904 static int
4905 mailimf_to_parse(const char * message, size_t length,
4906                  size_t * index, struct mailimf_to ** result)
4907 {
4908   struct mailimf_address_list * addr_list;
4909   struct mailimf_to * to;
4910   size_t cur_token;
4911   int r;
4912   int res;
4913
4914   cur_token = * index;
4915
4916   r = mailimf_token_case_insensitive_parse(message, length,
4917                                            &cur_token, "To");
4918   if (r != MAILIMF_NO_ERROR) {
4919     res = r;
4920     goto err;
4921   }
4922
4923   r = mailimf_colon_parse(message, length, &cur_token);
4924   if (r != MAILIMF_NO_ERROR) {
4925     res = r;
4926     goto err;
4927   }
4928
4929   r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
4930   if (r != MAILIMF_NO_ERROR) {
4931     res = r;
4932     goto err;
4933   }
4934
4935   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
4936   if (r != MAILIMF_NO_ERROR) {
4937     res = r;
4938     goto free_addr_list;
4939   }
4940
4941   to = mailimf_to_new(addr_list);
4942   if (to == NULL) {
4943     res = MAILIMF_ERROR_MEMORY;
4944     goto free_addr_list;
4945   }
4946
4947   * result = to;
4948   * index = cur_token;
4949
4950   return MAILIMF_NO_ERROR;
4951
4952  free_addr_list:
4953   mailimf_address_list_free(addr_list);
4954  err:
4955   return res;
4956 }
4957
4958 /*
4959 cc              =       "Cc:" address-list CRLF
4960 */
4961
4962
4963 static int
4964 mailimf_cc_parse(const char * message, size_t length,
4965                  size_t * index, struct mailimf_cc ** result)
4966 {
4967   struct mailimf_address_list * addr_list;
4968   struct mailimf_cc * cc;
4969   size_t cur_token;
4970   int r;
4971   int res;
4972
4973   cur_token = * index;
4974
4975   r = mailimf_token_case_insensitive_parse(message, length,
4976                                            &cur_token, "Cc");
4977   if (r != MAILIMF_NO_ERROR) {
4978     res = r;
4979     goto err;
4980   }
4981
4982   r = mailimf_colon_parse(message, length, &cur_token);
4983   if (r != MAILIMF_NO_ERROR) {
4984     res = r;
4985     goto err;
4986   }
4987
4988   r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
4989   if (r != MAILIMF_NO_ERROR) {
4990     res = r;
4991     goto err;
4992   }
4993
4994   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
4995   if (r != MAILIMF_NO_ERROR) {
4996     res = r;
4997     goto free_addr_list;
4998   }
4999
5000   cc = mailimf_cc_new(addr_list);
5001   if (cc == NULL) {
5002     res = MAILIMF_ERROR_MEMORY;
5003     goto free_addr_list;
5004   }
5005
5006   * result = cc;
5007   * index = cur_token;
5008
5009   return MAILIMF_NO_ERROR;
5010
5011  free_addr_list:
5012   mailimf_address_list_free(addr_list);
5013  err:
5014   return res;
5015 }
5016
5017 /*
5018 bcc             =       "Bcc:" (address-list / [CFWS]) CRLF
5019 */
5020
5021
5022 static int
5023 mailimf_bcc_parse(const char * message, size_t length,
5024                   size_t * index, struct mailimf_bcc ** result)
5025 {
5026   struct mailimf_address_list * addr_list;
5027   struct mailimf_bcc * bcc;
5028   size_t cur_token;
5029   int r;
5030   int res;
5031
5032   cur_token = * index;
5033   addr_list = NULL;
5034
5035   r = mailimf_token_case_insensitive_parse(message, length,
5036                                            &cur_token, "Bcc");
5037   if (r != MAILIMF_NO_ERROR) {
5038     res = r;
5039     goto err;
5040   }
5041
5042   r = mailimf_colon_parse(message, length, &cur_token);
5043   if (r != MAILIMF_NO_ERROR) {
5044     res = r;
5045     goto err;
5046   }
5047
5048   r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
5049   switch (r) {
5050   case MAILIMF_NO_ERROR:
5051     /* do nothing */
5052     break;
5053   case MAILIMF_ERROR_PARSE:
5054     r = mailimf_cfws_parse(message, length, &cur_token);
5055     if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
5056       res = r;
5057       goto err;
5058     }
5059     break;
5060   default:
5061     res = r;
5062     goto err;
5063   }
5064
5065   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5066   if (r != MAILIMF_NO_ERROR) {
5067     res = r;
5068     goto free_addr_list;
5069   }
5070
5071   bcc = mailimf_bcc_new(addr_list);
5072   if (bcc == NULL) {
5073     res = MAILIMF_ERROR_MEMORY;
5074     goto free_addr_list;
5075   }
5076
5077   * result = bcc;
5078   * index = cur_token;
5079
5080   return MAILIMF_NO_ERROR;
5081
5082  free_addr_list:
5083   mailimf_address_list_free(addr_list);
5084  err:
5085   return res;
5086 }
5087
5088 /*
5089 message-id      =       "Message-ID:" msg-id CRLF
5090 */
5091
5092 static int mailimf_message_id_parse(const char * message, size_t length,
5093                                     size_t * index,
5094                                     struct mailimf_message_id ** result)
5095 {
5096   char * value;
5097   size_t cur_token;
5098   struct mailimf_message_id * message_id;
5099   int r;
5100   int res;
5101
5102   cur_token = * index;
5103
5104   r = mailimf_token_case_insensitive_parse(message, length,
5105                                            &cur_token, "Message-ID");
5106   if (r != MAILIMF_NO_ERROR) {
5107     res = r;
5108     goto err;
5109   }
5110
5111   r = mailimf_colon_parse(message, length, &cur_token);
5112   if (r != MAILIMF_NO_ERROR) {
5113     res = r;
5114     goto err;
5115   }
5116
5117   r = mailimf_msg_id_parse(message, length, &cur_token, &value);
5118   if (r != MAILIMF_NO_ERROR) {
5119     res = r;
5120     goto err;
5121   }
5122
5123   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5124   if (r != MAILIMF_NO_ERROR) {
5125     res = r;
5126     goto free_value;
5127   }
5128
5129   message_id = mailimf_message_id_new(value);
5130   if (message_id == NULL) {
5131     res = MAILIMF_ERROR_MEMORY;
5132     goto free_value;
5133   }
5134
5135   * result = message_id;
5136   * index = cur_token;
5137
5138   return MAILIMF_NO_ERROR;
5139
5140  free_value:
5141   mailimf_msg_id_free(value);
5142  err:
5143   return res;
5144 }
5145
5146 /*
5147 in-reply-to     =       "In-Reply-To:" 1*msg-id CRLF
5148 */
5149
5150 int mailimf_msg_id_list_parse(const char * message, size_t length,
5151                               size_t * index, clist ** result)
5152 {
5153   return mailimf_struct_multiple_parse(message, length, index,
5154                                        result,
5155                                        (mailimf_struct_parser *)
5156                                        mailimf_unstrict_msg_id_parse,
5157                                        (mailimf_struct_destructor *)
5158                                        mailimf_msg_id_free);
5159 }
5160
5161 static int mailimf_in_reply_to_parse(const char * message, size_t length,
5162                                      size_t * index,
5163                                      struct mailimf_in_reply_to ** result)
5164 {
5165   struct mailimf_in_reply_to * in_reply_to;
5166   size_t cur_token;
5167   clist * msg_id_list;
5168   int res;
5169   int r;
5170
5171   cur_token = * index;
5172
5173   r = mailimf_token_case_insensitive_parse(message, length,
5174                                            &cur_token, "In-Reply-To");
5175   if (r != MAILIMF_NO_ERROR) {
5176     res = r;
5177     goto err;
5178   }
5179
5180   r = mailimf_colon_parse(message, length, &cur_token);
5181   if (r != MAILIMF_NO_ERROR) {
5182     res = r;
5183     goto err;
5184   }
5185
5186   r = mailimf_msg_id_list_parse(message, length, &cur_token, &msg_id_list);
5187   if (r != MAILIMF_NO_ERROR) {
5188     res = r;
5189     goto err;
5190   }
5191
5192   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5193   if (r != MAILIMF_NO_ERROR) {
5194     res = r;
5195     goto free_list;
5196   }
5197
5198   in_reply_to = mailimf_in_reply_to_new(msg_id_list);
5199   if (in_reply_to == NULL) {
5200     res = MAILIMF_ERROR_MEMORY;
5201     goto free_list;
5202   }
5203
5204   * result = in_reply_to;
5205   * index = cur_token;
5206
5207   return MAILIMF_NO_ERROR;
5208
5209  free_list:
5210   clist_foreach(msg_id_list, (clist_func) mailimf_msg_id_free, NULL);
5211   clist_free(msg_id_list);
5212  err:
5213   return res;
5214 }
5215
5216 /*
5217 references      =       "References:" 1*msg-id CRLF
5218 */
5219
5220 int mailimf_references_parse(const char * message, size_t length,
5221                              size_t * index,
5222                              struct mailimf_references ** result)
5223 {
5224   struct mailimf_references * references;
5225   size_t cur_token;
5226   clist * msg_id_list;
5227   int r;
5228   int res;
5229
5230   cur_token = * index;
5231
5232   r = mailimf_token_case_insensitive_parse(message, length,
5233                                            &cur_token, "References");
5234   if (r != MAILIMF_NO_ERROR) {
5235     res = r;
5236     goto err;
5237   }
5238
5239   r = mailimf_colon_parse(message, length, &cur_token);
5240   if (r != MAILIMF_NO_ERROR) {
5241     res = r;
5242     goto err;
5243   }
5244
5245   r = mailimf_msg_id_list_parse(message, length, &cur_token, &msg_id_list);
5246   if (r != MAILIMF_NO_ERROR) {
5247     res = r;
5248     goto err;
5249   }
5250
5251   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5252   if (r != MAILIMF_NO_ERROR) {
5253     res = r;
5254     goto free_list;
5255   }
5256
5257   references = mailimf_references_new(msg_id_list);
5258   if (references == NULL) {
5259     res = MAILIMF_ERROR_MEMORY;
5260     goto free_list;
5261   }
5262
5263   * result = references;
5264   * index = cur_token;
5265
5266   return MAILIMF_NO_ERROR;
5267
5268  free_list:
5269   clist_foreach(msg_id_list, (clist_func) mailimf_msg_id_free, NULL);
5270   clist_free(msg_id_list);
5271  err:
5272   return res;
5273 }
5274
5275 /*
5276 msg-id          =       [CFWS] "<" id-left "@" id-right ">" [CFWS]
5277 */
5278
5279 int mailimf_msg_id_parse(const char * message, size_t length,
5280                          size_t * index,
5281                          char ** result)
5282 {
5283   size_t cur_token;
5284 #if 0
5285   char * id_left;
5286   char * id_right;
5287 #endif
5288   char * msg_id;
5289   int r;
5290   int res;
5291
5292   cur_token = * index;
5293
5294   r = mailimf_cfws_parse(message, length, &cur_token);
5295   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
5296     return r;
5297
5298   r = mailimf_lower_parse(message, length, &cur_token);
5299   if (r != MAILIMF_NO_ERROR) {
5300     res = r;
5301     goto err;
5302   }
5303
5304   r = mailimf_addr_spec_parse(message, length, &cur_token, &msg_id);
5305   if (r != MAILIMF_NO_ERROR) {
5306     res = r;
5307     goto err;
5308   }
5309   
5310   r = mailimf_greater_parse(message, length, &cur_token);
5311   if (r != MAILIMF_NO_ERROR) {
5312     free(msg_id);
5313     res = r;
5314     goto err;
5315   }
5316
5317 #if 0
5318   r = mailimf_id_left_parse(message, length, &cur_token, &id_left);
5319   if (r != MAILIMF_NO_ERROR) {
5320     res = r;
5321     goto err;
5322   }
5323
5324   r = mailimf_at_sign_parse(message, length, &cur_token);
5325   if (r != MAILIMF_NO_ERROR) {
5326     res = r;
5327     goto free_id_left;
5328   }
5329
5330   r = mailimf_id_right_parse(message, length, &cur_token, &id_right);
5331   if (r != MAILIMF_NO_ERROR) {
5332     res = r;
5333     goto free_id_left;
5334   }
5335
5336   r = mailimf_greater_parse(message, length, &cur_token);
5337   if (r != MAILIMF_NO_ERROR) {
5338     res = r;
5339     goto free_id_right;
5340   }
5341
5342   msg_id = malloc(strlen(id_left) + strlen(id_right) + 2);
5343   if (msg_id == NULL) {
5344     res = MAILIMF_ERROR_MEMORY;
5345     goto free_id_right;
5346   }
5347   strcpy(msg_id, id_left);
5348   strcat(msg_id, "@");
5349   strcat(msg_id, id_right);
5350
5351   mailimf_id_left_free(id_left);
5352   mailimf_id_right_free(id_right);
5353 #endif
5354
5355   * result = msg_id;
5356   * index = cur_token;
5357
5358   return MAILIMF_NO_ERROR;
5359
5360 #if 0
5361  free_id_right:
5362   mailimf_id_right_free(id_right);
5363  free_id_left:
5364   mailimf_id_left_free(id_left);
5365 #endif
5366   /*
5367  free:
5368   mailimf_atom_free(msg_id);
5369   */
5370  err:
5371   return res;
5372 }
5373
5374 static int mailimf_parse_unwanted_msg_id(const char * message, size_t length,
5375                                          size_t * index)
5376 {
5377   size_t cur_token;
5378   int r;
5379   char * word;
5380   int token_parsed;
5381
5382   cur_token = * index;
5383
5384   token_parsed = TRUE;
5385   while (token_parsed) {
5386     token_parsed = FALSE;
5387     r = mailimf_word_parse(message, length, &cur_token, &word);
5388     if (r == MAILIMF_NO_ERROR) {
5389       mailimf_word_free(word);
5390       token_parsed = TRUE;
5391     }
5392     else if (r == MAILIMF_ERROR_PARSE) {
5393       /* do nothing */
5394     }
5395     else
5396       return r;
5397     r = mailimf_semi_colon_parse(message, length, &cur_token);
5398     if (r == MAILIMF_NO_ERROR)
5399       token_parsed = TRUE;
5400     else if (r == MAILIMF_ERROR_PARSE) {
5401       /* do nothing */
5402     }
5403     else
5404       return r;
5405     r = mailimf_comma_parse(message, length, &cur_token);
5406     if (r == MAILIMF_NO_ERROR)
5407       token_parsed = TRUE;
5408     else if (r == MAILIMF_ERROR_PARSE) {
5409       /* do nothing */
5410     }
5411     else
5412       return r;
5413     r = mailimf_plus_parse(message, length, &cur_token);
5414     if (r == MAILIMF_NO_ERROR)
5415       token_parsed = TRUE;
5416     else if (r == MAILIMF_ERROR_PARSE) {
5417       /* do nothing */
5418     }
5419     else
5420       return r;
5421     r = mailimf_colon_parse(message, length, &cur_token);
5422     if (r == MAILIMF_NO_ERROR)
5423       token_parsed = TRUE;
5424     else if (r == MAILIMF_ERROR_PARSE) {
5425       /* do nothing */
5426     }
5427     else
5428       return r;
5429     r = mailimf_point_parse(message, length, &cur_token);
5430     if (r == MAILIMF_NO_ERROR)
5431       token_parsed = TRUE;
5432     else if (r == MAILIMF_ERROR_PARSE) {
5433       /* do nothing */
5434     }
5435     else
5436       return r;
5437     r = mailimf_at_sign_parse(message, length, &cur_token);
5438     if (r == MAILIMF_NO_ERROR)
5439       token_parsed = TRUE;
5440     else if (r == MAILIMF_ERROR_PARSE) {
5441       /* do nothing */
5442     }
5443     else
5444       return r;
5445   }
5446
5447   return MAILIMF_NO_ERROR;
5448 }
5449
5450 static int mailimf_unstrict_msg_id_parse(const char * message, size_t length,
5451                                          size_t * index,
5452                                          char ** result)
5453 {
5454   char * msgid;
5455   size_t cur_token;
5456   int r;
5457
5458   cur_token = * index;
5459
5460   r = mailimf_cfws_parse(message, length, &cur_token);
5461   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
5462     return r;
5463
5464   r = mailimf_parse_unwanted_msg_id(message, length, &cur_token);
5465   if (r != MAILIMF_NO_ERROR)
5466     return r;
5467
5468   r = mailimf_msg_id_parse(message, length, &cur_token, &msgid);
5469   if (r != MAILIMF_NO_ERROR)
5470     return r;
5471
5472   r = mailimf_parse_unwanted_msg_id(message, length, &cur_token);
5473   if (r != MAILIMF_NO_ERROR)
5474     return r;
5475
5476   * result = msgid;
5477   * index = cur_token;
5478
5479   return MAILIMF_NO_ERROR;
5480 }
5481
5482 /*
5483 id-left         =       dot-atom-text / no-fold-quote / obs-id-left
5484 */
5485
5486 #if 0
5487 static int mailimf_id_left_parse(const char * message, size_t length,
5488                                  size_t * index, char ** result)
5489 {
5490   int r;
5491
5492   r = mailimf_dot_atom_text_parse(message, length, index, result);
5493   switch (r) {
5494   case MAILIMF_NO_ERROR:
5495     return MAILIMF_NO_ERROR;
5496   case MAILIMF_ERROR_PARSE:
5497     break;
5498   default:
5499     return r;
5500   }
5501   
5502   r = mailimf_no_fold_quote_parse(message, length, index, result);
5503   if (r != MAILIMF_NO_ERROR)
5504     return r;
5505
5506   return MAILIMF_NO_ERROR;
5507 }
5508 #endif
5509
5510 /*
5511 id-right        =       dot-atom-text / no-fold-literal / obs-id-right
5512 */
5513
5514 #if 0
5515 static int mailimf_id_right_parse(const char * message, size_t length,
5516                                   size_t * index, char ** result)
5517 {
5518   int r;
5519
5520   r = mailimf_dot_atom_text_parse(message, length, index, result);
5521   switch (r) {
5522   case MAILIMF_NO_ERROR:
5523     return MAILIMF_NO_ERROR;
5524   case MAILIMF_ERROR_PARSE:
5525     break;
5526   default:
5527     return r;
5528   }
5529
5530   r = mailimf_no_fold_literal_parse(message, length, index, result);
5531   if (r != MAILIMF_NO_ERROR)
5532     return r;
5533
5534   return MAILIMF_NO_ERROR;
5535 }
5536 #endif
5537
5538 /*
5539 no-fold-quote   =       DQUOTE *(qtext / quoted-pair) DQUOTE
5540 */
5541
5542 #if 0
5543 static int mailimf_no_fold_quote_char_parse(const char * message, size_t length,
5544                                             size_t * index, char * result)
5545 {
5546   char ch;
5547   size_t cur_token;
5548   int r;
5549
5550   cur_token = * index;
5551
5552 #if 0
5553   r = mailimf_qtext_parse(message, length, &cur_token, &ch);
5554 #endif
5555
5556   if (cur_token >= length)
5557     return MAILIMF_ERROR_PARSE;
5558
5559   if (is_qtext(message[cur_token])) {
5560     ch = message[cur_token];
5561     cur_token ++;
5562   }
5563   else {
5564     r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
5565     
5566     if (r != MAILIMF_NO_ERROR)
5567       return r;
5568   }
5569
5570   * index = cur_token;
5571   * result = ch;
5572
5573   return MAILIMF_NO_ERROR;
5574 }
5575 #endif
5576
5577 #if 0
5578 static int mailimf_no_fold_quote_parse(const char * message, size_t length,
5579                                        size_t * index, char ** result)
5580 {
5581   size_t cur_token;
5582   size_t begin;
5583   char ch;
5584   char * no_fold_quote;
5585   int r;
5586   int res;
5587
5588   begin = cur_token;
5589   r = mailimf_dquote_parse(message, length, &cur_token);
5590   if (r != MAILIMF_NO_ERROR) {
5591     res = r;
5592     goto err;
5593   }
5594
5595   while (1) {
5596     r = mailimf_no_fold_quote_char_parse(message, length, &cur_token, &ch);
5597     if (r == MAILIMF_NO_ERROR) {
5598       /* do nothing */
5599     }
5600     else if (r == MAILIMF_ERROR_PARSE)
5601       break;
5602     else {
5603       res = r;
5604       goto err;
5605     }
5606   }
5607
5608   r = mailimf_dquote_parse(message, length, &cur_token);
5609   if (r != MAILIMF_NO_ERROR) {
5610     res = r;
5611     goto err;
5612   }
5613
5614   /*  no_fold_quote = strndup(message + begin, cur_token - begin); */
5615   no_fold_quote = malloc(cur_token - begin + 1);
5616   if (no_fold_quote == NULL) {
5617     res = MAILIMF_ERROR_MEMORY;
5618     goto err;
5619   }
5620   strncpy(no_fold_quote, message + begin, cur_token - begin);
5621   no_fold_quote[cur_token - begin] = '\0';
5622
5623   * result = no_fold_quote;
5624   * index = cur_token;
5625
5626   return MAILIMF_NO_ERROR;
5627
5628  err:
5629   return res;
5630 }
5631 #endif
5632
5633 /*
5634 no-fold-literal =       "[" *(dtext / quoted-pair) "]"
5635 */
5636
5637 #if 0
5638 static inline int
5639 mailimf_no_fold_literal_char_parse(const char * message, size_t length,
5640                                    size_t * index, char * result)
5641 {
5642   char ch;
5643   size_t cur_token;
5644   int r;
5645
5646   cur_token = * index;
5647
5648 #if 0
5649   r = mailimf_dtext_parse(message, length, &cur_token, &ch);
5650 #endif
5651   if (cur_token >= length)
5652     return MAILIMF_ERROR_PARSE;
5653
5654   if (is_dtext(message[cur_token])) {
5655     ch = message[cur_token];
5656     cur_token ++;
5657   }
5658   else {
5659     r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
5660     
5661     if (r != MAILIMF_NO_ERROR)
5662       return r;
5663   }
5664
5665   * index = cur_token;
5666   * result = ch;
5667
5668   return MAILIMF_NO_ERROR;
5669 }
5670 #endif
5671
5672 #if 0
5673 static int mailimf_no_fold_literal_parse(const char * message, size_t length,
5674                                          size_t * index, char ** result)
5675 {
5676   size_t cur_token;
5677   size_t begin;
5678   char ch;
5679   char * no_fold_literal;
5680   int r;
5681   int res;
5682
5683   begin = cur_token;
5684   r = mailimf_obracket_parse(message, length, &cur_token);
5685   if (r != MAILIMF_NO_ERROR) {
5686     res = r;
5687     goto err;
5688   }
5689
5690   while (1) {
5691     r = mailimf_no_fold_literal_char_parse(message, length,
5692                                            &cur_token, &ch);
5693     if (r == MAILIMF_NO_ERROR) {
5694       /* do nothing */
5695     }
5696     else if (r == MAILIMF_ERROR_PARSE)
5697       break;
5698     else {
5699       res = r;
5700       goto err;
5701     }
5702   }
5703
5704   r = mailimf_cbracket_parse(message, length, &cur_token);
5705   if (r != MAILIMF_NO_ERROR) {
5706     res = r;
5707     goto err;
5708   }
5709
5710   /*
5711   no_fold_literal = strndup(message + begin, cur_token - begin);
5712   */
5713   no_fold_literal = malloc(cur_token - begin + 1);
5714   if (no_fold_literal == NULL) {
5715     res = MAILIMF_NO_ERROR;
5716     goto err;
5717   }
5718   strncpy(no_fold_literal, message + begin, cur_token - begin);
5719   no_fold_literal[cur_token - begin] = '\0';
5720
5721   * result = no_fold_literal;
5722   * index = cur_token;
5723
5724   return MAILIMF_NO_ERROR;
5725
5726  err:
5727   return res;
5728 }
5729 #endif
5730
5731 /*
5732 subject         =       "Subject:" unstructured CRLF
5733 */
5734
5735 static int mailimf_subject_parse(const char * message, size_t length,
5736                                  size_t * index,
5737                                  struct mailimf_subject ** result)
5738 {
5739   struct mailimf_subject * subject;
5740   char * value;
5741   size_t cur_token;
5742   int r;
5743   int res;
5744
5745   cur_token = * index;
5746
5747   r = mailimf_token_case_insensitive_parse(message, length,
5748                                            &cur_token, "Subject");
5749   if (r != MAILIMF_NO_ERROR) {
5750     res = r;
5751     goto err;
5752   }
5753
5754   r = mailimf_colon_parse(message, length, &cur_token);
5755   if (r != MAILIMF_NO_ERROR) {
5756     res = r;
5757     goto err;
5758   }
5759   
5760   r = mailimf_unstructured_parse(message, length, &cur_token, &value);
5761   if (r != MAILIMF_NO_ERROR) {
5762     res = r;
5763     goto err;
5764   }
5765
5766   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5767   if (r != MAILIMF_NO_ERROR) {
5768     res = r;
5769     goto free_value;
5770   }
5771   
5772   subject = mailimf_subject_new(value);
5773   if (subject == NULL) {
5774     res = MAILIMF_ERROR_MEMORY;
5775     goto free_value;
5776   }
5777
5778   * result = subject;
5779   * index = cur_token;
5780
5781   return MAILIMF_NO_ERROR;
5782
5783  free_value:
5784   mailimf_unstructured_free(value);
5785  err:
5786   return res;
5787 }
5788
5789 /*
5790 comments        =       "Comments:" unstructured CRLF
5791 */
5792
5793 static int mailimf_comments_parse(const char * message, size_t length,
5794                                   size_t * index,
5795                                   struct mailimf_comments ** result)
5796 {
5797   struct mailimf_comments * comments;
5798   char * value;
5799   size_t cur_token;
5800   int r;
5801   int res;
5802
5803   cur_token = * index;
5804
5805   r = mailimf_token_case_insensitive_parse(message, length,
5806                                            &cur_token, "Comments");
5807   if (r != MAILIMF_NO_ERROR) {
5808     res = r;
5809     goto err;
5810   }
5811
5812   r = mailimf_colon_parse(message, length, &cur_token);
5813   if (r != MAILIMF_NO_ERROR) {
5814     res = r;
5815     goto err;
5816   }
5817   
5818   r = mailimf_unstructured_parse(message, length, &cur_token, &value);
5819   if (r != MAILIMF_NO_ERROR) {
5820     res = r;
5821     goto err;
5822   }
5823
5824   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5825   if (r != MAILIMF_NO_ERROR) {
5826     res = r;
5827     goto free_value;
5828   }
5829   
5830   comments = mailimf_comments_new(value);
5831   if (comments == NULL) {
5832     res = MAILIMF_ERROR_MEMORY;
5833     goto free_value;
5834   }
5835
5836   * result = comments;
5837   * index = cur_token;
5838
5839   return MAILIMF_NO_ERROR;
5840
5841  free_value:
5842   mailimf_unstructured_free(value);
5843  err:
5844   return res;
5845 }
5846
5847 /*
5848 keywords        =       "Keywords:" phrase *("," phrase) CRLF
5849 */
5850
5851 static int mailimf_keywords_parse(const char * message, size_t length,
5852                                   size_t * index,
5853                                   struct mailimf_keywords ** result)
5854 {
5855   struct mailimf_keywords * keywords;
5856   clist * list;
5857   size_t cur_token;
5858   int r;
5859   int res;
5860
5861   cur_token = * index;
5862
5863   r = mailimf_token_case_insensitive_parse(message, length,
5864                                            &cur_token, "Keywords");
5865   if (r != MAILIMF_NO_ERROR) {
5866     res = r;
5867     goto err;
5868   }
5869
5870   r = mailimf_colon_parse(message, length, &cur_token);
5871   if (r != MAILIMF_NO_ERROR) {
5872     res = r;
5873     goto err;
5874   }
5875   
5876   r = mailimf_struct_list_parse(message, length, &cur_token,
5877                                 &list, ',',
5878                                 (mailimf_struct_parser *)
5879                                 mailimf_phrase_parse,
5880                                 (mailimf_struct_destructor *)
5881                                 mailimf_phrase_free);
5882   if (r != MAILIMF_NO_ERROR) {
5883     res = r;
5884     goto err;
5885   }
5886
5887   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5888   if (r != MAILIMF_NO_ERROR) {
5889     res = r;
5890     goto free_list;
5891   }
5892   
5893   keywords = mailimf_keywords_new(list);
5894   if (keywords == NULL) {
5895     res = MAILIMF_ERROR_MEMORY;
5896     goto free_list;
5897   }
5898
5899   * result = keywords;
5900   * index = cur_token;
5901
5902   return MAILIMF_NO_ERROR;
5903
5904  free_list:
5905   clist_foreach(list, (clist_func) mailimf_phrase_free, NULL);
5906   clist_free(list);
5907  err:
5908   return res;
5909 }
5910
5911 /*
5912 resent-date     =       "Resent-Date:" date-time CRLF
5913 */
5914
5915 static int
5916 mailimf_resent_date_parse(const char * message, size_t length,
5917                           size_t * index, struct mailimf_orig_date ** result)
5918 {
5919   struct mailimf_orig_date * orig_date;
5920   struct mailimf_date_time * date_time;
5921   size_t cur_token;
5922   int r;
5923   int res;
5924
5925   cur_token = * index;
5926
5927   r = mailimf_token_case_insensitive_parse(message, length,
5928                                            &cur_token, "Resent-Date");
5929   if (r != MAILIMF_NO_ERROR) {
5930     res = r;
5931     goto err;
5932   }
5933
5934   r = mailimf_colon_parse(message, length, &cur_token);
5935   if (r != MAILIMF_NO_ERROR) {
5936     res = r;
5937     goto err;
5938   }
5939
5940   r = mailimf_date_time_parse(message, length, &cur_token, &date_time);
5941   if (r != MAILIMF_NO_ERROR) {
5942     res = r;
5943     goto err;
5944   }
5945
5946   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5947   if (r != MAILIMF_NO_ERROR) {
5948     res = r;
5949     goto free_date_time;
5950   }
5951
5952   orig_date = mailimf_orig_date_new(date_time);
5953   if (orig_date == NULL) {
5954     res = MAILIMF_ERROR_MEMORY;
5955     goto free_date_time;
5956   }
5957
5958   * result = orig_date;
5959   * index = cur_token;
5960
5961   return MAILIMF_NO_ERROR;
5962
5963  free_date_time:
5964   mailimf_date_time_free(date_time);
5965  err:
5966   return res;
5967 }
5968
5969 /*
5970 resent-from     =       "Resent-From:" mailbox-list CRLF
5971 */
5972
5973 static int
5974 mailimf_resent_from_parse(const char * message, size_t length,
5975                           size_t * index, struct mailimf_from ** result)
5976 {
5977   struct mailimf_mailbox_list * mb_list;
5978   struct mailimf_from * from;
5979   size_t cur_token;
5980   int r;
5981   int res;
5982
5983   cur_token =  * index;
5984
5985   r = mailimf_token_case_insensitive_parse(message, length,
5986                                            &cur_token, "Resent-From");
5987   if (r != MAILIMF_NO_ERROR) {
5988     res = r;
5989     goto err;
5990   }
5991
5992   r = mailimf_colon_parse(message, length, &cur_token);
5993   if (r != MAILIMF_NO_ERROR) {
5994     res = r;
5995     goto err;
5996   }
5997
5998   r = mailimf_mailbox_list_parse(message, length, &cur_token, &mb_list);
5999   if (r != MAILIMF_NO_ERROR) {
6000     res = r;
6001     goto err;
6002   }
6003
6004   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6005   if (r != MAILIMF_NO_ERROR) {
6006     res = r;
6007     goto free_mb_list;
6008   }
6009
6010   from = mailimf_from_new(mb_list);
6011   if (from == NULL) {
6012     res = MAILIMF_ERROR_MEMORY;
6013     goto free_mb_list;
6014   }
6015
6016   * result = from;
6017   * index = cur_token;
6018
6019   return MAILIMF_NO_ERROR;
6020
6021  free_mb_list:
6022   mailimf_mailbox_list_free(mb_list);
6023  err:
6024   return res;
6025 }
6026
6027 /*
6028 resent-sender   =       "Resent-Sender:" mailbox CRLF
6029 */
6030
6031 static int
6032 mailimf_resent_sender_parse(const char * message, size_t length,
6033                             size_t * index, struct mailimf_sender ** result)
6034 {
6035   struct mailimf_mailbox * mb;
6036   struct mailimf_sender * sender;
6037   size_t cur_token;
6038   int r;
6039   int res;
6040
6041   cur_token = length;
6042
6043   r = mailimf_token_case_insensitive_parse(message, length,
6044                                            &cur_token, "Resent-Sender");
6045   if (r != MAILIMF_NO_ERROR) {
6046     res = r;
6047     goto err;
6048   }
6049
6050   r = mailimf_colon_parse(message, length, &cur_token);
6051   if (r != MAILIMF_NO_ERROR) {
6052     res = r;
6053     goto err;
6054   }
6055
6056   r = mailimf_mailbox_parse(message, length, &cur_token, &mb);
6057   if (r != MAILIMF_NO_ERROR) {
6058     res = r;
6059     goto err;
6060   }
6061
6062   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6063   if (r != MAILIMF_NO_ERROR) {
6064     res = r;
6065     goto free_mb;
6066   }
6067
6068   sender = mailimf_sender_new(mb);
6069   if (sender == NULL) {
6070     res = MAILIMF_ERROR_MEMORY;
6071     goto free_mb;
6072   }
6073
6074   * result = sender;
6075   * index = cur_token;
6076
6077   return MAILIMF_NO_ERROR;
6078
6079  free_mb:
6080   mailimf_mailbox_free(mb);
6081  err:
6082   return res;
6083 }
6084
6085 /*
6086 resent-to       =       "Resent-To:" address-list CRLF
6087 */
6088
6089 static int
6090 mailimf_resent_to_parse(const char * message, size_t length,
6091                         size_t * index, struct mailimf_to ** result)
6092 {
6093   struct mailimf_address_list * addr_list;
6094   struct mailimf_to * to;
6095   size_t cur_token;
6096   int r;
6097   int res;
6098
6099   cur_token = * index;
6100
6101   r = mailimf_token_case_insensitive_parse(message, length,
6102                                            &cur_token, "Resent-To");
6103   if (r != MAILIMF_NO_ERROR) {
6104     res = r;
6105     goto err;
6106   }
6107
6108   r = mailimf_colon_parse(message, length, &cur_token);
6109   if (r != MAILIMF_NO_ERROR) {
6110     res = r;
6111     goto err;
6112   }
6113
6114   r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
6115   if (r != MAILIMF_NO_ERROR) {
6116     res = r;
6117     goto err;
6118   }
6119
6120   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6121   if (r != MAILIMF_NO_ERROR) {
6122     res = r;
6123     goto free_addr_list;
6124   }
6125
6126   to = mailimf_to_new(addr_list);
6127   if (to == NULL) {
6128     res = MAILIMF_ERROR_MEMORY;
6129     goto free_addr_list;
6130   }
6131
6132   * result = to;
6133   * index = cur_token;
6134
6135   return MAILIMF_NO_ERROR;
6136
6137  free_addr_list:
6138   mailimf_address_list_free(addr_list);
6139  err:
6140   return res;
6141 }
6142
6143 /*
6144 resent-cc       =       "Resent-Cc:" address-list CRLF
6145 */
6146
6147 static int
6148 mailimf_resent_cc_parse(const char * message, size_t length,
6149                         size_t * index, struct mailimf_cc ** result)
6150 {
6151   struct mailimf_address_list * addr_list;
6152   struct mailimf_cc * cc;
6153   size_t cur_token;
6154   int r;
6155   int res;
6156
6157   cur_token = * index;
6158
6159   r = mailimf_token_case_insensitive_parse(message, length,
6160                                            &cur_token, "Resent-Cc");
6161   if (r != MAILIMF_NO_ERROR) {
6162     res = r;
6163     goto err;
6164   }
6165
6166   r = mailimf_colon_parse(message, length, &cur_token);
6167   if (r != MAILIMF_NO_ERROR) {
6168     res = r;
6169     goto err;
6170   }
6171
6172   r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
6173   if (r != MAILIMF_NO_ERROR) {
6174     res = r;
6175     goto err;
6176   }
6177
6178   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6179   if (r != MAILIMF_NO_ERROR) {
6180     res = r;
6181     goto free_addr_list;
6182   }
6183
6184   cc = mailimf_cc_new(addr_list);
6185   if (cc == NULL) {
6186     res = MAILIMF_ERROR_MEMORY;
6187     goto free_addr_list;
6188   }
6189
6190   * result = cc;
6191   * index = cur_token;
6192
6193   return MAILIMF_NO_ERROR;
6194
6195  free_addr_list:
6196   mailimf_address_list_free(addr_list);
6197  err:
6198   return res;
6199 }
6200
6201 /*
6202 resent-bcc      =       "Resent-Bcc:" (address-list / [CFWS]) CRLF
6203 */
6204
6205 static int
6206 mailimf_resent_bcc_parse(const char * message, size_t length,
6207                          size_t * index, struct mailimf_bcc ** result)
6208 {
6209   struct mailimf_address_list * addr_list;
6210   struct mailimf_bcc * bcc;
6211   size_t cur_token;
6212   int r;
6213   int res;
6214
6215   cur_token = * index;
6216   bcc = NULL;
6217
6218   r = mailimf_token_case_insensitive_parse(message, length,
6219                                            &cur_token, "Resent-Bcc");
6220   if (r != MAILIMF_NO_ERROR) {
6221     res = r;
6222     goto err;
6223   }
6224
6225   r = mailimf_colon_parse(message, length, &cur_token);
6226   if (r != MAILIMF_NO_ERROR) {
6227     res = r;
6228     goto err;
6229   }
6230
6231   r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
6232   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
6233     res = r;
6234     goto err;
6235   }
6236
6237   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6238   if (r != MAILIMF_NO_ERROR) {
6239     res = r;
6240     goto free_addr_list;
6241   }
6242
6243   bcc = mailimf_bcc_new(addr_list);
6244   if (bcc == NULL) {
6245     res = MAILIMF_ERROR_MEMORY;
6246     goto free_addr_list;
6247   }
6248
6249   * result = bcc;
6250   * index = cur_token;
6251
6252   return TRUE;
6253
6254  free_addr_list:
6255   mailimf_address_list_free(addr_list);
6256  err:
6257   return res;
6258 }
6259
6260 /*
6261 resent-msg-id   =       "Resent-Message-ID:" msg-id CRLF
6262 */
6263
6264 static int
6265 mailimf_resent_msg_id_parse(const char * message, size_t length,
6266                             size_t * index,
6267                             struct mailimf_message_id ** result)
6268 {
6269   char * value;
6270   size_t cur_token;
6271   struct mailimf_message_id * message_id;
6272   int r;
6273   int res;
6274
6275   cur_token = * index;
6276
6277   r = mailimf_token_case_insensitive_parse(message, length,
6278                                            &cur_token, "Resent-Message-ID");
6279   if (r != MAILIMF_NO_ERROR) {
6280     res = r;
6281     goto err;
6282   }
6283
6284   r = mailimf_colon_parse(message, length, &cur_token);
6285   if (r != MAILIMF_NO_ERROR) {
6286     res = r;
6287     goto err;
6288   }
6289
6290   r = mailimf_msg_id_parse(message, length, &cur_token, &value);
6291   if (r != MAILIMF_NO_ERROR) {
6292     res = r;
6293     goto err;
6294   }
6295
6296   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6297   if (r != MAILIMF_NO_ERROR) {
6298     res = r;
6299     goto free_value;
6300   }
6301
6302   message_id = mailimf_message_id_new(value);
6303   if (message_id == NULL) {
6304     res = MAILIMF_ERROR_MEMORY;
6305     goto free_value;
6306   }
6307
6308   * result = message_id;
6309   * index = cur_token;
6310
6311   return MAILIMF_NO_ERROR;
6312
6313  free_value:
6314   mailimf_msg_id_free(value);
6315  err:
6316   return res;
6317 }
6318
6319 /*
6320 trace           =       [return]
6321                         1*received
6322 */
6323
6324 #if 0
6325 static int mailimf_trace_parse(const char * message, size_t length,
6326                                size_t * index,
6327                                struct mailimf_trace ** result)
6328 {
6329   size_t cur_token;
6330   struct mailimf_return * return_path;
6331   clist * received_list;
6332   struct mailimf_trace * trace;
6333   int r;
6334   int res;
6335
6336   cur_token = * index;
6337   return_path = NULL;
6338   received_list = NULL;
6339
6340   r = mailimf_return_parse(message, length, &cur_token, &return_path);
6341   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
6342     res = r;
6343     goto err;
6344   }
6345
6346   r = mailimf_struct_multiple_parse(message, length, &cur_token,
6347                                     &received_list,
6348                                     (mailimf_struct_parser *)
6349                                     mailimf_received_parse,
6350                                     (mailimf_struct_destructor *)
6351                                     mailimf_received_free);
6352   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
6353     res = r;
6354     goto err;
6355   }
6356
6357   if ((received_list == NULL) && (return_path == NULL)) {
6358     res = MAILIMF_ERROR_PARSE;
6359     goto free_return;
6360   }
6361
6362   trace = mailimf_trace_new(return_path, received_list);
6363   if (trace == NULL) {
6364     res = MAILIMF_ERROR_MEMORY;
6365     goto free_list;
6366   }
6367
6368   * result = trace;
6369   * index = cur_token;
6370
6371   return MAILIMF_NO_ERROR;
6372
6373  free_list:
6374   clist_foreach(received_list, (clist_func) mailimf_received_free, NULL);
6375   clist_free(received_list);
6376  free_return:
6377   if (return_path != NULL)
6378     mailimf_return_free(return_path);
6379  err:
6380   return res;
6381 }
6382 #endif
6383
6384 /*
6385 return          =       "Return-Path:" path CRLF
6386 */
6387
6388 static int mailimf_return_parse(const char * message, size_t length,
6389                                 size_t * index,
6390                                 struct mailimf_return ** result)
6391 {
6392   struct mailimf_path * path = NULL;
6393   struct mailimf_return * return_path;
6394   size_t cur_token;
6395   int r;
6396   int res;
6397
6398   cur_token = * index;
6399
6400   r = mailimf_token_case_insensitive_parse(message, length,
6401                                            &cur_token, "Return-Path");
6402   if (r != MAILIMF_NO_ERROR) {
6403     res = r;
6404     goto err;
6405   }
6406
6407   r = mailimf_colon_parse(message, length, &cur_token);
6408   if (r != MAILIMF_NO_ERROR) {
6409     res = r;
6410     goto err;
6411   }
6412
6413   r = mailimf_path_parse(message, length, &cur_token, &path);
6414   if ( r!= MAILIMF_NO_ERROR) {
6415     res = r;
6416     goto err;
6417   }
6418
6419   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6420   if (r != MAILIMF_NO_ERROR) {
6421     res = r;
6422     goto free_path;
6423   }
6424
6425   return_path = mailimf_return_new(path);
6426   if (return_path == NULL) {
6427     res = MAILIMF_ERROR_MEMORY;
6428     goto free_path;
6429   }
6430
6431   * result = return_path;
6432   * index = cur_token;
6433
6434   return MAILIMF_NO_ERROR;
6435
6436  free_path:
6437   mailimf_path_free(path);
6438  err:
6439   return res;
6440 }
6441
6442 /*
6443 path            =       ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) /
6444                         obs-path
6445 */
6446
6447 static int mailimf_path_parse(const char * message, size_t length,
6448                               size_t * index, struct mailimf_path ** result)
6449 {
6450   size_t cur_token;
6451   char * addr_spec;
6452   struct mailimf_path * path;
6453   int res;
6454   int r;
6455
6456   cur_token = * index;
6457   addr_spec = NULL;
6458
6459   r = mailimf_cfws_parse(message, length, &cur_token);
6460   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
6461     res = r;
6462     goto err;
6463   }
6464
6465   r = mailimf_lower_parse(message, length, &cur_token);
6466   if (r != MAILIMF_NO_ERROR) {
6467     res = r;
6468     goto err;
6469   }
6470
6471   r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec);
6472   switch (r) {
6473   case MAILIMF_NO_ERROR:
6474     break;
6475   case MAILIMF_ERROR_PARSE:
6476     r = mailimf_cfws_parse(message, length, &cur_token);
6477     if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
6478       res = r;
6479       goto err;
6480     }
6481     break;
6482   default:
6483     return r;
6484   }
6485   
6486   r = mailimf_greater_parse(message, length, &cur_token);
6487   if (r != MAILIMF_NO_ERROR) {
6488     res = r;
6489     goto err;
6490   }
6491
6492   path = mailimf_path_new(addr_spec);
6493   if (path == NULL) {
6494     res = MAILIMF_ERROR_MEMORY;
6495     goto free_addr_spec;
6496   }
6497
6498   * index = cur_token;
6499   * result = path;
6500
6501   return MAILIMF_NO_ERROR;
6502
6503  free_addr_spec:
6504   if (addr_spec == NULL)
6505     mailimf_addr_spec_free(addr_spec);
6506  err:
6507   return res;
6508 }
6509
6510 /*
6511 received        =       "Received:" name-val-list ";" date-time CRLF
6512 */
6513
6514 #if 0
6515 static int mailimf_received_parse(const char * message, size_t length,
6516                                   size_t * index,
6517                                   struct mailimf_received ** result)
6518 {
6519   size_t cur_token;
6520   struct mailimf_received * received;
6521   struct mailimf_name_val_list * name_val_list;
6522   struct mailimf_date_time * date_time;
6523   int r;
6524   int res;
6525
6526   cur_token = * index;
6527
6528   r = mailimf_token_case_insensitive_parse(message, length,
6529                                            &cur_token, "Received");
6530   if (r != MAILIMF_NO_ERROR) {
6531     res = r;
6532     goto err;
6533   }
6534   
6535   r = mailimf_colon_parse(message, length, &cur_token);
6536   if (r != MAILIMF_NO_ERROR) {
6537     res = r;
6538     goto err;
6539   }
6540
6541   r = mailimf_name_val_list_parse(message, length,
6542                                   &cur_token, &name_val_list);
6543   if (r != MAILIMF_NO_ERROR) {
6544     res = r;
6545     goto err;
6546   }
6547
6548   r = mailimf_semi_colon_parse(message, length, &cur_token);
6549   if (r != MAILIMF_NO_ERROR) {
6550     res = r;
6551     goto free_name_val_list;
6552   }
6553
6554   r = mailimf_date_time_parse(message, length, &cur_token, &date_time);
6555   if (r != MAILIMF_NO_ERROR) {
6556     res = r;
6557     goto free_name_val_list;
6558   }
6559
6560   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6561   if (r != MAILIMF_NO_ERROR) {
6562     res = r;
6563     goto free_date_time;
6564   }
6565
6566   received = mailimf_received_new(name_val_list, date_time);
6567   if (received == NULL) {
6568     res = MAILIMF_ERROR_MEMORY;
6569     goto free_date_time;
6570   }
6571
6572   * index = cur_token;
6573   * result = received;
6574
6575   return MAILIMF_NO_ERROR;
6576
6577  free_date_time:
6578   mailimf_date_time_free(date_time);
6579  free_name_val_list:
6580   mailimf_name_val_list_free(name_val_list);
6581  err:
6582   return res;
6583 }
6584 #endif
6585
6586 /*
6587 name-val-list   =       [CFWS] [name-val-pair *(CFWS name-val-pair)]
6588 */
6589
6590 #if 0
6591 static int
6592 mailimf_name_val_list_parse(const char * message, size_t length,
6593                             size_t * index,
6594                             struct mailimf_name_val_list ** result)
6595 {
6596   size_t cur_token;
6597   struct mailimf_name_val_pair * pair;
6598   struct mailimf_name_val_list * name_val_list;
6599   clist* list;
6600   int res;
6601   int r;
6602
6603   cur_token = * index;
6604   list = NULL;
6605
6606   r = mailimf_name_val_pair_parse(message, length, &cur_token, &pair);
6607
6608   if (r == MAILIMF_NO_ERROR){
6609     size_t final_token;
6610
6611     list = clist_new();
6612     if (list == NULL) {
6613       mailimf_name_val_pair_free(pair);
6614       res = MAILIMF_ERROR_MEMORY;
6615       goto err;
6616     }
6617
6618     r = clist_append(list, pair);
6619     if (r < 0) {
6620       mailimf_name_val_pair_free(pair);
6621       res = MAILIMF_ERROR_MEMORY;
6622       goto free_list;
6623     }
6624
6625     final_token = cur_token;
6626     
6627     while (1) {
6628       r = mailimf_cfws_parse(message, length, &cur_token);
6629       if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
6630         res = r;
6631         goto free_list;
6632       }
6633
6634       r = mailimf_name_val_pair_parse(message, length, &cur_token, &pair);
6635       if (r == MAILIMF_NO_ERROR) {
6636         /* do nothing */
6637       }
6638       else if (r == MAILIMF_ERROR_PARSE)
6639         break;
6640       else {
6641         res = r;
6642         goto free_list;
6643       }
6644
6645       r = clist_append(list, pair);
6646       if (r < 0) {
6647         mailimf_name_val_pair_free(pair);
6648         res = MAILIMF_ERROR_MEMORY;
6649         goto free_list;
6650       }
6651
6652       final_token = cur_token;
6653     }
6654     cur_token = final_token;
6655   }
6656
6657   name_val_list = mailimf_name_val_list_new(list);
6658   if (name_val_list == NULL) {
6659     res = MAILIMF_ERROR_MEMORY;
6660     goto free_list;
6661   }
6662
6663   * index = cur_token;
6664   * result = name_val_list;
6665
6666   return MAILIMF_NO_ERROR;
6667
6668  free_list:
6669   if (list != NULL) {
6670     clist_foreach(list, (clist_func) mailimf_name_val_pair_free, NULL);
6671     clist_free(list);
6672   }
6673  err:
6674   return res;
6675 }
6676 #endif
6677
6678 /*
6679 name-val-pair   =       item-name CFWS item-value
6680 */
6681
6682 #if 0
6683 static int
6684 mailimf_name_val_pair_parse(const char * message, size_t length,
6685                             size_t * index,
6686                             struct mailimf_name_val_pair ** result)
6687 {
6688   size_t cur_token;
6689   char * item_name;
6690   struct mailimf_item_value * item_value;
6691   struct mailimf_name_val_pair * name_val_pair;
6692   int r;
6693   int res;
6694
6695   cur_token = * index;
6696
6697   r = mailimf_cfws_parse(message, length, &cur_token);
6698   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
6699     res = r;
6700     goto err;
6701   }
6702   
6703   r = mailimf_item_name_parse(message, length, &cur_token, &item_name);
6704   if (r != MAILIMF_NO_ERROR) {
6705     res = r;
6706     goto err;
6707   }
6708
6709   r = mailimf_cfws_parse(message, length, &cur_token);
6710   if (r != MAILIMF_NO_ERROR) {
6711     res = r;
6712     goto free_item_name;
6713   }
6714
6715   r = mailimf_item_value_parse(message, length, &cur_token, &item_value);
6716   if (r != MAILIMF_NO_ERROR) {
6717     res = r;
6718     goto free_item_name;
6719   }
6720
6721   name_val_pair = mailimf_name_val_pair_new(item_name, item_value);
6722   if (name_val_pair == NULL) {
6723     res = MAILIMF_ERROR_MEMORY;
6724     goto free_item_value;
6725   }
6726
6727   * result = name_val_pair;
6728   * index = cur_token;
6729
6730   return MAILIMF_NO_ERROR;
6731
6732  free_item_value:
6733   mailimf_item_value_free(item_value);
6734  free_item_name:
6735   mailimf_item_name_free(item_name);
6736  err:
6737   return res;
6738 }
6739 #endif
6740
6741 /*
6742 item-name       =       ALPHA *(["-"] (ALPHA / DIGIT))
6743 */
6744
6745 #if 0
6746 static int mailimf_item_name_parse(const char * message, size_t length,
6747                                    size_t * index, char ** result)
6748 {
6749   size_t cur_token;
6750   size_t begin;
6751   char * item_name;
6752   char ch;
6753   int digit;
6754   int r;
6755   int res;
6756
6757   cur_token = * index;
6758
6759   begin = cur_token;
6760
6761   r = mailimf_alpha_parse(message, length, &cur_token, &ch);
6762   if (r != MAILIMF_NO_ERROR) {
6763     res = r;
6764     goto err;
6765   }
6766
6767   while (1) {
6768     int minus_sign;
6769
6770     minus_sign = mailimf_minus_parse(message, length, &cur_token);
6771
6772     r = mailimf_alpha_parse(message, length, &cur_token, &ch);
6773     if (r == MAILIMF_ERROR_PARSE)
6774       r = mailimf_digit_parse(message, length, &cur_token, &digit);
6775
6776     if (r == MAILIMF_NO_ERROR) {
6777       /* do nothing */
6778     }
6779     if (r == MAILIMF_ERROR_PARSE)
6780       break;
6781     else if (r != MAILIMF_NO_ERROR) {
6782       res = r;
6783       goto err;
6784     }
6785   }
6786
6787   item_name = strndup(message + begin, cur_token - begin);
6788   if (item_name == NULL) {
6789     res = MAILIMF_ERROR_MEMORY;
6790     goto err;
6791   }
6792
6793   * index = cur_token;
6794   * result = item_name;
6795
6796   return MAILIMF_NO_ERROR;
6797
6798  err:
6799   return res;
6800 }
6801 #endif
6802
6803 /*
6804 item-value      =       1*angle-addr / addr-spec /
6805                          atom / domain / msg-id
6806 */
6807
6808 #if 0
6809 static int is_item_value_atext(char ch)
6810 {
6811   switch (ch) {
6812   case '\t':
6813   case ' ':
6814   case '\r':
6815   case '\n':
6816   case ';':
6817     return FALSE;
6818   default:
6819     return TRUE;
6820   }
6821 }
6822
6823 static int mailimf_item_value_atom_parse(const char * message, size_t length,
6824                                          size_t * index, char ** result)
6825 {
6826   char * atom;
6827   size_t cur_token;
6828   int r;
6829
6830   cur_token = * index;
6831
6832   r = mailimf_cfws_parse(message, length, &cur_token);
6833   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
6834     return r;
6835
6836   r = mailimf_custom_string_parse(message, length, &cur_token,
6837                                   &atom, is_item_value_atext);
6838   if (r != MAILIMF_NO_ERROR)
6839     return r;
6840
6841   r = mailimf_cfws_parse(message, length, &cur_token);
6842   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
6843     return r;
6844
6845   * index = cur_token;
6846   * result = atom;
6847
6848   return MAILIMF_NO_ERROR;
6849 }
6850
6851 static int mailimf_item_value_parse(const char * message, size_t length,
6852                                     size_t * index,
6853                                     struct mailimf_item_value ** result)
6854 {
6855   size_t cur_token;
6856   clist * angle_addr_list;
6857   char * addr_spec;
6858   char * atom;
6859   char * domain;
6860   char * msg_id;
6861   int type;
6862   struct mailimf_item_value * item_value;
6863   int r;
6864   int res;
6865
6866   cur_token = * index;
6867   
6868   angle_addr_list = NULL;
6869   addr_spec = NULL;
6870   atom = NULL;
6871   domain = NULL;
6872   msg_id = NULL;
6873
6874   r = mailimf_struct_multiple_parse(message, length, &cur_token,
6875                                     &angle_addr_list,
6876                                     (mailimf_struct_parser *)
6877                                     mailimf_angle_addr_parse,
6878                                     (mailimf_struct_destructor *)
6879                                     mailimf_angle_addr_free);
6880   if (r == MAILIMF_NO_ERROR)
6881     type = MAILIMF_ITEM_VALUE_ANGLE_ADDR_LIST;
6882
6883   if (r == MAILIMF_ERROR_PARSE) {
6884     r = mailimf_addr_spec_parse(message, length, &cur_token,
6885                                 &addr_spec);
6886     if (r == MAILIMF_NO_ERROR)
6887       type = MAILIMF_ITEM_VALUE_ADDR_SPEC;
6888   }
6889
6890   if (r == MAILIMF_ERROR_PARSE) {
6891     r = mailimf_msg_id_parse(message, length, &cur_token,
6892                              &msg_id);
6893     if (r == MAILIMF_NO_ERROR)
6894       type = MAILIMF_ITEM_VALUE_MSG_ID;
6895   }
6896
6897   /*
6898   else if (mailimf_domain_parse(message, length, &cur_token,
6899                                 &domain))
6900     type = MAILIMF_ITEM_VALUE_DOMAIN;
6901   */
6902   /*
6903   else if (mailimf_atom_parse(message, length, &cur_token,
6904                               &atom))
6905     type = MAILIMF_ITEM_VALUE_ATOM;
6906   */
6907
6908   if (r == MAILIMF_ERROR_PARSE) {
6909     r = mailimf_item_value_atom_parse(message, length, &cur_token,
6910                                       &atom);
6911     if (r == MAILIMF_NO_ERROR)
6912       type = MAILIMF_ITEM_VALUE_ATOM;
6913   }
6914
6915   if (r != MAILIMF_NO_ERROR) {
6916     res = r;
6917     goto err;
6918   }
6919
6920   item_value = mailimf_item_value_new(type, angle_addr_list, addr_spec,
6921                                       atom, domain, msg_id);
6922   if (item_value == NULL) {
6923     res = MAILIMF_ERROR_MEMORY;
6924     goto free;
6925   }
6926
6927   * result = item_value;
6928   * index = cur_token;
6929
6930   return MAILIMF_NO_ERROR;
6931
6932  free:
6933   if (angle_addr_list != NULL) {
6934     clist_foreach(angle_addr_list, (clist_func) mailimf_angle_addr_free, NULL);
6935     clist_free(angle_addr_list);
6936   }
6937   if (addr_spec != NULL)
6938     mailimf_addr_spec_free(addr_spec);
6939   if (atom != NULL)
6940     mailimf_atom_free(atom);
6941   if (domain != NULL)
6942     mailimf_domain_free(domain);
6943   if (msg_id != NULL)
6944     mailimf_msg_id_free(msg_id);
6945  err:
6946   return res;
6947 }
6948 #endif
6949
6950 /*
6951 optional-field  =       field-name ":" unstructured CRLF
6952 */
6953
6954 static int
6955 mailimf_optional_field_parse(const char * message, size_t length,
6956                              size_t * index,
6957                              struct mailimf_optional_field ** result)
6958 {
6959   char * name;
6960   char * value;
6961   struct mailimf_optional_field * optional_field;
6962   size_t cur_token;
6963   int r;
6964   int res;
6965
6966   cur_token = * index;
6967
6968   r = mailimf_field_name_parse(message, length, &cur_token, &name);
6969   if (r != MAILIMF_NO_ERROR) {
6970     res = r;
6971     goto err;
6972   }
6973
6974   r = mailimf_colon_parse(message, length, &cur_token);
6975   if (r != MAILIMF_NO_ERROR) {
6976     res = r;
6977     goto free_name;
6978   }
6979
6980   r = mailimf_unstructured_parse(message, length, &cur_token, &value);
6981   if (r != MAILIMF_NO_ERROR) {
6982     res = r;
6983     goto free_name;
6984   }
6985
6986   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6987   if (r != MAILIMF_NO_ERROR) {
6988     res = r;
6989     goto free_value;
6990   }
6991
6992   optional_field = mailimf_optional_field_new(name, value);
6993   if (optional_field == NULL) {
6994     res = MAILIMF_ERROR_MEMORY;
6995     goto free_value;
6996   }
6997
6998   * result = optional_field;
6999   * index = cur_token;
7000
7001   return MAILIMF_NO_ERROR;
7002
7003  free_value:
7004   mailimf_unstructured_free(value);
7005  free_name:
7006   mailimf_field_name_free(name);
7007  err:
7008   return res;
7009 }
7010      
7011 /*
7012 field-name      =       1*ftext
7013 */
7014
7015 static inline int is_ftext(char ch);
7016
7017 static int mailimf_field_name_parse(const char * message, size_t length,
7018                                     size_t * index, char ** result)
7019 {
7020   char * field_name;
7021   size_t cur_token;
7022   size_t end;
7023   
7024   cur_token = * index;
7025
7026   end = cur_token;
7027   if (end >= length) {
7028     return MAILIMF_ERROR_PARSE;
7029   }
7030
7031   while (is_ftext(message[end])) {
7032     end ++;
7033     if (end >= length)
7034       break;
7035   }
7036   if (end == cur_token) {
7037     return MAILIMF_ERROR_PARSE;
7038   }
7039
7040   /*  field_name = strndup(message + cur_token, end - cur_token); */
7041   field_name = malloc(end - cur_token + 1);
7042   if (field_name == NULL) {
7043     return MAILIMF_ERROR_MEMORY;
7044   }
7045   strncpy(field_name, message + cur_token, end - cur_token);
7046   field_name[end - cur_token] = '\0';
7047
7048   cur_token = end;
7049   
7050   * index = cur_token;
7051   * result = field_name;
7052   
7053   return MAILIMF_NO_ERROR;
7054 }
7055
7056 /*
7057 ftext           =       %d33-57 /               ; Any character except
7058                         %d59-126                ;  controls, SP, and
7059                                                 ;  ":".
7060 */
7061
7062 static inline int is_ftext(char ch)
7063 {
7064   unsigned char uch = (unsigned char) ch;
7065
7066   if (uch < 33)
7067     return FALSE;
7068
7069   if (uch == 58)
7070     return FALSE;
7071
7072   return TRUE;
7073 }
7074
7075 /*
7076 static int mailimf_ftext_parse(const char * message, size_t length,
7077                                     size_t * index, gchar * result)
7078 {
7079   return mailimf_typed_text_parse(message, length, index, result, is_ftext);
7080 }
7081 */
7082
7083
7084
7085
7086 static int mailimf_envelope_field_parse(const char * message, size_t length,
7087                                         size_t * index,
7088                                         struct mailimf_field ** result)
7089 {
7090   size_t cur_token;
7091   int type;
7092   struct mailimf_orig_date * orig_date;
7093   struct mailimf_from * from;
7094   struct mailimf_sender * sender;
7095   struct mailimf_reply_to * reply_to;
7096   struct mailimf_to * to;
7097   struct mailimf_cc * cc;
7098   struct mailimf_bcc * bcc;
7099   struct mailimf_message_id * message_id;
7100   struct mailimf_in_reply_to * in_reply_to;
7101   struct mailimf_references * references;
7102   struct mailimf_subject * subject;
7103   struct mailimf_optional_field * optional_field;
7104   struct mailimf_field * field;
7105   int guessed_type;
7106   int r;
7107   int res;
7108   
7109   cur_token = * index;
7110
7111   orig_date = NULL;
7112   from = NULL;
7113   sender = NULL;
7114   reply_to = NULL;
7115   to = NULL;
7116   cc = NULL;
7117   bcc = NULL;
7118   message_id = NULL;
7119   in_reply_to = NULL;
7120   references = NULL;
7121   subject = NULL;
7122   optional_field = NULL;
7123
7124   guessed_type = guess_header_type(message, length, cur_token);
7125   type = MAILIMF_FIELD_NONE;
7126
7127   switch (guessed_type) {
7128   case MAILIMF_FIELD_ORIG_DATE:
7129     r = mailimf_orig_date_parse(message, length, &cur_token,
7130                                 &orig_date);
7131     if (r == MAILIMF_NO_ERROR)
7132       type = guessed_type;
7133     else if (r == MAILIMF_ERROR_PARSE) {
7134       /* do nothing */
7135     }
7136     else {
7137       res = r;
7138       goto err;
7139     }
7140     break;
7141   case MAILIMF_FIELD_FROM:
7142     r = mailimf_from_parse(message, length, &cur_token,
7143                            &from);
7144     if (r == MAILIMF_NO_ERROR)
7145       type = guessed_type;
7146     else if (r == MAILIMF_ERROR_PARSE) {
7147       /* do nothing */
7148     }
7149     else {
7150       res = r;
7151       goto err;
7152     }
7153     break;
7154   case MAILIMF_FIELD_SENDER:
7155     r = mailimf_sender_parse(message, length, &cur_token,
7156                              &sender);
7157     if (r == MAILIMF_NO_ERROR)
7158       type = guessed_type;
7159     else if (r == MAILIMF_ERROR_PARSE) {
7160       /* do nothing */
7161     }
7162     else {
7163       res = r;
7164       goto err;
7165     }
7166     break;
7167   case MAILIMF_FIELD_REPLY_TO:
7168     r = mailimf_reply_to_parse(message, length, &cur_token,
7169                                &reply_to);
7170     if (r == MAILIMF_NO_ERROR)
7171       type = guessed_type;
7172     else if (r == MAILIMF_ERROR_PARSE) {
7173       /* do nothing */
7174     }
7175     else {
7176       res = r;
7177       goto err;
7178     }
7179     break;
7180   case MAILIMF_FIELD_TO:
7181     r = mailimf_to_parse(message, length, &cur_token,
7182                          &to);
7183     if (r == MAILIMF_NO_ERROR)
7184       type = guessed_type;
7185     else if (r == MAILIMF_ERROR_PARSE) {
7186       /* do nothing */
7187     }
7188     else {
7189       res = r;
7190       goto err;
7191     }
7192     break;
7193   case MAILIMF_FIELD_CC:
7194     r = mailimf_cc_parse(message, length, &cur_token,
7195                          &cc);
7196     if (r == MAILIMF_NO_ERROR)
7197       type = guessed_type;
7198     else if (r == MAILIMF_ERROR_PARSE) {
7199       /* do nothing */
7200     }
7201     else {
7202       res = r;
7203       goto err;
7204     }
7205     break;
7206   case MAILIMF_FIELD_BCC:
7207     r = mailimf_bcc_parse(message, length, &cur_token,
7208                           &bcc);
7209     if (r == MAILIMF_NO_ERROR)
7210       type = guessed_type;
7211     else if (r == MAILIMF_ERROR_PARSE) {
7212       /* do nothing */
7213     }
7214     else {
7215       res = r;
7216       goto err;
7217     }
7218     break;
7219   case MAILIMF_FIELD_MESSAGE_ID:
7220     r = mailimf_message_id_parse(message, length, &cur_token,
7221                                  &message_id);
7222     if (r == MAILIMF_NO_ERROR)
7223       type = guessed_type;
7224     else if (r == MAILIMF_ERROR_PARSE) {
7225       /* do nothing */
7226     }
7227     else {
7228       res = r;
7229       goto err;
7230     }
7231     break;
7232   case MAILIMF_FIELD_IN_REPLY_TO:
7233     r = mailimf_in_reply_to_parse(message, length, &cur_token,
7234                                   &in_reply_to);
7235     if (r == MAILIMF_NO_ERROR)
7236       type = guessed_type;
7237     else if (r == MAILIMF_ERROR_PARSE) {
7238       /* do nothing */
7239     }
7240     else {
7241       res = r;
7242       goto err;
7243     }
7244     break;
7245   case MAILIMF_FIELD_REFERENCES:
7246     r = mailimf_references_parse(message, length, &cur_token,
7247                                  &references);
7248     if (r == MAILIMF_NO_ERROR)
7249       type = guessed_type;
7250     else if (r == MAILIMF_ERROR_PARSE) {
7251       /* do nothing */
7252     }
7253     else {
7254       res = r;
7255       goto err;
7256     }
7257     break;
7258   case MAILIMF_FIELD_SUBJECT:
7259     r = mailimf_subject_parse(message, length, &cur_token,
7260                               &subject);
7261     if (r == MAILIMF_NO_ERROR)
7262       type = guessed_type;
7263     else if (r == MAILIMF_ERROR_PARSE) {
7264       /* do nothing */
7265     }
7266     else {
7267       res = r;
7268       goto err;
7269     }
7270     break;
7271   }
7272
7273   if (type == MAILIMF_FIELD_NONE) {
7274     res = MAILIMF_ERROR_PARSE;
7275     goto err;
7276   }
7277
7278   field = mailimf_field_new(type, NULL, NULL, NULL, NULL, NULL,
7279       NULL, NULL, NULL,
7280       orig_date, from, sender, reply_to, to,
7281       cc, bcc, message_id, in_reply_to, references,
7282       subject, NULL, NULL, optional_field);
7283   if (field == NULL) {
7284     res = MAILIMF_ERROR_MEMORY;
7285     goto free_field;
7286   }
7287   
7288   * result = field;
7289   * index = cur_token;
7290
7291   return MAILIMF_NO_ERROR;
7292
7293  free_field:
7294   if (orig_date != NULL)
7295     mailimf_orig_date_free(orig_date);
7296   if (from != NULL)
7297     mailimf_from_free(from);
7298   if (sender != NULL)
7299     mailimf_sender_free(sender);
7300   if (reply_to != NULL)
7301     mailimf_reply_to_free(reply_to);
7302   if (to != NULL)
7303     mailimf_to_free(to);
7304   if (cc != NULL)
7305     mailimf_cc_free(cc);
7306   if (bcc != NULL)
7307     mailimf_bcc_free(bcc);
7308   if (message_id != NULL)
7309     mailimf_message_id_free(message_id);
7310   if (in_reply_to != NULL)
7311     mailimf_in_reply_to_free(in_reply_to);
7312   if (references != NULL)
7313     mailimf_references_free(references);
7314   if (subject != NULL)
7315     mailimf_subject_free(subject);
7316   if (optional_field != NULL)
7317     mailimf_optional_field_free(optional_field);
7318  err:
7319   return res;
7320 }
7321
7322 int mailimf_envelope_fields_parse(const char * message, size_t length,
7323                                   size_t * index,
7324                                   struct mailimf_fields ** result)
7325 {
7326   size_t cur_token;
7327   clist * list;
7328   struct mailimf_fields * fields;
7329   int r;
7330   int res;
7331
7332   cur_token = * index;
7333
7334   list = clist_new();
7335   if (list == NULL) {
7336     res = MAILIMF_ERROR_MEMORY;
7337     goto err;
7338   }
7339
7340   while (1) {
7341     struct mailimf_field * elt;
7342
7343     r = mailimf_envelope_field_parse(message, length, &cur_token, &elt);
7344     if (r == MAILIMF_NO_ERROR) {
7345       r = clist_append(list, elt);
7346       if (r < 0) {
7347         res = MAILIMF_ERROR_MEMORY;
7348         goto free;
7349       }
7350     }
7351     else if (r == MAILIMF_ERROR_PARSE) {
7352       r = mailimf_ignore_field_parse(message, length, &cur_token);
7353       if (r == MAILIMF_NO_ERROR) {
7354         /* do nothing */
7355       }
7356       else if (r == MAILIMF_ERROR_PARSE) {
7357         break;
7358       }
7359       else {
7360         res = r;
7361         goto free;
7362       }
7363     }
7364     else {
7365       res = r;
7366       goto free;
7367     }
7368   }
7369
7370   fields = mailimf_fields_new(list);
7371   if (fields == NULL) {
7372     res = MAILIMF_ERROR_MEMORY;
7373     goto free;
7374   }
7375
7376   * result = fields;
7377   * index = cur_token;
7378
7379   return MAILIMF_NO_ERROR;
7380
7381  free:
7382   if (list != NULL) {
7383     clist_foreach(list, (clist_func) mailimf_field_free, NULL);
7384     clist_free(list);
7385   }
7386  err:
7387   return res;
7388 }
7389
7390
7391 static int
7392 mailimf_envelope_or_optional_field_parse(const char * message,
7393                                          size_t length,
7394                                          size_t * index,
7395                                          struct mailimf_field ** result)
7396 {
7397   int r;
7398   size_t cur_token;
7399   struct mailimf_optional_field * optional_field;
7400   struct mailimf_field * field;
7401
7402   r = mailimf_envelope_field_parse(message, length, index, result);
7403   if (r == MAILIMF_NO_ERROR)
7404     return MAILIMF_NO_ERROR;
7405
7406   cur_token = * index;
7407
7408   r = mailimf_optional_field_parse(message, length, &cur_token,
7409                                    &optional_field);
7410   if (r != MAILIMF_NO_ERROR)
7411     return r;
7412
7413   field = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD, NULL,
7414       NULL, NULL, NULL,
7415       NULL, NULL, NULL,
7416       NULL, NULL, NULL,
7417       NULL, NULL, NULL,
7418       NULL, NULL, NULL, NULL, NULL,
7419       NULL, NULL, NULL, optional_field);
7420   if (field == NULL) {
7421     mailimf_optional_field_free(optional_field);
7422     return MAILIMF_ERROR_MEMORY;
7423   }
7424
7425   * result = field;
7426   * index = cur_token;
7427
7428   return MAILIMF_NO_ERROR;
7429 }
7430
7431
7432 int
7433 mailimf_envelope_and_optional_fields_parse(const char * message, size_t length,
7434                                            size_t * index,
7435                                            struct mailimf_fields ** result)
7436 {
7437   size_t cur_token;
7438   clist * list;
7439   struct mailimf_fields * fields;
7440   int r;
7441   int res;
7442
7443   cur_token = * index;
7444
7445   list = NULL;
7446
7447   r = mailimf_struct_multiple_parse(message, length, &cur_token,
7448                                     &list,
7449                                     (mailimf_struct_parser *)
7450                                     mailimf_envelope_or_optional_field_parse,
7451                                     (mailimf_struct_destructor *)
7452                                     mailimf_field_free);
7453   switch (r) {
7454   case MAILIMF_NO_ERROR:
7455     /* do nothing */
7456     break;
7457
7458   case MAILIMF_ERROR_PARSE:
7459     list = clist_new();
7460     if (list == NULL) {
7461       res = MAILIMF_ERROR_MEMORY;
7462       goto err;
7463     }
7464     break;
7465
7466   default:
7467     res = r;
7468     goto err;
7469   }
7470
7471   fields = mailimf_fields_new(list);
7472   if (fields == NULL) {
7473     res = MAILIMF_ERROR_MEMORY;
7474     goto free;
7475   }
7476
7477   * result = fields;
7478   * index = cur_token;
7479
7480   return MAILIMF_NO_ERROR;
7481
7482  free:
7483   if (list != NULL) {
7484     clist_foreach(list, (clist_func) mailimf_field_free, NULL);
7485     clist_free(list);
7486   }
7487  err:
7488   return res;
7489 }
7490
7491
7492
7493 static int
7494 mailimf_only_optional_field_parse(const char * message,
7495                                   size_t length,
7496                                   size_t * index,
7497                                   struct mailimf_field ** result)
7498 {
7499   int r;
7500   size_t cur_token;
7501   struct mailimf_optional_field * optional_field;
7502   struct mailimf_field * field;
7503
7504   cur_token = * index;
7505
7506   r = mailimf_optional_field_parse(message, length, &cur_token,
7507                                    &optional_field);
7508   if (r != MAILIMF_NO_ERROR)
7509     return r;
7510
7511   field = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD, NULL, NULL, NULL,
7512       NULL, NULL, NULL, NULL, NULL,
7513       NULL, NULL, NULL, NULL, NULL,
7514       NULL, NULL, NULL, NULL, NULL,
7515       NULL, NULL, NULL, optional_field);
7516   if (field == NULL) {
7517     mailimf_optional_field_free(optional_field);
7518     return MAILIMF_ERROR_MEMORY;
7519   }
7520
7521   * result = field;
7522   * index = cur_token;
7523
7524   return MAILIMF_NO_ERROR;
7525 }
7526
7527
7528 int
7529 mailimf_optional_fields_parse(const char * message, size_t length,
7530                               size_t * index,
7531                               struct mailimf_fields ** result)
7532 {
7533   size_t cur_token;
7534   clist * list;
7535   struct mailimf_fields * fields;
7536   int r;
7537   int res;
7538
7539   cur_token = * index;
7540
7541   list = NULL;
7542
7543   r = mailimf_struct_multiple_parse(message, length, &cur_token,
7544                                     &list,
7545                                     (mailimf_struct_parser *)
7546                                     mailimf_only_optional_field_parse,
7547                                     (mailimf_struct_destructor *)
7548                                     mailimf_field_free);
7549   switch (r) {
7550   case MAILIMF_NO_ERROR:
7551     /* do nothing */
7552     break;
7553
7554   case MAILIMF_ERROR_PARSE:
7555     list = clist_new();
7556     if (list == NULL) {
7557       res = MAILIMF_ERROR_MEMORY;
7558       goto err;
7559     }
7560     break;
7561
7562   default:
7563     res = r;
7564     goto err;
7565   }
7566
7567   fields = mailimf_fields_new(list);
7568   if (fields == NULL) {
7569     res = MAILIMF_ERROR_MEMORY;
7570     goto free;
7571   }
7572
7573   * result = fields;
7574   * index = cur_token;
7575
7576   return MAILIMF_NO_ERROR;
7577
7578  free:
7579   if (list != NULL) {
7580     clist_foreach(list, (clist_func) mailimf_field_free, NULL);
7581     clist_free(list);
7582   }
7583  err:
7584   return res;
7585 }