Wow. Such data, so leak, very unfreed
[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       res = r;
3012       goto free_display_name;
3013     }
3014     break;
3015   default:
3016     res = r;
3017     goto free_display_name;
3018   }
3019
3020   r = mailimf_semi_colon_parse(message, length, &cur_token);
3021   if (r != MAILIMF_NO_ERROR) {
3022     res = r;
3023     goto free_mailbox_list;
3024   }
3025
3026   group = mailimf_group_new(display_name, mailbox_list);
3027   if (group == NULL) {
3028     res = MAILIMF_ERROR_MEMORY;
3029     goto free_mailbox_list;
3030   }
3031
3032   * index = cur_token;
3033   * result = group;
3034
3035   return MAILIMF_NO_ERROR;
3036
3037  free_mailbox_list:
3038   mailimf_mailbox_list_free(mailbox_list);
3039  free_display_name:
3040   mailimf_display_name_free(display_name);
3041  err:
3042   return res;
3043 }
3044
3045 /*
3046 display-name    =       phrase
3047 */
3048
3049 static int mailimf_display_name_parse(const char * message, size_t length,
3050                                       size_t * index, char ** result)
3051 {
3052   return mailimf_phrase_parse(message, length, index, result);
3053 }
3054
3055 /*
3056 mailbox-list    =       (mailbox *("," mailbox)) / obs-mbox-list
3057 */
3058
3059 int
3060 mailimf_mailbox_list_parse(const char * message, size_t length,
3061                            size_t * index,
3062                            struct mailimf_mailbox_list ** result)
3063 {
3064   size_t cur_token;
3065   clist * list;
3066   struct mailimf_mailbox_list * mailbox_list;
3067   int r;
3068   int res;
3069
3070   cur_token = * index;
3071
3072   r = mailimf_struct_list_parse(message, length, 
3073                                 &cur_token, &list, ',',
3074                                 (mailimf_struct_parser *)
3075                                 mailimf_mailbox_parse,
3076                                 (mailimf_struct_destructor *)
3077                                 mailimf_mailbox_free);
3078   if (r != MAILIMF_NO_ERROR) {
3079     res = r;
3080     goto err;
3081   }
3082
3083   mailbox_list = mailimf_mailbox_list_new(list);
3084   if (mailbox_list == NULL) {
3085     res = MAILIMF_ERROR_MEMORY;
3086     goto free_list;
3087   }
3088
3089   * result = mailbox_list;
3090   * index = cur_token;
3091
3092   return MAILIMF_NO_ERROR;
3093
3094  free_list:
3095   clist_foreach(list, (clist_func) mailimf_mailbox_free, NULL);
3096   clist_free(list);
3097  err:
3098   return res;
3099 }                                  
3100
3101 /*
3102 address-list    =       (address *("," address)) / obs-addr-list
3103 */
3104
3105
3106 int
3107 mailimf_address_list_parse(const char * message, size_t length,
3108                            size_t * index,
3109                            struct mailimf_address_list ** result)
3110 {
3111   size_t cur_token;
3112   clist * list;
3113   struct mailimf_address_list * address_list;
3114   int r;
3115   int res;
3116
3117   cur_token = * index;
3118
3119   r = mailimf_struct_list_parse(message, length,
3120                                 &cur_token, &list, ',',
3121                                 (mailimf_struct_parser *)
3122                                 mailimf_address_parse,
3123                                 (mailimf_struct_destructor *)
3124                                 mailimf_address_free);
3125   if (r != MAILIMF_NO_ERROR) {
3126     res = r;
3127     goto err;
3128   }
3129
3130   address_list = mailimf_address_list_new(list);
3131   if (address_list == NULL) {
3132     res = MAILIMF_ERROR_MEMORY;
3133     goto free_list;
3134   }
3135
3136   * result = address_list;
3137   * index = cur_token;
3138
3139   return MAILIMF_NO_ERROR;
3140
3141  free_list:
3142   clist_foreach(list, (clist_func) mailimf_address_free, NULL);
3143   clist_free(list);
3144  err:
3145   return res;
3146 }                                  
3147
3148 /*
3149 addr-spec       =       local-part "@" domain
3150 */
3151
3152
3153 static int mailimf_addr_spec_parse(const char * message, size_t length,
3154                                    size_t * index,
3155                                    char ** result)
3156 {
3157   size_t cur_token;
3158 #if 0
3159   char * local_part;
3160   char * domain;
3161 #endif
3162   char * addr_spec;
3163   int r;
3164   int res;
3165   size_t begin;
3166   size_t end;
3167   int final;
3168   size_t count;
3169   const char * src;
3170   char * dest;
3171   size_t i;
3172   
3173   cur_token = * index;
3174   
3175   r = mailimf_cfws_parse(message, length, &cur_token);
3176   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
3177     res = r;
3178     goto err;
3179   }
3180
3181   end = cur_token;
3182   if (end >= length) {
3183     res = MAILIMF_ERROR_PARSE;
3184     goto err;
3185   }
3186
3187   begin = cur_token;
3188
3189   final = FALSE;
3190   while (1) {
3191     switch (message[end]) {
3192     case '>':
3193     case ',':
3194     case '\r':
3195     case '\n':
3196     case '(':
3197     case ')':
3198     case ':':
3199     case ';':
3200       final = TRUE;
3201       break;
3202     }
3203
3204     if (final)
3205       break;
3206
3207     end ++;
3208     if (end >= length)
3209       break;
3210   }
3211
3212   if (end == begin) {
3213     res = MAILIMF_ERROR_PARSE;
3214     goto err;
3215   }
3216   
3217   addr_spec = malloc(end - cur_token + 1);
3218   if (addr_spec == NULL) {
3219     res = MAILIMF_ERROR_MEMORY;
3220     goto err;
3221   }
3222   
3223   count = end - cur_token;
3224   src = message + cur_token;
3225   dest = addr_spec;
3226   for(i = 0 ; i < count ; i ++) {
3227     if ((* src != ' ') && (* src != '\t')) {
3228       * dest = * src;
3229       dest ++;
3230     }
3231     src ++;
3232   }
3233   * dest = '\0';
3234   
3235 #if 0
3236   strncpy(addr_spec, message + cur_token, end - cur_token);
3237   addr_spec[end - cur_token] = '\0';
3238 #endif
3239
3240   cur_token = end;
3241
3242 #if 0
3243   r = mailimf_local_part_parse(message, length, &cur_token, &local_part);
3244   if (r != MAILIMF_NO_ERROR) {
3245     res = r;
3246     goto err;
3247   }
3248
3249   r = mailimf_at_sign_parse(message, length, &cur_token);
3250   switch (r) {
3251   case MAILIMF_NO_ERROR:
3252     r = mailimf_domain_parse(message, length, &cur_token, &domain);
3253     if (r != MAILIMF_NO_ERROR) {
3254       res = r;
3255       goto free_local_part;
3256     }
3257     break;
3258
3259   case MAILIMF_ERROR_PARSE:
3260     domain = NULL;
3261     break;
3262
3263   default:
3264     res = r;
3265     goto free_local_part;
3266   }
3267
3268   if (domain) {
3269     addr_spec = malloc(strlen(local_part) + strlen(domain) + 2);
3270     if (addr_spec == NULL) {
3271       res = MAILIMF_ERROR_MEMORY;
3272       goto free_domain;
3273     }
3274     
3275     strcpy(addr_spec, local_part);
3276     strcat(addr_spec, "@");
3277     strcat(addr_spec, domain);
3278
3279     mailimf_domain_free(domain);
3280     mailimf_local_part_free(local_part);
3281   }
3282   else {
3283     addr_spec = local_part;
3284   }
3285 #endif
3286
3287   * result = addr_spec;
3288   * index = cur_token;
3289
3290   return MAILIMF_NO_ERROR;
3291
3292 #if 0
3293  free_domain:
3294   mailimf_domain_free(domain);
3295  free_local_part:
3296   mailimf_local_part_free(local_part);
3297 #endif
3298  err:
3299   return res;
3300 }
3301
3302 /*
3303 local-part      =       dot-atom / quoted-string / obs-local-part
3304 */
3305
3306 #if 0
3307 static int mailimf_local_part_parse(const char * message, size_t length,
3308                                     size_t * index,
3309                                     char ** result)
3310 {
3311   int r;
3312
3313   r = mailimf_dot_atom_parse(message, length, index, result);
3314   switch (r) {
3315   case MAILIMF_NO_ERROR:
3316     return r;
3317   case MAILIMF_ERROR_PARSE:
3318     break;
3319   default:
3320     return r;
3321   }
3322
3323   r = mailimf_quoted_string_parse(message, length, index, result);
3324   if (r != MAILIMF_NO_ERROR)
3325     return r;
3326
3327   return MAILIMF_NO_ERROR;
3328 }
3329 #endif
3330
3331 /*
3332 domain          =       dot-atom / domain-literal / obs-domain
3333 */
3334
3335 #if 0
3336 static int mailimf_domain_parse(const char * message, size_t length,
3337                                 size_t * index,
3338                                 char ** result)
3339 {
3340   int r;
3341
3342   r = mailimf_dot_atom_parse(message, length, index, result);
3343   switch (r) {
3344   case MAILIMF_NO_ERROR:
3345     return r;
3346   case MAILIMF_ERROR_PARSE:
3347     break;
3348   default:
3349     return r;
3350   }
3351
3352   r = mailimf_domain_literal_parse(message, length, index, result);
3353   if (r != MAILIMF_NO_ERROR)
3354     return r;
3355
3356   return MAILIMF_NO_ERROR;
3357 }
3358 #endif
3359
3360 /*
3361 [FWS] dcontent
3362 */
3363
3364 #if 0
3365 static int
3366 mailimf_domain_literal_fws_dcontent_parse(const char * message, size_t length,
3367                                           size_t * index)
3368 {
3369   size_t cur_token;
3370   char ch;
3371   int r;
3372
3373   cur_token = * index;
3374
3375   r = mailimf_cfws_parse(message, length, &cur_token);
3376   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
3377     return r;
3378   
3379   r = mailimf_dcontent_parse(message, length, &cur_token, &ch);
3380   if (r != MAILIMF_NO_ERROR)
3381     return r;
3382
3383   * index = cur_token;
3384
3385   return MAILIMF_NO_ERROR;
3386 }
3387 #endif
3388
3389 /*
3390 domain-literal  =       [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
3391 */
3392
3393 #if 0
3394 static int mailimf_domain_literal_parse(const char * message, size_t length,
3395                                         size_t * index, char ** result)
3396 {
3397   size_t cur_token;
3398   int len;
3399   int begin;
3400   char * domain_literal;
3401   int r;
3402
3403   cur_token = * index;
3404
3405   r = mailimf_cfws_parse(message, length, &cur_token);
3406   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
3407     return r;
3408
3409   begin = cur_token;
3410   r = mailimf_obracket_parse(message, length, &cur_token);
3411   if (r != MAILIMF_NO_ERROR)
3412     return r;
3413
3414   while (1) {
3415     r = mailimf_domain_literal_fws_dcontent_parse(message, length,
3416                                                   &cur_token);
3417     if (r == MAILIMF_NO_ERROR) {
3418       /* do nothing */
3419     }
3420     else if (r == MAILIMF_ERROR_PARSE)
3421       break;
3422     else
3423       return r;
3424   }
3425
3426   r = mailimf_fws_parse(message, length, &cur_token);
3427   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
3428     return r;
3429
3430   r = mailimf_cbracket_parse(message, length, &cur_token);
3431   if (r != MAILIMF_NO_ERROR)
3432     return r;
3433
3434   len = cur_token - begin;
3435
3436   domain_literal = malloc(len + 1);
3437   if (domain_literal == NULL)
3438     return MAILIMF_ERROR_MEMORY;
3439   strncpy(domain_literal, message + begin, len);
3440   domain_literal[len] = '\0';
3441
3442   * result = domain_literal;
3443   * index = cur_token;
3444
3445   return MAILIMF_NO_ERROR;
3446 }
3447 #endif
3448
3449 /*
3450 dcontent        =       dtext / quoted-pair
3451 */
3452
3453 #if 0
3454 static int mailimf_dcontent_parse(const char * message, size_t length,
3455                                   size_t * index, char * result)
3456 {
3457   size_t cur_token;
3458   char ch;
3459   int r;
3460   
3461   cur_token = * index;
3462
3463   if (cur_token >= length)
3464     return MAILIMF_ERROR_PARSE;
3465
3466   if (is_dtext(message[cur_token])) {
3467     ch = message[cur_token];
3468     cur_token ++;
3469   }
3470   else {
3471     r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
3472     
3473     if (r != MAILIMF_NO_ERROR)
3474       return r;
3475   }
3476     
3477   * index = cur_token;
3478   * result = ch;
3479
3480   return MAILIMF_NO_ERROR;
3481 }
3482 #endif
3483
3484
3485 /*
3486 dtext           =       NO-WS-CTL /     ; Non white space controls
3487
3488                         %d33-90 /       ; The rest of the US-ASCII
3489                         %d94-126        ;  characters not including "[",
3490                                         ;  "]", or "\"
3491 */
3492
3493 static inline int is_dtext(char ch)
3494 {
3495   unsigned char uch = (unsigned char) ch;
3496
3497   if (is_no_ws_ctl(ch))
3498     return TRUE;
3499
3500   if (uch < 33)
3501     return FALSE;
3502
3503   if ((uch >= 91) && (uch <= 93))
3504     return FALSE;
3505
3506   if (uch == 127)
3507     return FALSE;
3508
3509   return TRUE;
3510 }
3511
3512 /*
3513 message         =       (fields / obs-fields)
3514                         [CRLF body]
3515 */
3516
3517 int mailimf_message_parse(const char * message, size_t length,
3518                           size_t * index,
3519                           struct mailimf_message ** result)
3520 {
3521   struct mailimf_fields * fields;
3522   struct mailimf_body * body;
3523   struct mailimf_message * msg;
3524   size_t cur_token;
3525   int r;
3526   int res;
3527
3528   cur_token = * index;
3529
3530   r = mailimf_fields_parse(message, length, &cur_token, &fields);
3531   if (r != MAILIMF_NO_ERROR) {
3532     res = r;
3533     goto err;
3534   }
3535
3536   r = mailimf_crlf_parse(message, length, &cur_token);
3537   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
3538     res = r;
3539     goto err;
3540   }
3541
3542   r = mailimf_body_parse(message, length, &cur_token, &body);
3543   if (r != MAILIMF_NO_ERROR) {
3544     res = r;
3545     goto free_fields;
3546   }
3547
3548   msg = mailimf_message_new(fields, body);
3549   if (msg == NULL) {
3550     res = MAILIMF_ERROR_MEMORY;
3551     goto free_body;
3552   }
3553
3554   * index = cur_token;
3555   * result = msg;
3556
3557   return MAILIMF_NO_ERROR;
3558
3559  free_body:
3560   mailimf_body_free(body);
3561  free_fields:
3562   mailimf_fields_free(fields);
3563  err:
3564   return res;
3565 }
3566
3567 /*
3568 body            =       *(*998text CRLF) *998text
3569 */
3570
3571 int mailimf_body_parse(const char * message, size_t length,
3572                        size_t * index,
3573                        struct mailimf_body ** result)
3574 {
3575   size_t cur_token;
3576   struct mailimf_body * body;
3577
3578   cur_token = * index;
3579
3580   body = mailimf_body_new(message + cur_token, length - cur_token);
3581   if (body == NULL)
3582     return MAILIMF_ERROR_MEMORY;
3583
3584   cur_token = length;
3585
3586   * result = body;
3587   * index = cur_token;
3588
3589   return MAILIMF_NO_ERROR;
3590 }
3591
3592 /*
3593 CHANGE TO THE RFC 2822
3594
3595 original :
3596
3597 fields          =       *(trace
3598                           *(resent-date /
3599                            resent-from /
3600                            resent-sender /
3601                            resent-to /
3602                            resent-cc /
3603                            resent-bcc /
3604                            resent-msg-id))
3605                         *(orig-date /
3606                         from /
3607                         sender /
3608                         reply-to /
3609                         to /
3610                         cc /
3611                         bcc /
3612                         message-id /
3613                         in-reply-to /
3614                         references /
3615                         subject /
3616                         comments /
3617                         keywords /
3618                         optional-field)
3619
3620 INTO THE FOLLOWING :
3621 */
3622
3623 /*
3624 resent-fields-list =      *(resent-date /
3625                            resent-from /
3626                            resent-sender /
3627                            resent-to /
3628                            resent-cc /
3629                            resent-bcc /
3630                            resent-msg-id))
3631 */
3632
3633 #if 0
3634 enum {
3635   RESENT_HEADER_START,
3636 };
3637
3638 static int guess_resent_header_type(char * message,
3639                                     size_t length, size_t index)
3640 {
3641   int r;
3642
3643   r = mailimf_token_case_insensitive_parse(message,
3644                                            length, &index, "Resent-");
3645   if (r != MAILIMF_NO_ERROR)
3646     return MAILIMF_RESENT_FIELD_NONE;
3647   
3648   if (index >= length)
3649     return MAILIMF_RESENT_FIELD_NONE;
3650
3651   switch(toupper(message[index])) {
3652   case 'D':
3653     return MAILIMF_RESENT_FIELD_DATE;
3654   case 'F':
3655     return MAILIMF_RESENT_FIELD_FROM;
3656   case 'S':
3657     return MAILIMF_RESENT_FIELD_SENDER;
3658   case 'T':
3659     return MAILIMF_RESENT_FIELD_TO;
3660   case 'C':
3661     return MAILIMF_RESENT_FIELD_CC;
3662   case 'B':
3663     return MAILIMF_RESENT_FIELD_BCC;
3664   case 'M':
3665     return MAILIMF_RESENT_FIELD_MSG_ID;
3666   default:
3667     return MAILIMF_RESENT_FIELD_NONE;
3668   }
3669 }
3670 #endif
3671
3672 #if 0
3673 static int
3674 mailimf_resent_field_parse(const char * message, size_t length,
3675                            size_t * index,
3676                            struct mailimf_resent_field ** result)
3677 {
3678   struct mailimf_orig_date * resent_date;
3679   struct mailimf_from * resent_from;
3680   struct mailimf_sender * resent_sender;
3681   struct mailimf_to* resent_to;
3682   struct mailimf_cc * resent_cc;
3683   struct mailimf_bcc * resent_bcc;
3684   struct mailimf_message_id * resent_msg_id;
3685   size_t cur_token;
3686   int type;
3687   struct mailimf_resent_field * resent_field;
3688   int r;
3689   int res;
3690
3691   cur_token = * index;
3692
3693   resent_date = NULL;
3694   resent_from = NULL;
3695   resent_sender = NULL;
3696   resent_to = NULL;
3697   resent_cc = NULL;
3698   resent_bcc = NULL;
3699   resent_msg_id = NULL;
3700
3701   type = guess_resent_header_type(message, length, cur_token);
3702
3703   switch(type) {
3704   case MAILIMF_RESENT_FIELD_DATE:
3705     r = mailimf_resent_date_parse(message, length, &cur_token,
3706                                   &resent_date);
3707     if (r != MAILIMF_NO_ERROR) {
3708       res = r;
3709       goto free_resent;
3710     }
3711     break;
3712   case MAILIMF_RESENT_FIELD_FROM:
3713     r = mailimf_resent_from_parse(message, length, &cur_token,
3714                                   &resent_from);
3715     if (r != MAILIMF_NO_ERROR) {
3716       res = r;
3717       goto free_resent;
3718     }
3719     break;
3720   case MAILIMF_RESENT_FIELD_SENDER:
3721     r = mailimf_resent_sender_parse(message, length, &cur_token,
3722                                     &resent_sender);
3723     if (r != MAILIMF_NO_ERROR) {
3724       res = r;
3725       goto free_resent;
3726     }
3727     break;
3728   case MAILIMF_RESENT_FIELD_TO:
3729     r = mailimf_resent_to_parse(message, length, &cur_token,
3730                                 &resent_to);
3731     if (r != MAILIMF_NO_ERROR) {
3732       res = r;
3733       goto free_resent;
3734     }
3735     break;
3736   case MAILIMF_RESENT_FIELD_CC:
3737     r= mailimf_resent_cc_parse(message, length, &cur_token,
3738                                &resent_cc);
3739     if (r != MAILIMF_NO_ERROR) {
3740       res = r;
3741       goto free_resent;
3742     }
3743     break;
3744   case MAILIMF_RESENT_FIELD_BCC:
3745     r = mailimf_resent_bcc_parse(message, length, &cur_token,
3746                                  &resent_bcc);
3747     if (r != MAILIMF_NO_ERROR) {
3748       res = r;
3749       goto free_resent;
3750     }
3751     break;
3752   case MAILIMF_RESENT_FIELD_MSG_ID:
3753     r = mailimf_resent_msg_id_parse(message, length, &cur_token,
3754                                     &resent_msg_id);
3755     if (r != MAILIMF_NO_ERROR) {
3756       res = r;
3757       goto free_resent;
3758     }
3759     break;
3760   default:
3761     res = MAILIMF_ERROR_PARSE;
3762     goto free_resent;
3763   }
3764
3765   resent_field = mailimf_resent_field_new(type, resent_date,
3766                                           resent_from, resent_sender,
3767                                           resent_to, resent_cc,
3768                                           resent_bcc, resent_msg_id);
3769   if (resent_field == NULL) {
3770     res = MAILIMF_ERROR_MEMORY;
3771     goto free_resent;
3772   }
3773
3774   * result = resent_field;
3775   * index = cur_token;
3776
3777   return MAILIMF_NO_ERROR;
3778
3779  free_resent:
3780   if (resent_msg_id != NULL)
3781     mailimf_message_id_free(resent_msg_id);
3782   if (resent_bcc != NULL)
3783     mailimf_bcc_free(resent_bcc);
3784   if (resent_cc != NULL)
3785     mailimf_cc_free(resent_cc);
3786   if (resent_to != NULL)
3787     mailimf_to_free(resent_to);
3788   if (resent_sender != NULL)
3789     mailimf_sender_free(resent_sender);
3790   if (resent_from != NULL)
3791     mailimf_from_free(resent_from);
3792   if (resent_date != NULL)
3793     mailimf_orig_date_free(resent_date);
3794  err:
3795   return res;
3796 }
3797 #endif
3798
3799 #if 0
3800 static int
3801 mailimf_resent_fields_list_parse(const char * message, size_t length,
3802                                  size_t * index,
3803                                  struct mailimf_resent_fields_list ** result)
3804 {
3805   clist * list;
3806   size_t cur_token;
3807   struct mailimf_resent_fields_list * resent_fields_list;
3808   int r;
3809   int res;
3810
3811   cur_token = * index;
3812   list = NULL;
3813
3814   r = mailimf_struct_multiple_parse(message, length, &cur_token, &list,
3815                                     (mailimf_struct_parser *)
3816                                     mailimf_resent_field_parse,
3817                                     (mailimf_struct_destructor *)
3818                                     mailimf_resent_field_free);
3819   if (r != MAILIMF_NO_ERROR) {
3820     res = r;
3821     goto err;
3822   }
3823
3824   resent_fields_list = mailimf_resent_fields_list_new(list);
3825   if (resent_fields_list == NULL) {
3826     res = MAILIMF_ERROR_MEMORY;
3827     goto free_list;
3828   }
3829
3830   * result = resent_fields_list;
3831   * index = cur_token;
3832
3833   return MAILIMF_NO_ERROR;
3834
3835  free_list:
3836   clist_foreach(list, (clist_func) mailimf_resent_field_free, NULL);
3837   clist_free(list);
3838  err:
3839   return res;
3840 }
3841 #endif
3842
3843 /*
3844  ([trace]
3845   [resent-fields-list])
3846 */
3847
3848 #if 0
3849 static int
3850 mailimf_trace_resent_fields_parse(const char * message, size_t length,
3851                                   size_t * index,
3852                                   struct mailimf_trace_resent_fields ** result)
3853 {
3854   size_t cur_token;
3855   struct mailimf_return * return_path;
3856   struct mailimf_resent_fields_list * resent_fields;
3857   struct mailimf_trace_resent_fields * trace_resent_fields;
3858   int res;
3859   int r;
3860
3861   cur_token = * index;
3862
3863   return_path = NULL;
3864   resent_fields = NULL;
3865
3866   r = mailimf_return_parse(message, length, &cur_token,
3867                            &return_path);
3868   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
3869     res = r;
3870     goto err;
3871   }
3872
3873   r = mailimf_resent_fields_list_parse(message, length, &cur_token,
3874                                        &resent_fields);
3875   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
3876     res = r;
3877     goto err;
3878   }
3879
3880   if ((return_path == NULL) && (resent_fields == NULL)) {
3881     res = MAILIMF_ERROR_PARSE;
3882     goto err;
3883   }
3884
3885   trace_resent_fields = mailimf_trace_resent_fields_new(return_path,
3886                                                         resent_fields);
3887   if (trace_resent_fields == NULL) {
3888     res = MAILIMF_ERROR_MEMORY;
3889     goto free_resent_fields;
3890   }
3891
3892   * result = trace_resent_fields;
3893   * index = cur_token;
3894
3895   return MAILIMF_NO_ERROR;
3896
3897  free_resent_fields:
3898   if (resent_fields != NULL)
3899     mailimf_resent_fields_list_free(resent_fields);
3900   if (return_path != NULL)
3901     mailimf_return_free(return_path);
3902  err:
3903   return res;
3904 }
3905 #endif
3906
3907 /*
3908 delivering-info =       *([trace]
3909                           [resent-fields-list])
3910 */
3911
3912 #if 0
3913 static int
3914 mailimf_delivering_info_parse(const char * message, size_t length,
3915                               size_t * index,
3916                               struct mailimf_delivering_info ** result)
3917 {
3918   size_t cur_token;
3919   clist * list;
3920   struct mailimf_delivering_info * delivering_info;
3921   int r;
3922   int res;
3923
3924   cur_token = * index;
3925
3926   r = mailimf_struct_multiple_parse(message, length, &cur_token,
3927                                     &list,
3928                                     (mailimf_struct_parser *)
3929                                     mailimf_trace_resent_fields_parse,
3930                                     (mailimf_struct_destructor *)
3931                                     mailimf_trace_resent_fields_free);
3932   if (r != MAILIMF_NO_ERROR) {
3933     res = r;
3934     goto err;
3935   }
3936
3937   delivering_info = mailimf_delivering_info_new(list);
3938   if (delivering_info == NULL) {
3939     res = MAILIMF_ERROR_MEMORY;
3940     goto free_list;
3941   }
3942
3943   * result = delivering_info;
3944   * index = cur_token;
3945
3946   return MAILIMF_NO_ERROR;
3947
3948  free_list:
3949   clist_foreach(list, (clist_func) mailimf_trace_resent_fields_free, NULL);
3950   clist_free(list);
3951  err:
3952   return res;
3953 }
3954 #endif
3955
3956 /*
3957 field           =       delivering-info /
3958                         orig-date /
3959                         from /
3960                         sender /
3961                         reply-to /
3962                         to /
3963                         cc /
3964                         bcc /
3965                         message-id /
3966                         in-reply-to /
3967                         references /
3968                         subject /
3969                         comments /
3970                         keywords /
3971                         optional-field
3972 */
3973
3974 enum {
3975   HEADER_START,
3976   HEADER_C,
3977   HEADER_R,
3978   HEADER_RE,
3979   HEADER_S,
3980   HEADER_RES,
3981 };
3982
3983 static int guess_header_type(const char * message, size_t length, size_t index)
3984 {
3985   int state;
3986   int r;
3987
3988   state = HEADER_START;
3989   
3990   while (1) {
3991
3992     if (index >= length)
3993       return MAILIMF_FIELD_NONE;
3994
3995     switch(state) {
3996     case HEADER_START:
3997       switch((char) toupper((unsigned char) message[index])) {
3998       case 'B':
3999         return MAILIMF_FIELD_BCC;
4000       case 'C':
4001         state = HEADER_C;
4002         break;
4003       case 'D':
4004         return MAILIMF_FIELD_ORIG_DATE;
4005       case 'F':
4006         return MAILIMF_FIELD_FROM;
4007       case 'I':
4008         return MAILIMF_FIELD_IN_REPLY_TO;
4009       case 'K':
4010         return MAILIMF_FIELD_KEYWORDS;
4011       case 'M':
4012         return MAILIMF_FIELD_MESSAGE_ID;
4013       case 'R':
4014         state = HEADER_R;
4015         break;
4016       case 'T':
4017         return MAILIMF_FIELD_TO;
4018         break;
4019       case 'S':
4020         state = HEADER_S;
4021         break;
4022       default:
4023         return MAILIMF_FIELD_NONE;
4024       }
4025       break;
4026     case HEADER_C:
4027       switch((char) toupper((unsigned char) message[index])) {
4028       case 'O':
4029         return MAILIMF_FIELD_COMMENTS;
4030       case 'C':
4031         return MAILIMF_FIELD_CC;
4032       default:
4033         return MAILIMF_FIELD_NONE;
4034       }
4035       break;
4036     case HEADER_R:
4037       switch((char) toupper((unsigned char) message[index])) {
4038       case 'E':
4039         state = HEADER_RE;
4040         break;
4041       default:
4042         return MAILIMF_FIELD_NONE;
4043       }
4044       break;
4045     case HEADER_RE:
4046       switch((char) toupper((unsigned char) message[index])) {
4047       case 'F':
4048         return MAILIMF_FIELD_REFERENCES;
4049       case 'P':
4050         return MAILIMF_FIELD_REPLY_TO;
4051       case 'S':
4052         state = HEADER_RES;
4053         break;
4054       case 'T':
4055         return MAILIMF_FIELD_RETURN_PATH;
4056       default:
4057         return MAILIMF_FIELD_NONE;
4058       }
4059       break;
4060     case HEADER_S:
4061       switch((char) toupper((unsigned char) message[index])) {
4062       case 'E':
4063         return MAILIMF_FIELD_SENDER;
4064       case 'U':
4065         return MAILIMF_FIELD_SUBJECT;
4066       default:
4067         return MAILIMF_FIELD_NONE;
4068       }
4069       break;
4070
4071     case HEADER_RES:
4072       r = mailimf_token_case_insensitive_parse(message,
4073           length, &index, "ent-");
4074       if (r != MAILIMF_NO_ERROR)
4075         return MAILIMF_FIELD_NONE;
4076       
4077       if (index >= length)
4078         return MAILIMF_FIELD_NONE;
4079       
4080       switch((char) toupper((unsigned char) message[index])) {
4081       case 'D':
4082         return MAILIMF_FIELD_RESENT_DATE;
4083       case 'F':
4084         return MAILIMF_FIELD_RESENT_FROM;
4085       case 'S':
4086         return MAILIMF_FIELD_RESENT_SENDER;
4087       case 'T':
4088         return MAILIMF_FIELD_RESENT_TO;
4089       case 'C':
4090         return MAILIMF_FIELD_RESENT_CC;
4091       case 'B':
4092         return MAILIMF_FIELD_RESENT_BCC;
4093       case 'M':
4094         return MAILIMF_FIELD_RESENT_MSG_ID;
4095       default:
4096         return MAILIMF_FIELD_NONE;
4097       }
4098       break;
4099     }
4100     index ++;
4101   }
4102 }
4103
4104 static int mailimf_field_parse(const char * message, size_t length,
4105                                size_t * index,
4106                                struct mailimf_field ** result)
4107 {
4108   size_t cur_token;
4109   int type;
4110   struct mailimf_return * return_path;
4111   struct mailimf_orig_date * resent_date;
4112   struct mailimf_from * resent_from;
4113   struct mailimf_sender * resent_sender;
4114   struct mailimf_to* resent_to;
4115   struct mailimf_cc * resent_cc;
4116   struct mailimf_bcc * resent_bcc;
4117   struct mailimf_message_id * resent_msg_id;
4118   struct mailimf_orig_date * orig_date;
4119   struct mailimf_from * from;
4120   struct mailimf_sender * sender;
4121   struct mailimf_reply_to * reply_to;
4122   struct mailimf_to * to;
4123   struct mailimf_cc * cc;
4124   struct mailimf_bcc * bcc;
4125   struct mailimf_message_id * message_id;
4126   struct mailimf_in_reply_to * in_reply_to;
4127   struct mailimf_references * references;
4128   struct mailimf_subject * subject;
4129   struct mailimf_comments * comments;
4130   struct mailimf_keywords * keywords;
4131   struct mailimf_optional_field * optional_field;
4132   struct mailimf_field * field;
4133   int guessed_type;
4134   int r;
4135   int res;
4136   
4137   cur_token = * index;
4138
4139   return_path = NULL;
4140   resent_date = NULL;
4141   resent_from = NULL;
4142   resent_sender = NULL;
4143   resent_to = NULL;
4144   resent_cc = NULL;
4145   resent_bcc = NULL;
4146   resent_msg_id = NULL;
4147   orig_date = NULL;
4148   from = NULL;
4149   sender = NULL;
4150   reply_to = NULL;
4151   to = NULL;
4152   cc = NULL;
4153   bcc = NULL;
4154   message_id = NULL;
4155   in_reply_to = NULL;
4156   references = NULL;
4157   subject = NULL;
4158   comments = NULL;
4159   keywords = NULL;
4160   optional_field = NULL;
4161
4162   guessed_type = guess_header_type(message, length, cur_token);
4163   type = MAILIMF_FIELD_NONE;
4164
4165   switch (guessed_type) {
4166   case MAILIMF_FIELD_ORIG_DATE:
4167     r = mailimf_orig_date_parse(message, length, &cur_token,
4168                                 &orig_date);
4169     if (r == MAILIMF_NO_ERROR)
4170       type = MAILIMF_FIELD_ORIG_DATE;
4171     else if (r == MAILIMF_ERROR_PARSE) {
4172       /* do nothing */
4173     }
4174     else {
4175       res = r;
4176       goto free_fields;
4177     }
4178     break;
4179   case MAILIMF_FIELD_FROM:
4180     r = mailimf_from_parse(message, length, &cur_token,
4181                            &from);
4182     if (r == MAILIMF_NO_ERROR)
4183       type = guessed_type;
4184     else if (r == MAILIMF_ERROR_PARSE) {
4185       /* do nothing */
4186     }
4187     else {
4188       res = r;
4189       goto free_fields;
4190     }
4191     break;
4192   case MAILIMF_FIELD_SENDER:
4193     r = mailimf_sender_parse(message, length, &cur_token,
4194                              &sender);
4195     if (r == MAILIMF_NO_ERROR)
4196       type = guessed_type;
4197     else if (r == MAILIMF_ERROR_PARSE) {
4198       /* do nothing */
4199     }
4200     else {
4201       res = r;
4202       goto free_fields;
4203     }
4204     break;
4205   case MAILIMF_FIELD_REPLY_TO:
4206     r = mailimf_reply_to_parse(message, length, &cur_token,
4207                                &reply_to);
4208     if (r == MAILIMF_NO_ERROR)
4209       type = guessed_type;
4210     else if (r == MAILIMF_ERROR_PARSE) {
4211       /* do nothing */
4212     }
4213     else {
4214       res = r;
4215       goto free_fields;
4216     }
4217     break;
4218   case MAILIMF_FIELD_TO:
4219     r = mailimf_to_parse(message, length, &cur_token,
4220                          &to);
4221     if (r == MAILIMF_NO_ERROR)
4222       type = guessed_type;
4223     else if (r == MAILIMF_ERROR_PARSE) {
4224       /* do nothing */
4225     }
4226     else {
4227       res = r;
4228       goto free_fields;
4229     }
4230     break;
4231   case MAILIMF_FIELD_CC:
4232     r = mailimf_cc_parse(message, length, &cur_token,
4233                          &cc);
4234     if (r == MAILIMF_NO_ERROR)
4235       type = guessed_type;
4236     else if (r == MAILIMF_ERROR_PARSE) {
4237       /* do nothing */
4238     }
4239     else {
4240       res = r;
4241       goto free_fields;
4242     }
4243     break;
4244   case MAILIMF_FIELD_BCC:
4245     r = mailimf_bcc_parse(message, length, &cur_token,
4246                           &bcc);
4247     if (r == MAILIMF_NO_ERROR)
4248       type = guessed_type;
4249     else if (r == MAILIMF_ERROR_PARSE) {
4250       /* do nothing */
4251     }
4252     else {
4253       res = r;
4254       goto free_fields;
4255     }
4256     break;
4257   case MAILIMF_FIELD_MESSAGE_ID:
4258     r = mailimf_message_id_parse(message, length, &cur_token,
4259                                  &message_id);
4260     if (r == MAILIMF_NO_ERROR)
4261       type = guessed_type;
4262     else if (r == MAILIMF_ERROR_PARSE) {
4263       /* do nothing */
4264     }
4265     else {
4266       res = r;
4267       goto free_fields;
4268     }
4269     break;
4270   case MAILIMF_FIELD_IN_REPLY_TO:
4271     r = mailimf_in_reply_to_parse(message, length, &cur_token,
4272                                   &in_reply_to);
4273     if (r == MAILIMF_NO_ERROR)
4274       type = guessed_type;
4275     else if (r == MAILIMF_ERROR_PARSE) {
4276       /* do nothing */
4277     }
4278     else {
4279       res = r;
4280       goto free_fields;
4281     }
4282     break;
4283   case MAILIMF_FIELD_REFERENCES:
4284     r = mailimf_references_parse(message, length, &cur_token,
4285                                  &references);
4286     if (r == MAILIMF_NO_ERROR)
4287       type = guessed_type;
4288     else if (r == MAILIMF_ERROR_PARSE) {
4289       /* do nothing */
4290     }
4291     else {
4292       res = r;
4293       goto free_fields;
4294     }
4295     break;
4296   case MAILIMF_FIELD_SUBJECT:
4297     r = mailimf_subject_parse(message, length, &cur_token,
4298                               &subject);
4299     if (r == MAILIMF_NO_ERROR)
4300       type = guessed_type;
4301     else if (r == MAILIMF_ERROR_PARSE) {
4302       /* do nothing */
4303     }
4304     else {
4305       res = r;
4306       goto free_fields;
4307     }
4308     break;
4309   case MAILIMF_FIELD_COMMENTS:
4310     r = mailimf_comments_parse(message, length, &cur_token,
4311                                &comments);
4312     if (r == MAILIMF_NO_ERROR)
4313       type = guessed_type;
4314     else if (r == MAILIMF_ERROR_PARSE) {
4315       /* do nothing */
4316     }
4317     else {
4318       res = r;
4319       goto free_fields;
4320     }
4321     break;
4322   case MAILIMF_FIELD_KEYWORDS:
4323     r = mailimf_keywords_parse(message, length, &cur_token,
4324                                &keywords);
4325     if (r == MAILIMF_NO_ERROR)
4326       type = guessed_type;
4327     else if (r == MAILIMF_ERROR_PARSE) {
4328       /* do nothing */
4329     }
4330     else {
4331       res = r;
4332       goto free_fields;
4333     }
4334     break;
4335   case MAILIMF_FIELD_RETURN_PATH:
4336     r = mailimf_return_parse(message, length, &cur_token,
4337         &return_path);
4338     if (r == MAILIMF_NO_ERROR)
4339       type = guessed_type;
4340     else if (r == MAILIMF_ERROR_PARSE) {
4341       /* do nothing */
4342     }
4343     else {
4344       res = r;
4345       goto free_fields;
4346     }
4347     break;
4348   case MAILIMF_FIELD_RESENT_DATE:
4349     r = mailimf_resent_date_parse(message, length, &cur_token,
4350                                   &resent_date);
4351     if (r == MAILIMF_NO_ERROR)
4352       type = guessed_type;
4353     else if (r == MAILIMF_ERROR_PARSE) {
4354       /* do nothing */
4355     }
4356     else {
4357       res = r;
4358       goto free_fields;
4359     }
4360     break;
4361   case MAILIMF_FIELD_RESENT_FROM:
4362     r = mailimf_resent_from_parse(message, length, &cur_token,
4363                                   &resent_from);
4364     if (r == MAILIMF_NO_ERROR)
4365       type = guessed_type;
4366     else if (r == MAILIMF_ERROR_PARSE) {
4367       /* do nothing */
4368     }
4369     else {
4370       res = r;
4371       goto free_fields;
4372     }
4373     break;
4374   case MAILIMF_FIELD_RESENT_SENDER:
4375     r = mailimf_resent_sender_parse(message, length, &cur_token,
4376                                     &resent_sender);
4377     if (r == MAILIMF_NO_ERROR)
4378       type = guessed_type;
4379     else if (r == MAILIMF_ERROR_PARSE) {
4380       /* do nothing */
4381     }
4382     else {
4383       res = r;
4384       goto free_fields;
4385     }
4386     break;
4387   case MAILIMF_FIELD_RESENT_TO:
4388     r = mailimf_resent_to_parse(message, length, &cur_token,
4389                                 &resent_to);
4390     if (r == MAILIMF_NO_ERROR)
4391       type = guessed_type;
4392     else if (r == MAILIMF_ERROR_PARSE) {
4393       /* do nothing */
4394     }
4395     else {
4396       res = r;
4397       goto free_fields;
4398     }
4399     break;
4400   case MAILIMF_FIELD_RESENT_CC:
4401     r= mailimf_resent_cc_parse(message, length, &cur_token,
4402                                &resent_cc);
4403     if (r == MAILIMF_NO_ERROR)
4404       type = guessed_type;
4405     else if (r == MAILIMF_ERROR_PARSE) {
4406       /* do nothing */
4407     }
4408     else {
4409       res = r;
4410       goto free_fields;
4411     }
4412     break;
4413   case MAILIMF_FIELD_RESENT_BCC:
4414     r = mailimf_resent_bcc_parse(message, length, &cur_token,
4415                                  &resent_bcc);
4416     if (r == MAILIMF_NO_ERROR)
4417       type = guessed_type;
4418     else if (r == MAILIMF_ERROR_PARSE) {
4419       /* do nothing */
4420     }
4421     else {
4422       res = r;
4423       goto free_fields;
4424     }
4425     break;
4426   case MAILIMF_FIELD_RESENT_MSG_ID:
4427     r = mailimf_resent_msg_id_parse(message, length, &cur_token,
4428                                     &resent_msg_id);
4429     if (r == MAILIMF_NO_ERROR)
4430       type = guessed_type;
4431     else if (r == MAILIMF_ERROR_PARSE) {
4432       /* do nothing */
4433     }
4434     else {
4435       res = r;
4436       goto free_fields;
4437     }
4438     break;
4439   }
4440
4441   if (type == MAILIMF_FIELD_NONE) {
4442     r = mailimf_optional_field_parse(message, length, &cur_token,
4443         &optional_field);
4444     if (r != MAILIMF_NO_ERROR) {
4445       res = r;
4446       goto err;
4447     }
4448
4449     type = MAILIMF_FIELD_OPTIONAL_FIELD;
4450   }
4451
4452   field = mailimf_field_new(type, return_path, resent_date,
4453       resent_from, resent_sender, resent_to, resent_cc, resent_bcc,
4454       resent_msg_id, orig_date, from, sender, reply_to, to,
4455       cc, bcc, message_id, in_reply_to, references,
4456       subject, comments, keywords, optional_field);
4457   if (field == NULL) {
4458     res = MAILIMF_ERROR_MEMORY;
4459     goto free_fields;
4460   }
4461
4462   * result = field;
4463   * index = cur_token;
4464
4465   return MAILIMF_NO_ERROR;
4466
4467  free_fields:
4468   if (return_path != NULL)
4469     mailimf_return_free(return_path);
4470   if (resent_date != NULL)
4471     mailimf_orig_date_free(resent_date);
4472   if (resent_from != NULL)
4473     mailimf_from_free(resent_from);
4474   if (resent_sender != NULL)
4475     mailimf_sender_free(resent_sender);
4476   if (resent_to != NULL)
4477     mailimf_to_free(resent_to);
4478   if (resent_cc != NULL)
4479     mailimf_cc_free(resent_cc);
4480   if (resent_bcc != NULL)
4481     mailimf_bcc_free(resent_bcc);
4482   if (resent_msg_id != NULL)
4483     mailimf_message_id_free(resent_msg_id);
4484   if (orig_date != NULL)
4485     mailimf_orig_date_free(orig_date);
4486   if (from != NULL)
4487     mailimf_from_free(from);
4488   if (sender != NULL)
4489     mailimf_sender_free(sender);
4490   if (reply_to != NULL)
4491     mailimf_reply_to_free(reply_to);
4492   if (to != NULL)
4493     mailimf_to_free(to);
4494   if (cc != NULL)
4495     mailimf_cc_free(cc);
4496   if (bcc != NULL)
4497     mailimf_bcc_free(bcc);
4498   if (message_id != NULL)
4499     mailimf_message_id_free(message_id);
4500   if (in_reply_to != NULL)
4501     mailimf_in_reply_to_free(in_reply_to);
4502   if (references != NULL)
4503     mailimf_references_free(references);
4504   if (subject != NULL)
4505     mailimf_subject_free(subject);
4506   if (comments != NULL)
4507     mailimf_comments_free(comments);
4508   if (keywords != NULL)
4509     mailimf_keywords_free(keywords);
4510   if (optional_field != NULL)
4511     mailimf_optional_field_free(optional_field);
4512  err:
4513   return res;
4514 }
4515
4516
4517 /*
4518 fields          =       *(delivering-info /
4519                         orig-date /
4520                         from /
4521                         sender /
4522                         reply-to /
4523                         to /
4524                         cc /
4525                         bcc /
4526                         message-id /
4527                         in-reply-to /
4528                         references /
4529                         subject /
4530                         comments /
4531                         keywords /
4532                         optional-field)
4533 */
4534
4535 #if 0
4536 int
4537 mailimf_unparsed_fields_parse(const char * message, size_t length,
4538                               size_t * index,
4539                               struct mailimf_unparsed_fields ** result)
4540 {
4541   size_t cur_token;
4542   clist * list;
4543   struct mailimf_unparsed_fields * fields;
4544   int r;
4545   int res;
4546
4547   cur_token = * index;
4548
4549   list = NULL;
4550
4551   r = mailimf_struct_multiple_parse(message, length, &cur_token,
4552                                     &list,
4553                                     (mailimf_struct_parser *)
4554                                     mailimf_optional_field_parse,
4555                                     (mailimf_struct_destructor *)
4556                                     mailimf_optional_field_free);
4557   /*
4558   if ((r = MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
4559     res = r;
4560     goto err;
4561   }
4562   */
4563
4564   switch (r) {
4565   case MAILIMF_NO_ERROR:
4566     /* do nothing */
4567     break;
4568
4569   case MAILIMF_ERROR_PARSE:
4570     list = clist_new();
4571     if (list == NULL) {
4572       res = MAILIMF_ERROR_MEMORY;
4573       goto err;
4574     }
4575     break;
4576
4577   default:
4578     res = r;
4579     goto err;
4580   }
4581
4582   fields = mailimf_unparsed_fields_new(list);
4583   if (fields == NULL) {
4584     res = MAILIMF_ERROR_MEMORY;
4585     goto free;
4586   }
4587
4588   * result = fields;
4589   * index = cur_token;
4590
4591   return MAILIMF_NO_ERROR;
4592
4593  free:
4594   if (list != NULL) {
4595     clist_foreach(list, (clist_func) mailimf_optional_field_free, NULL);
4596     clist_free(list);
4597   }
4598  err:
4599   return res;
4600 }
4601 #endif
4602
4603 int mailimf_fields_parse(const char * message, size_t length,
4604                          size_t * index,
4605                          struct mailimf_fields ** result)
4606 {
4607   size_t cur_token;
4608   clist * list;
4609   struct mailimf_fields * fields;
4610   int r;
4611   int res;
4612
4613   cur_token = * index;
4614
4615   list = NULL;
4616
4617   r = mailimf_struct_multiple_parse(message, length, &cur_token,
4618                                     &list,
4619                                     (mailimf_struct_parser *)
4620                                     mailimf_field_parse,
4621                                     (mailimf_struct_destructor *)
4622                                     mailimf_field_free);
4623   /*
4624   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
4625     res = r;
4626     goto err;
4627   }
4628   */
4629
4630   switch (r) {
4631   case MAILIMF_NO_ERROR:
4632     /* do nothing */
4633     break;
4634
4635   case MAILIMF_ERROR_PARSE:
4636     list = clist_new();
4637     if (list == NULL) {
4638       res = MAILIMF_ERROR_MEMORY;
4639       goto err;
4640     }
4641     break;
4642
4643   default:
4644     res = r;
4645     goto err;
4646   }
4647
4648   fields = mailimf_fields_new(list);
4649   if (fields == NULL) {
4650     res = MAILIMF_ERROR_MEMORY;
4651     goto free;
4652   }
4653
4654   * result = fields;
4655   * index = cur_token;
4656
4657   return MAILIMF_NO_ERROR;
4658
4659  free:
4660   if (list != NULL) {
4661     clist_foreach(list, (clist_func) mailimf_field_free, NULL);
4662     clist_free(list);
4663   }
4664  err:
4665   return res;
4666 }
4667
4668 /*
4669 orig-date       =       "Date:" date-time CRLF
4670 */
4671
4672
4673 static int
4674 mailimf_orig_date_parse(const char * message, size_t length,
4675                         size_t * index, struct mailimf_orig_date ** result)
4676 {
4677   struct mailimf_date_time * date_time;
4678   struct mailimf_orig_date * orig_date;
4679   size_t cur_token;
4680   int r;
4681   int res;
4682
4683   cur_token = * index;
4684
4685   r = mailimf_token_case_insensitive_parse(message, length,
4686                                            &cur_token, "Date:");
4687   if (r != MAILIMF_NO_ERROR) {
4688     res = r;
4689     goto err;
4690   }
4691
4692   r = mailimf_date_time_parse(message, length, &cur_token, &date_time);
4693   if (r != MAILIMF_NO_ERROR) {
4694     res = r;
4695     goto err;
4696   }
4697
4698   r = mailimf_ignore_unstructured_parse(message, length, &cur_token);
4699   if (r != MAILIMF_NO_ERROR) {
4700     res = r;
4701     goto free_date_time;
4702   }
4703
4704   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
4705   if (r != MAILIMF_NO_ERROR) {
4706     res = r;
4707     goto free_date_time;
4708   }
4709
4710   orig_date = mailimf_orig_date_new(date_time);
4711   if (orig_date == NULL) {
4712     res = MAILIMF_ERROR_MEMORY;
4713     goto free_date_time;
4714   }
4715
4716   * result = orig_date;
4717   * index = cur_token;
4718
4719   return MAILIMF_NO_ERROR;
4720
4721  free_date_time:
4722   mailimf_date_time_free(date_time);
4723  err:
4724   return res;
4725 }
4726
4727 /*
4728 from            =       "From:" mailbox-list CRLF
4729 */
4730
4731 static int
4732 mailimf_from_parse(const char * message, size_t length,
4733                    size_t * index, struct mailimf_from ** result)
4734 {
4735   struct mailimf_mailbox_list * mb_list;
4736   struct mailimf_from * from;
4737   size_t cur_token;
4738   int r;
4739   int res;
4740
4741   cur_token =  * index;
4742
4743   r = mailimf_token_case_insensitive_parse(message, length,
4744                                            &cur_token, "From");
4745   if (r != MAILIMF_NO_ERROR) {
4746     res = r;
4747     goto err;
4748   }
4749
4750   r = mailimf_colon_parse(message, length, &cur_token);
4751   if (r != MAILIMF_NO_ERROR) {
4752     res = r;
4753     goto err;
4754   }
4755
4756   r = mailimf_mailbox_list_parse(message, length, &cur_token, &mb_list);
4757
4758   if (r != MAILIMF_NO_ERROR) {
4759     res = r;
4760     goto err;
4761   }
4762
4763   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
4764   if (r != MAILIMF_NO_ERROR) {
4765     res = r;
4766     goto free_mb_list;
4767   }
4768
4769   from = mailimf_from_new(mb_list);
4770   if (from == NULL) {
4771     res = MAILIMF_ERROR_MEMORY;
4772     goto free_mb_list;
4773   }
4774
4775   * result = from;
4776   * index = cur_token;
4777
4778   return MAILIMF_NO_ERROR;
4779
4780  free_mb_list:
4781   mailimf_mailbox_list_free(mb_list);
4782  err:
4783   return res;
4784 }
4785
4786 /*
4787 sender          =       "Sender:" mailbox CRLF
4788 */
4789
4790 static int
4791 mailimf_sender_parse(const char * message, size_t length,
4792                      size_t * index, struct mailimf_sender ** result)
4793 {
4794   struct mailimf_mailbox * mb;
4795   struct mailimf_sender * sender;
4796   size_t cur_token;
4797   int r;
4798   int res;
4799
4800   cur_token = * index;
4801
4802   r = mailimf_token_case_insensitive_parse(message, length,
4803                                            &cur_token, "Sender");
4804   if (r != MAILIMF_NO_ERROR) {
4805     res = r;
4806     goto err;
4807   }
4808
4809   r = mailimf_colon_parse(message, length, &cur_token);
4810   if (r != MAILIMF_NO_ERROR) {
4811     res = r;
4812     goto err;
4813   }
4814
4815   r = mailimf_mailbox_parse(message, length, &cur_token, &mb);
4816   if (r != MAILIMF_NO_ERROR) {
4817     res = r;
4818     goto err;
4819   }
4820
4821   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
4822   if (r != MAILIMF_NO_ERROR) {
4823     res = r;
4824     goto free_mb;
4825   }
4826
4827   sender = mailimf_sender_new(mb);
4828   if (sender == NULL) {
4829     res = MAILIMF_ERROR_MEMORY;
4830     goto free_mb;
4831   }
4832
4833   * result = sender;
4834   * index = cur_token;
4835
4836   return MAILIMF_NO_ERROR;
4837
4838  free_mb:
4839   mailimf_mailbox_free(mb);
4840  err:
4841   return res;
4842 }
4843
4844 /*
4845 reply-to        =       "Reply-To:" address-list CRLF
4846 */
4847
4848
4849 static int
4850 mailimf_reply_to_parse(const char * message, size_t length,
4851                        size_t * index, struct mailimf_reply_to ** result)
4852 {
4853   struct mailimf_address_list * addr_list;
4854   struct mailimf_reply_to * reply_to;
4855   size_t cur_token;
4856   int r;
4857   int res;
4858
4859   cur_token = * index;
4860
4861   r = mailimf_token_case_insensitive_parse(message, length,
4862                                            &cur_token, "Reply-To");
4863   if (r != MAILIMF_NO_ERROR) {
4864     res = r;
4865     goto err;
4866   }
4867
4868   r = mailimf_colon_parse(message, length, &cur_token);
4869   if (r != MAILIMF_NO_ERROR) {
4870     res = r;
4871     goto err;
4872   }
4873
4874   r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
4875   if (r != MAILIMF_NO_ERROR) {
4876     res = r;
4877     goto err;
4878   }
4879
4880   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
4881   if (r != MAILIMF_NO_ERROR) {
4882     res = r;
4883     goto free_addr_list;
4884   }
4885
4886   reply_to = mailimf_reply_to_new(addr_list);
4887   if (reply_to == NULL) {
4888     res = MAILIMF_ERROR_MEMORY;
4889     goto free_addr_list;
4890   }
4891
4892   * result = reply_to;
4893   * index = cur_token;
4894
4895   return MAILIMF_NO_ERROR;
4896
4897  free_addr_list:
4898   mailimf_address_list_free(addr_list);
4899  err:
4900   return res;
4901 }
4902
4903 /*
4904 to              =       "To:" address-list CRLF
4905 */
4906
4907 static int
4908 mailimf_to_parse(const char * message, size_t length,
4909                  size_t * index, struct mailimf_to ** result)
4910 {
4911   struct mailimf_address_list * addr_list;
4912   struct mailimf_to * to;
4913   size_t cur_token;
4914   int r;
4915   int res;
4916
4917   cur_token = * index;
4918
4919   r = mailimf_token_case_insensitive_parse(message, length,
4920                                            &cur_token, "To");
4921   if (r != MAILIMF_NO_ERROR) {
4922     res = r;
4923     goto err;
4924   }
4925
4926   r = mailimf_colon_parse(message, length, &cur_token);
4927   if (r != MAILIMF_NO_ERROR) {
4928     res = r;
4929     goto err;
4930   }
4931
4932   r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
4933   if (r != MAILIMF_NO_ERROR) {
4934     res = r;
4935     goto err;
4936   }
4937
4938   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
4939   if (r != MAILIMF_NO_ERROR) {
4940     res = r;
4941     goto free_addr_list;
4942   }
4943
4944   to = mailimf_to_new(addr_list);
4945   if (to == NULL) {
4946     res = MAILIMF_ERROR_MEMORY;
4947     goto free_addr_list;
4948   }
4949
4950   * result = to;
4951   * index = cur_token;
4952
4953   return MAILIMF_NO_ERROR;
4954
4955  free_addr_list:
4956   mailimf_address_list_free(addr_list);
4957  err:
4958   return res;
4959 }
4960
4961 /*
4962 cc              =       "Cc:" address-list CRLF
4963 */
4964
4965
4966 static int
4967 mailimf_cc_parse(const char * message, size_t length,
4968                  size_t * index, struct mailimf_cc ** result)
4969 {
4970   struct mailimf_address_list * addr_list;
4971   struct mailimf_cc * cc;
4972   size_t cur_token;
4973   int r;
4974   int res;
4975
4976   cur_token = * index;
4977
4978   r = mailimf_token_case_insensitive_parse(message, length,
4979                                            &cur_token, "Cc");
4980   if (r != MAILIMF_NO_ERROR) {
4981     res = r;
4982     goto err;
4983   }
4984
4985   r = mailimf_colon_parse(message, length, &cur_token);
4986   if (r != MAILIMF_NO_ERROR) {
4987     res = r;
4988     goto err;
4989   }
4990
4991   r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
4992   if (r != MAILIMF_NO_ERROR) {
4993     res = r;
4994     goto err;
4995   }
4996
4997   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
4998   if (r != MAILIMF_NO_ERROR) {
4999     res = r;
5000     goto free_addr_list;
5001   }
5002
5003   cc = mailimf_cc_new(addr_list);
5004   if (cc == NULL) {
5005     res = MAILIMF_ERROR_MEMORY;
5006     goto free_addr_list;
5007   }
5008
5009   * result = cc;
5010   * index = cur_token;
5011
5012   return MAILIMF_NO_ERROR;
5013
5014  free_addr_list:
5015   mailimf_address_list_free(addr_list);
5016  err:
5017   return res;
5018 }
5019
5020 /*
5021 bcc             =       "Bcc:" (address-list / [CFWS]) CRLF
5022 */
5023
5024
5025 static int
5026 mailimf_bcc_parse(const char * message, size_t length,
5027                   size_t * index, struct mailimf_bcc ** result)
5028 {
5029   struct mailimf_address_list * addr_list;
5030   struct mailimf_bcc * bcc;
5031   size_t cur_token;
5032   int r;
5033   int res;
5034
5035   cur_token = * index;
5036   addr_list = NULL;
5037
5038   r = mailimf_token_case_insensitive_parse(message, length,
5039                                            &cur_token, "Bcc");
5040   if (r != MAILIMF_NO_ERROR) {
5041     res = r;
5042     goto err;
5043   }
5044
5045   r = mailimf_colon_parse(message, length, &cur_token);
5046   if (r != MAILIMF_NO_ERROR) {
5047     res = r;
5048     goto err;
5049   }
5050
5051   r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
5052   switch (r) {
5053   case MAILIMF_NO_ERROR:
5054     /* do nothing */
5055     break;
5056   case MAILIMF_ERROR_PARSE:
5057     r = mailimf_cfws_parse(message, length, &cur_token);
5058     if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
5059       res = r;
5060       goto err;
5061     }
5062     break;
5063   default:
5064     res = r;
5065     goto err;
5066   }
5067
5068   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5069   if (r != MAILIMF_NO_ERROR) {
5070     res = r;
5071     goto free_addr_list;
5072   }
5073
5074   bcc = mailimf_bcc_new(addr_list);
5075   if (bcc == NULL) {
5076     res = MAILIMF_ERROR_MEMORY;
5077     goto free_addr_list;
5078   }
5079
5080   * result = bcc;
5081   * index = cur_token;
5082
5083   return MAILIMF_NO_ERROR;
5084
5085  free_addr_list:
5086   mailimf_address_list_free(addr_list);
5087  err:
5088   return res;
5089 }
5090
5091 /*
5092 message-id      =       "Message-ID:" msg-id CRLF
5093 */
5094
5095 static int mailimf_message_id_parse(const char * message, size_t length,
5096                                     size_t * index,
5097                                     struct mailimf_message_id ** result)
5098 {
5099   char * value;
5100   size_t cur_token;
5101   struct mailimf_message_id * message_id;
5102   int r;
5103   int res;
5104
5105   cur_token = * index;
5106
5107   r = mailimf_token_case_insensitive_parse(message, length,
5108                                            &cur_token, "Message-ID");
5109   if (r != MAILIMF_NO_ERROR) {
5110     res = r;
5111     goto err;
5112   }
5113
5114   r = mailimf_colon_parse(message, length, &cur_token);
5115   if (r != MAILIMF_NO_ERROR) {
5116     res = r;
5117     goto err;
5118   }
5119
5120   r = mailimf_msg_id_parse(message, length, &cur_token, &value);
5121   if (r != MAILIMF_NO_ERROR) {
5122     res = r;
5123     goto err;
5124   }
5125
5126   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5127   if (r != MAILIMF_NO_ERROR) {
5128     res = r;
5129     goto free_value;
5130   }
5131
5132   message_id = mailimf_message_id_new(value);
5133   if (message_id == NULL) {
5134     res = MAILIMF_ERROR_MEMORY;
5135     goto free_value;
5136   }
5137
5138   * result = message_id;
5139   * index = cur_token;
5140
5141   return MAILIMF_NO_ERROR;
5142
5143  free_value:
5144   mailimf_msg_id_free(value);
5145  err:
5146   return res;
5147 }
5148
5149 /*
5150 in-reply-to     =       "In-Reply-To:" 1*msg-id CRLF
5151 */
5152
5153 int mailimf_msg_id_list_parse(const char * message, size_t length,
5154                               size_t * index, clist ** result)
5155 {
5156   return mailimf_struct_multiple_parse(message, length, index,
5157                                        result,
5158                                        (mailimf_struct_parser *)
5159                                        mailimf_unstrict_msg_id_parse,
5160                                        (mailimf_struct_destructor *)
5161                                        mailimf_msg_id_free);
5162 }
5163
5164 static int mailimf_in_reply_to_parse(const char * message, size_t length,
5165                                      size_t * index,
5166                                      struct mailimf_in_reply_to ** result)
5167 {
5168   struct mailimf_in_reply_to * in_reply_to;
5169   size_t cur_token;
5170   clist * msg_id_list;
5171   int res;
5172   int r;
5173
5174   cur_token = * index;
5175
5176   r = mailimf_token_case_insensitive_parse(message, length,
5177                                            &cur_token, "In-Reply-To");
5178   if (r != MAILIMF_NO_ERROR) {
5179     res = r;
5180     goto err;
5181   }
5182
5183   r = mailimf_colon_parse(message, length, &cur_token);
5184   if (r != MAILIMF_NO_ERROR) {
5185     res = r;
5186     goto err;
5187   }
5188
5189   r = mailimf_msg_id_list_parse(message, length, &cur_token, &msg_id_list);
5190   if (r != MAILIMF_NO_ERROR) {
5191     res = r;
5192     goto err;
5193   }
5194
5195   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5196   if (r != MAILIMF_NO_ERROR) {
5197     res = r;
5198     goto free_list;
5199   }
5200
5201   in_reply_to = mailimf_in_reply_to_new(msg_id_list);
5202   if (in_reply_to == NULL) {
5203     res = MAILIMF_ERROR_MEMORY;
5204     goto free_list;
5205   }
5206
5207   * result = in_reply_to;
5208   * index = cur_token;
5209
5210   return MAILIMF_NO_ERROR;
5211
5212  free_list:
5213   clist_foreach(msg_id_list, (clist_func) mailimf_msg_id_free, NULL);
5214   clist_free(msg_id_list);
5215  err:
5216   return res;
5217 }
5218
5219 /*
5220 references      =       "References:" 1*msg-id CRLF
5221 */
5222
5223 int mailimf_references_parse(const char * message, size_t length,
5224                              size_t * index,
5225                              struct mailimf_references ** result)
5226 {
5227   struct mailimf_references * references;
5228   size_t cur_token;
5229   clist * msg_id_list;
5230   int r;
5231   int res;
5232
5233   cur_token = * index;
5234
5235   r = mailimf_token_case_insensitive_parse(message, length,
5236                                            &cur_token, "References");
5237   if (r != MAILIMF_NO_ERROR) {
5238     res = r;
5239     goto err;
5240   }
5241
5242   r = mailimf_colon_parse(message, length, &cur_token);
5243   if (r != MAILIMF_NO_ERROR) {
5244     res = r;
5245     goto err;
5246   }
5247
5248   r = mailimf_msg_id_list_parse(message, length, &cur_token, &msg_id_list);
5249   if (r != MAILIMF_NO_ERROR) {
5250     res = r;
5251     goto err;
5252   }
5253
5254   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5255   if (r != MAILIMF_NO_ERROR) {
5256     res = r;
5257     goto free_list;
5258   }
5259
5260   references = mailimf_references_new(msg_id_list);
5261   if (references == NULL) {
5262     res = MAILIMF_ERROR_MEMORY;
5263     goto free_list;
5264   }
5265
5266   * result = references;
5267   * index = cur_token;
5268
5269   return MAILIMF_NO_ERROR;
5270
5271  free_list:
5272   clist_foreach(msg_id_list, (clist_func) mailimf_msg_id_free, NULL);
5273   clist_free(msg_id_list);
5274  err:
5275   return res;
5276 }
5277
5278 /*
5279 msg-id          =       [CFWS] "<" id-left "@" id-right ">" [CFWS]
5280 */
5281
5282 int mailimf_msg_id_parse(const char * message, size_t length,
5283                          size_t * index,
5284                          char ** result)
5285 {
5286   size_t cur_token;
5287 #if 0
5288   char * id_left;
5289   char * id_right;
5290 #endif
5291   char * msg_id;
5292   int r;
5293   int res;
5294
5295   cur_token = * index;
5296
5297   r = mailimf_cfws_parse(message, length, &cur_token);
5298   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
5299     return r;
5300
5301   r = mailimf_lower_parse(message, length, &cur_token);
5302   if (r != MAILIMF_NO_ERROR) {
5303     res = r;
5304     goto err;
5305   }
5306
5307   r = mailimf_addr_spec_parse(message, length, &cur_token, &msg_id);
5308   if (r != MAILIMF_NO_ERROR) {
5309     res = r;
5310     goto err;
5311   }
5312   
5313   r = mailimf_greater_parse(message, length, &cur_token);
5314   if (r != MAILIMF_NO_ERROR) {
5315     free(msg_id);
5316     res = r;
5317     goto err;
5318   }
5319
5320 #if 0
5321   r = mailimf_id_left_parse(message, length, &cur_token, &id_left);
5322   if (r != MAILIMF_NO_ERROR) {
5323     res = r;
5324     goto err;
5325   }
5326
5327   r = mailimf_at_sign_parse(message, length, &cur_token);
5328   if (r != MAILIMF_NO_ERROR) {
5329     res = r;
5330     goto free_id_left;
5331   }
5332
5333   r = mailimf_id_right_parse(message, length, &cur_token, &id_right);
5334   if (r != MAILIMF_NO_ERROR) {
5335     res = r;
5336     goto free_id_left;
5337   }
5338
5339   r = mailimf_greater_parse(message, length, &cur_token);
5340   if (r != MAILIMF_NO_ERROR) {
5341     res = r;
5342     goto free_id_right;
5343   }
5344
5345   msg_id = malloc(strlen(id_left) + strlen(id_right) + 2);
5346   if (msg_id == NULL) {
5347     res = MAILIMF_ERROR_MEMORY;
5348     goto free_id_right;
5349   }
5350   strcpy(msg_id, id_left);
5351   strcat(msg_id, "@");
5352   strcat(msg_id, id_right);
5353
5354   mailimf_id_left_free(id_left);
5355   mailimf_id_right_free(id_right);
5356 #endif
5357
5358   * result = msg_id;
5359   * index = cur_token;
5360
5361   return MAILIMF_NO_ERROR;
5362
5363 #if 0
5364  free_id_right:
5365   mailimf_id_right_free(id_right);
5366  free_id_left:
5367   mailimf_id_left_free(id_left);
5368 #endif
5369   /*
5370  free:
5371   mailimf_atom_free(msg_id);
5372   */
5373  err:
5374   return res;
5375 }
5376
5377 static int mailimf_parse_unwanted_msg_id(const char * message, size_t length,
5378                                          size_t * index)
5379 {
5380   size_t cur_token;
5381   int r;
5382   char * word;
5383   int token_parsed;
5384
5385   cur_token = * index;
5386
5387   token_parsed = TRUE;
5388   while (token_parsed) {
5389     token_parsed = FALSE;
5390     r = mailimf_word_parse(message, length, &cur_token, &word);
5391     if (r == MAILIMF_NO_ERROR) {
5392       mailimf_word_free(word);
5393       token_parsed = TRUE;
5394     }
5395     else if (r == MAILIMF_ERROR_PARSE) {
5396       /* do nothing */
5397     }
5398     else
5399       return r;
5400     r = mailimf_semi_colon_parse(message, length, &cur_token);
5401     if (r == MAILIMF_NO_ERROR)
5402       token_parsed = TRUE;
5403     else if (r == MAILIMF_ERROR_PARSE) {
5404       /* do nothing */
5405     }
5406     else
5407       return r;
5408     r = mailimf_comma_parse(message, length, &cur_token);
5409     if (r == MAILIMF_NO_ERROR)
5410       token_parsed = TRUE;
5411     else if (r == MAILIMF_ERROR_PARSE) {
5412       /* do nothing */
5413     }
5414     else
5415       return r;
5416     r = mailimf_plus_parse(message, length, &cur_token);
5417     if (r == MAILIMF_NO_ERROR)
5418       token_parsed = TRUE;
5419     else if (r == MAILIMF_ERROR_PARSE) {
5420       /* do nothing */
5421     }
5422     else
5423       return r;
5424     r = mailimf_colon_parse(message, length, &cur_token);
5425     if (r == MAILIMF_NO_ERROR)
5426       token_parsed = TRUE;
5427     else if (r == MAILIMF_ERROR_PARSE) {
5428       /* do nothing */
5429     }
5430     else
5431       return r;
5432     r = mailimf_point_parse(message, length, &cur_token);
5433     if (r == MAILIMF_NO_ERROR)
5434       token_parsed = TRUE;
5435     else if (r == MAILIMF_ERROR_PARSE) {
5436       /* do nothing */
5437     }
5438     else
5439       return r;
5440     r = mailimf_at_sign_parse(message, length, &cur_token);
5441     if (r == MAILIMF_NO_ERROR)
5442       token_parsed = TRUE;
5443     else if (r == MAILIMF_ERROR_PARSE) {
5444       /* do nothing */
5445     }
5446     else
5447       return r;
5448   }
5449
5450   return MAILIMF_NO_ERROR;
5451 }
5452
5453 static int mailimf_unstrict_msg_id_parse(const char * message, size_t length,
5454                                          size_t * index,
5455                                          char ** result)
5456 {
5457   char * msgid = NULL;
5458   size_t cur_token;
5459   int r;
5460
5461   cur_token = * index;
5462
5463   r = mailimf_cfws_parse(message, length, &cur_token);
5464   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
5465     return r;
5466
5467   r = mailimf_parse_unwanted_msg_id(message, length, &cur_token);
5468   if (r != MAILIMF_NO_ERROR)
5469     return r;
5470
5471   r = mailimf_msg_id_parse(message, length, &cur_token, &msgid);
5472   if (r != MAILIMF_NO_ERROR)
5473     return r;
5474
5475   r = mailimf_parse_unwanted_msg_id(message, length, &cur_token);
5476   if (r != MAILIMF_NO_ERROR) {
5477     free(msgid);
5478     return r;
5479   }
5480
5481   * result = msgid;
5482   * index = cur_token;
5483
5484   return MAILIMF_NO_ERROR;
5485 }
5486
5487 /*
5488 id-left         =       dot-atom-text / no-fold-quote / obs-id-left
5489 */
5490
5491 #if 0
5492 static int mailimf_id_left_parse(const char * message, size_t length,
5493                                  size_t * index, char ** result)
5494 {
5495   int r;
5496
5497   r = mailimf_dot_atom_text_parse(message, length, index, result);
5498   switch (r) {
5499   case MAILIMF_NO_ERROR:
5500     return MAILIMF_NO_ERROR;
5501   case MAILIMF_ERROR_PARSE:
5502     break;
5503   default:
5504     return r;
5505   }
5506   
5507   r = mailimf_no_fold_quote_parse(message, length, index, result);
5508   if (r != MAILIMF_NO_ERROR)
5509     return r;
5510
5511   return MAILIMF_NO_ERROR;
5512 }
5513 #endif
5514
5515 /*
5516 id-right        =       dot-atom-text / no-fold-literal / obs-id-right
5517 */
5518
5519 #if 0
5520 static int mailimf_id_right_parse(const char * message, size_t length,
5521                                   size_t * index, char ** result)
5522 {
5523   int r;
5524
5525   r = mailimf_dot_atom_text_parse(message, length, index, result);
5526   switch (r) {
5527   case MAILIMF_NO_ERROR:
5528     return MAILIMF_NO_ERROR;
5529   case MAILIMF_ERROR_PARSE:
5530     break;
5531   default:
5532     return r;
5533   }
5534
5535   r = mailimf_no_fold_literal_parse(message, length, index, result);
5536   if (r != MAILIMF_NO_ERROR)
5537     return r;
5538
5539   return MAILIMF_NO_ERROR;
5540 }
5541 #endif
5542
5543 /*
5544 no-fold-quote   =       DQUOTE *(qtext / quoted-pair) DQUOTE
5545 */
5546
5547 #if 0
5548 static int mailimf_no_fold_quote_char_parse(const char * message, size_t length,
5549                                             size_t * index, char * result)
5550 {
5551   char ch;
5552   size_t cur_token;
5553   int r;
5554
5555   cur_token = * index;
5556
5557 #if 0
5558   r = mailimf_qtext_parse(message, length, &cur_token, &ch);
5559 #endif
5560
5561   if (cur_token >= length)
5562     return MAILIMF_ERROR_PARSE;
5563
5564   if (is_qtext(message[cur_token])) {
5565     ch = message[cur_token];
5566     cur_token ++;
5567   }
5568   else {
5569     r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
5570     
5571     if (r != MAILIMF_NO_ERROR)
5572       return r;
5573   }
5574
5575   * index = cur_token;
5576   * result = ch;
5577
5578   return MAILIMF_NO_ERROR;
5579 }
5580 #endif
5581
5582 #if 0
5583 static int mailimf_no_fold_quote_parse(const char * message, size_t length,
5584                                        size_t * index, char ** result)
5585 {
5586   size_t cur_token;
5587   size_t begin;
5588   char ch;
5589   char * no_fold_quote;
5590   int r;
5591   int res;
5592
5593   begin = cur_token;
5594   r = mailimf_dquote_parse(message, length, &cur_token);
5595   if (r != MAILIMF_NO_ERROR) {
5596     res = r;
5597     goto err;
5598   }
5599
5600   while (1) {
5601     r = mailimf_no_fold_quote_char_parse(message, length, &cur_token, &ch);
5602     if (r == MAILIMF_NO_ERROR) {
5603       /* do nothing */
5604     }
5605     else if (r == MAILIMF_ERROR_PARSE)
5606       break;
5607     else {
5608       res = r;
5609       goto err;
5610     }
5611   }
5612
5613   r = mailimf_dquote_parse(message, length, &cur_token);
5614   if (r != MAILIMF_NO_ERROR) {
5615     res = r;
5616     goto err;
5617   }
5618
5619   /*  no_fold_quote = strndup(message + begin, cur_token - begin); */
5620   no_fold_quote = malloc(cur_token - begin + 1);
5621   if (no_fold_quote == NULL) {
5622     res = MAILIMF_ERROR_MEMORY;
5623     goto err;
5624   }
5625   strncpy(no_fold_quote, message + begin, cur_token - begin);
5626   no_fold_quote[cur_token - begin] = '\0';
5627
5628   * result = no_fold_quote;
5629   * index = cur_token;
5630
5631   return MAILIMF_NO_ERROR;
5632
5633  err:
5634   return res;
5635 }
5636 #endif
5637
5638 /*
5639 no-fold-literal =       "[" *(dtext / quoted-pair) "]"
5640 */
5641
5642 #if 0
5643 static inline int
5644 mailimf_no_fold_literal_char_parse(const char * message, size_t length,
5645                                    size_t * index, char * result)
5646 {
5647   char ch;
5648   size_t cur_token;
5649   int r;
5650
5651   cur_token = * index;
5652
5653 #if 0
5654   r = mailimf_dtext_parse(message, length, &cur_token, &ch);
5655 #endif
5656   if (cur_token >= length)
5657     return MAILIMF_ERROR_PARSE;
5658
5659   if (is_dtext(message[cur_token])) {
5660     ch = message[cur_token];
5661     cur_token ++;
5662   }
5663   else {
5664     r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
5665     
5666     if (r != MAILIMF_NO_ERROR)
5667       return r;
5668   }
5669
5670   * index = cur_token;
5671   * result = ch;
5672
5673   return MAILIMF_NO_ERROR;
5674 }
5675 #endif
5676
5677 #if 0
5678 static int mailimf_no_fold_literal_parse(const char * message, size_t length,
5679                                          size_t * index, char ** result)
5680 {
5681   size_t cur_token;
5682   size_t begin;
5683   char ch;
5684   char * no_fold_literal;
5685   int r;
5686   int res;
5687
5688   begin = cur_token;
5689   r = mailimf_obracket_parse(message, length, &cur_token);
5690   if (r != MAILIMF_NO_ERROR) {
5691     res = r;
5692     goto err;
5693   }
5694
5695   while (1) {
5696     r = mailimf_no_fold_literal_char_parse(message, length,
5697                                            &cur_token, &ch);
5698     if (r == MAILIMF_NO_ERROR) {
5699       /* do nothing */
5700     }
5701     else if (r == MAILIMF_ERROR_PARSE)
5702       break;
5703     else {
5704       res = r;
5705       goto err;
5706     }
5707   }
5708
5709   r = mailimf_cbracket_parse(message, length, &cur_token);
5710   if (r != MAILIMF_NO_ERROR) {
5711     res = r;
5712     goto err;
5713   }
5714
5715   /*
5716   no_fold_literal = strndup(message + begin, cur_token - begin);
5717   */
5718   no_fold_literal = malloc(cur_token - begin + 1);
5719   if (no_fold_literal == NULL) {
5720     res = MAILIMF_NO_ERROR;
5721     goto err;
5722   }
5723   strncpy(no_fold_literal, message + begin, cur_token - begin);
5724   no_fold_literal[cur_token - begin] = '\0';
5725
5726   * result = no_fold_literal;
5727   * index = cur_token;
5728
5729   return MAILIMF_NO_ERROR;
5730
5731  err:
5732   return res;
5733 }
5734 #endif
5735
5736 /*
5737 subject         =       "Subject:" unstructured CRLF
5738 */
5739
5740 static int mailimf_subject_parse(const char * message, size_t length,
5741                                  size_t * index,
5742                                  struct mailimf_subject ** result)
5743 {
5744   struct mailimf_subject * subject;
5745   char * value;
5746   size_t cur_token;
5747   int r;
5748   int res;
5749
5750   cur_token = * index;
5751
5752   r = mailimf_token_case_insensitive_parse(message, length,
5753                                            &cur_token, "Subject");
5754   if (r != MAILIMF_NO_ERROR) {
5755     res = r;
5756     goto err;
5757   }
5758
5759   r = mailimf_colon_parse(message, length, &cur_token);
5760   if (r != MAILIMF_NO_ERROR) {
5761     res = r;
5762     goto err;
5763   }
5764   
5765   r = mailimf_unstructured_parse(message, length, &cur_token, &value);
5766   if (r != MAILIMF_NO_ERROR) {
5767     res = r;
5768     goto err;
5769   }
5770
5771   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5772   if (r != MAILIMF_NO_ERROR) {
5773     res = r;
5774     goto free_value;
5775   }
5776   
5777   subject = mailimf_subject_new(value);
5778   if (subject == NULL) {
5779     res = MAILIMF_ERROR_MEMORY;
5780     goto free_value;
5781   }
5782
5783   * result = subject;
5784   * index = cur_token;
5785
5786   return MAILIMF_NO_ERROR;
5787
5788  free_value:
5789   mailimf_unstructured_free(value);
5790  err:
5791   return res;
5792 }
5793
5794 /*
5795 comments        =       "Comments:" unstructured CRLF
5796 */
5797
5798 static int mailimf_comments_parse(const char * message, size_t length,
5799                                   size_t * index,
5800                                   struct mailimf_comments ** result)
5801 {
5802   struct mailimf_comments * comments;
5803   char * value;
5804   size_t cur_token;
5805   int r;
5806   int res;
5807
5808   cur_token = * index;
5809
5810   r = mailimf_token_case_insensitive_parse(message, length,
5811                                            &cur_token, "Comments");
5812   if (r != MAILIMF_NO_ERROR) {
5813     res = r;
5814     goto err;
5815   }
5816
5817   r = mailimf_colon_parse(message, length, &cur_token);
5818   if (r != MAILIMF_NO_ERROR) {
5819     res = r;
5820     goto err;
5821   }
5822   
5823   r = mailimf_unstructured_parse(message, length, &cur_token, &value);
5824   if (r != MAILIMF_NO_ERROR) {
5825     res = r;
5826     goto err;
5827   }
5828
5829   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5830   if (r != MAILIMF_NO_ERROR) {
5831     res = r;
5832     goto free_value;
5833   }
5834   
5835   comments = mailimf_comments_new(value);
5836   if (comments == NULL) {
5837     res = MAILIMF_ERROR_MEMORY;
5838     goto free_value;
5839   }
5840
5841   * result = comments;
5842   * index = cur_token;
5843
5844   return MAILIMF_NO_ERROR;
5845
5846  free_value:
5847   mailimf_unstructured_free(value);
5848  err:
5849   return res;
5850 }
5851
5852 /*
5853 keywords        =       "Keywords:" phrase *("," phrase) CRLF
5854 */
5855
5856 static int mailimf_keywords_parse(const char * message, size_t length,
5857                                   size_t * index,
5858                                   struct mailimf_keywords ** result)
5859 {
5860   struct mailimf_keywords * keywords;
5861   clist * list;
5862   size_t cur_token;
5863   int r;
5864   int res;
5865
5866   cur_token = * index;
5867
5868   r = mailimf_token_case_insensitive_parse(message, length,
5869                                            &cur_token, "Keywords");
5870   if (r != MAILIMF_NO_ERROR) {
5871     res = r;
5872     goto err;
5873   }
5874
5875   r = mailimf_colon_parse(message, length, &cur_token);
5876   if (r != MAILIMF_NO_ERROR) {
5877     res = r;
5878     goto err;
5879   }
5880   
5881   r = mailimf_struct_list_parse(message, length, &cur_token,
5882                                 &list, ',',
5883                                 (mailimf_struct_parser *)
5884                                 mailimf_phrase_parse,
5885                                 (mailimf_struct_destructor *)
5886                                 mailimf_phrase_free);
5887   if (r != MAILIMF_NO_ERROR) {
5888     res = r;
5889     goto err;
5890   }
5891
5892   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5893   if (r != MAILIMF_NO_ERROR) {
5894     res = r;
5895     goto free_list;
5896   }
5897   
5898   keywords = mailimf_keywords_new(list);
5899   if (keywords == NULL) {
5900     res = MAILIMF_ERROR_MEMORY;
5901     goto free_list;
5902   }
5903
5904   * result = keywords;
5905   * index = cur_token;
5906
5907   return MAILIMF_NO_ERROR;
5908
5909  free_list:
5910   clist_foreach(list, (clist_func) mailimf_phrase_free, NULL);
5911   clist_free(list);
5912  err:
5913   return res;
5914 }
5915
5916 /*
5917 resent-date     =       "Resent-Date:" date-time CRLF
5918 */
5919
5920 static int
5921 mailimf_resent_date_parse(const char * message, size_t length,
5922                           size_t * index, struct mailimf_orig_date ** result)
5923 {
5924   struct mailimf_orig_date * orig_date;
5925   struct mailimf_date_time * date_time;
5926   size_t cur_token;
5927   int r;
5928   int res;
5929
5930   cur_token = * index;
5931
5932   r = mailimf_token_case_insensitive_parse(message, length,
5933                                            &cur_token, "Resent-Date");
5934   if (r != MAILIMF_NO_ERROR) {
5935     res = r;
5936     goto err;
5937   }
5938
5939   r = mailimf_colon_parse(message, length, &cur_token);
5940   if (r != MAILIMF_NO_ERROR) {
5941     res = r;
5942     goto err;
5943   }
5944
5945   r = mailimf_date_time_parse(message, length, &cur_token, &date_time);
5946   if (r != MAILIMF_NO_ERROR) {
5947     res = r;
5948     goto err;
5949   }
5950
5951   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
5952   if (r != MAILIMF_NO_ERROR) {
5953     res = r;
5954     goto free_date_time;
5955   }
5956
5957   orig_date = mailimf_orig_date_new(date_time);
5958   if (orig_date == NULL) {
5959     res = MAILIMF_ERROR_MEMORY;
5960     goto free_date_time;
5961   }
5962
5963   * result = orig_date;
5964   * index = cur_token;
5965
5966   return MAILIMF_NO_ERROR;
5967
5968  free_date_time:
5969   mailimf_date_time_free(date_time);
5970  err:
5971   return res;
5972 }
5973
5974 /*
5975 resent-from     =       "Resent-From:" mailbox-list CRLF
5976 */
5977
5978 static int
5979 mailimf_resent_from_parse(const char * message, size_t length,
5980                           size_t * index, struct mailimf_from ** result)
5981 {
5982   struct mailimf_mailbox_list * mb_list;
5983   struct mailimf_from * from;
5984   size_t cur_token;
5985   int r;
5986   int res;
5987
5988   cur_token =  * index;
5989
5990   r = mailimf_token_case_insensitive_parse(message, length,
5991                                            &cur_token, "Resent-From");
5992   if (r != MAILIMF_NO_ERROR) {
5993     res = r;
5994     goto err;
5995   }
5996
5997   r = mailimf_colon_parse(message, length, &cur_token);
5998   if (r != MAILIMF_NO_ERROR) {
5999     res = r;
6000     goto err;
6001   }
6002
6003   r = mailimf_mailbox_list_parse(message, length, &cur_token, &mb_list);
6004   if (r != MAILIMF_NO_ERROR) {
6005     res = r;
6006     goto err;
6007   }
6008
6009   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6010   if (r != MAILIMF_NO_ERROR) {
6011     res = r;
6012     goto free_mb_list;
6013   }
6014
6015   from = mailimf_from_new(mb_list);
6016   if (from == NULL) {
6017     res = MAILIMF_ERROR_MEMORY;
6018     goto free_mb_list;
6019   }
6020
6021   * result = from;
6022   * index = cur_token;
6023
6024   return MAILIMF_NO_ERROR;
6025
6026  free_mb_list:
6027   mailimf_mailbox_list_free(mb_list);
6028  err:
6029   return res;
6030 }
6031
6032 /*
6033 resent-sender   =       "Resent-Sender:" mailbox CRLF
6034 */
6035
6036 static int
6037 mailimf_resent_sender_parse(const char * message, size_t length,
6038                             size_t * index, struct mailimf_sender ** result)
6039 {
6040   struct mailimf_mailbox * mb;
6041   struct mailimf_sender * sender;
6042   size_t cur_token;
6043   int r;
6044   int res;
6045
6046   cur_token = length;
6047
6048   r = mailimf_token_case_insensitive_parse(message, length,
6049                                            &cur_token, "Resent-Sender");
6050   if (r != MAILIMF_NO_ERROR) {
6051     res = r;
6052     goto err;
6053   }
6054
6055   r = mailimf_colon_parse(message, length, &cur_token);
6056   if (r != MAILIMF_NO_ERROR) {
6057     res = r;
6058     goto err;
6059   }
6060
6061   r = mailimf_mailbox_parse(message, length, &cur_token, &mb);
6062   if (r != MAILIMF_NO_ERROR) {
6063     res = r;
6064     goto err;
6065   }
6066
6067   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6068   if (r != MAILIMF_NO_ERROR) {
6069     res = r;
6070     goto free_mb;
6071   }
6072
6073   sender = mailimf_sender_new(mb);
6074   if (sender == NULL) {
6075     res = MAILIMF_ERROR_MEMORY;
6076     goto free_mb;
6077   }
6078
6079   * result = sender;
6080   * index = cur_token;
6081
6082   return MAILIMF_NO_ERROR;
6083
6084  free_mb:
6085   mailimf_mailbox_free(mb);
6086  err:
6087   return res;
6088 }
6089
6090 /*
6091 resent-to       =       "Resent-To:" address-list CRLF
6092 */
6093
6094 static int
6095 mailimf_resent_to_parse(const char * message, size_t length,
6096                         size_t * index, struct mailimf_to ** result)
6097 {
6098   struct mailimf_address_list * addr_list;
6099   struct mailimf_to * to;
6100   size_t cur_token;
6101   int r;
6102   int res;
6103
6104   cur_token = * index;
6105
6106   r = mailimf_token_case_insensitive_parse(message, length,
6107                                            &cur_token, "Resent-To");
6108   if (r != MAILIMF_NO_ERROR) {
6109     res = r;
6110     goto err;
6111   }
6112
6113   r = mailimf_colon_parse(message, length, &cur_token);
6114   if (r != MAILIMF_NO_ERROR) {
6115     res = r;
6116     goto err;
6117   }
6118
6119   r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
6120   if (r != MAILIMF_NO_ERROR) {
6121     res = r;
6122     goto err;
6123   }
6124
6125   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6126   if (r != MAILIMF_NO_ERROR) {
6127     res = r;
6128     goto free_addr_list;
6129   }
6130
6131   to = mailimf_to_new(addr_list);
6132   if (to == NULL) {
6133     res = MAILIMF_ERROR_MEMORY;
6134     goto free_addr_list;
6135   }
6136
6137   * result = to;
6138   * index = cur_token;
6139
6140   return MAILIMF_NO_ERROR;
6141
6142  free_addr_list:
6143   mailimf_address_list_free(addr_list);
6144  err:
6145   return res;
6146 }
6147
6148 /*
6149 resent-cc       =       "Resent-Cc:" address-list CRLF
6150 */
6151
6152 static int
6153 mailimf_resent_cc_parse(const char * message, size_t length,
6154                         size_t * index, struct mailimf_cc ** result)
6155 {
6156   struct mailimf_address_list * addr_list;
6157   struct mailimf_cc * cc;
6158   size_t cur_token;
6159   int r;
6160   int res;
6161
6162   cur_token = * index;
6163
6164   r = mailimf_token_case_insensitive_parse(message, length,
6165                                            &cur_token, "Resent-Cc");
6166   if (r != MAILIMF_NO_ERROR) {
6167     res = r;
6168     goto err;
6169   }
6170
6171   r = mailimf_colon_parse(message, length, &cur_token);
6172   if (r != MAILIMF_NO_ERROR) {
6173     res = r;
6174     goto err;
6175   }
6176
6177   r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
6178   if (r != MAILIMF_NO_ERROR) {
6179     res = r;
6180     goto err;
6181   }
6182
6183   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6184   if (r != MAILIMF_NO_ERROR) {
6185     res = r;
6186     goto free_addr_list;
6187   }
6188
6189   cc = mailimf_cc_new(addr_list);
6190   if (cc == NULL) {
6191     res = MAILIMF_ERROR_MEMORY;
6192     goto free_addr_list;
6193   }
6194
6195   * result = cc;
6196   * index = cur_token;
6197
6198   return MAILIMF_NO_ERROR;
6199
6200  free_addr_list:
6201   mailimf_address_list_free(addr_list);
6202  err:
6203   return res;
6204 }
6205
6206 /*
6207 resent-bcc      =       "Resent-Bcc:" (address-list / [CFWS]) CRLF
6208 */
6209
6210 static int
6211 mailimf_resent_bcc_parse(const char * message, size_t length,
6212                          size_t * index, struct mailimf_bcc ** result)
6213 {
6214   struct mailimf_address_list * addr_list;
6215   struct mailimf_bcc * bcc;
6216   size_t cur_token;
6217   int r;
6218   int res;
6219
6220   cur_token = * index;
6221   bcc = NULL;
6222
6223   r = mailimf_token_case_insensitive_parse(message, length,
6224                                            &cur_token, "Resent-Bcc");
6225   if (r != MAILIMF_NO_ERROR) {
6226     res = r;
6227     goto err;
6228   }
6229
6230   r = mailimf_colon_parse(message, length, &cur_token);
6231   if (r != MAILIMF_NO_ERROR) {
6232     res = r;
6233     goto err;
6234   }
6235
6236   r = mailimf_address_list_parse(message, length, &cur_token, &addr_list);
6237   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
6238     res = r;
6239     goto err;
6240   }
6241
6242   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6243   if (r != MAILIMF_NO_ERROR) {
6244     res = r;
6245     goto free_addr_list;
6246   }
6247
6248   bcc = mailimf_bcc_new(addr_list);
6249   if (bcc == NULL) {
6250     res = MAILIMF_ERROR_MEMORY;
6251     goto free_addr_list;
6252   }
6253
6254   * result = bcc;
6255   * index = cur_token;
6256
6257   return TRUE;
6258
6259  free_addr_list:
6260   mailimf_address_list_free(addr_list);
6261  err:
6262   return res;
6263 }
6264
6265 /*
6266 resent-msg-id   =       "Resent-Message-ID:" msg-id CRLF
6267 */
6268
6269 static int
6270 mailimf_resent_msg_id_parse(const char * message, size_t length,
6271                             size_t * index,
6272                             struct mailimf_message_id ** result)
6273 {
6274   char * value;
6275   size_t cur_token;
6276   struct mailimf_message_id * message_id;
6277   int r;
6278   int res;
6279
6280   cur_token = * index;
6281
6282   r = mailimf_token_case_insensitive_parse(message, length,
6283                                            &cur_token, "Resent-Message-ID");
6284   if (r != MAILIMF_NO_ERROR) {
6285     res = r;
6286     goto err;
6287   }
6288
6289   r = mailimf_colon_parse(message, length, &cur_token);
6290   if (r != MAILIMF_NO_ERROR) {
6291     res = r;
6292     goto err;
6293   }
6294
6295   r = mailimf_msg_id_parse(message, length, &cur_token, &value);
6296   if (r != MAILIMF_NO_ERROR) {
6297     res = r;
6298     goto err;
6299   }
6300
6301   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6302   if (r != MAILIMF_NO_ERROR) {
6303     res = r;
6304     goto free_value;
6305   }
6306
6307   message_id = mailimf_message_id_new(value);
6308   if (message_id == NULL) {
6309     res = MAILIMF_ERROR_MEMORY;
6310     goto free_value;
6311   }
6312
6313   * result = message_id;
6314   * index = cur_token;
6315
6316   return MAILIMF_NO_ERROR;
6317
6318  free_value:
6319   mailimf_msg_id_free(value);
6320  err:
6321   return res;
6322 }
6323
6324 /*
6325 trace           =       [return]
6326                         1*received
6327 */
6328
6329 #if 0
6330 static int mailimf_trace_parse(const char * message, size_t length,
6331                                size_t * index,
6332                                struct mailimf_trace ** result)
6333 {
6334   size_t cur_token;
6335   struct mailimf_return * return_path;
6336   clist * received_list;
6337   struct mailimf_trace * trace;
6338   int r;
6339   int res;
6340
6341   cur_token = * index;
6342   return_path = NULL;
6343   received_list = NULL;
6344
6345   r = mailimf_return_parse(message, length, &cur_token, &return_path);
6346   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
6347     res = r;
6348     goto err;
6349   }
6350
6351   r = mailimf_struct_multiple_parse(message, length, &cur_token,
6352                                     &received_list,
6353                                     (mailimf_struct_parser *)
6354                                     mailimf_received_parse,
6355                                     (mailimf_struct_destructor *)
6356                                     mailimf_received_free);
6357   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
6358     res = r;
6359     goto err;
6360   }
6361
6362   if ((received_list == NULL) && (return_path == NULL)) {
6363     res = MAILIMF_ERROR_PARSE;
6364     goto free_return;
6365   }
6366
6367   trace = mailimf_trace_new(return_path, received_list);
6368   if (trace == NULL) {
6369     res = MAILIMF_ERROR_MEMORY;
6370     goto free_list;
6371   }
6372
6373   * result = trace;
6374   * index = cur_token;
6375
6376   return MAILIMF_NO_ERROR;
6377
6378  free_list:
6379   clist_foreach(received_list, (clist_func) mailimf_received_free, NULL);
6380   clist_free(received_list);
6381  free_return:
6382   if (return_path != NULL)
6383     mailimf_return_free(return_path);
6384  err:
6385   return res;
6386 }
6387 #endif
6388
6389 /*
6390 return          =       "Return-Path:" path CRLF
6391 */
6392
6393 static int mailimf_return_parse(const char * message, size_t length,
6394                                 size_t * index,
6395                                 struct mailimf_return ** result)
6396 {
6397   struct mailimf_path * path = NULL;
6398   struct mailimf_return * return_path;
6399   size_t cur_token;
6400   int r;
6401   int res;
6402
6403   cur_token = * index;
6404
6405   r = mailimf_token_case_insensitive_parse(message, length,
6406                                            &cur_token, "Return-Path");
6407   if (r != MAILIMF_NO_ERROR) {
6408     res = r;
6409     goto err;
6410   }
6411
6412   r = mailimf_colon_parse(message, length, &cur_token);
6413   if (r != MAILIMF_NO_ERROR) {
6414     res = r;
6415     goto err;
6416   }
6417
6418   r = mailimf_path_parse(message, length, &cur_token, &path);
6419   if ( r!= MAILIMF_NO_ERROR) {
6420     res = r;
6421     goto err;
6422   }
6423
6424   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6425   if (r != MAILIMF_NO_ERROR) {
6426     res = r;
6427     goto free_path;
6428   }
6429
6430   return_path = mailimf_return_new(path);
6431   if (return_path == NULL) {
6432     res = MAILIMF_ERROR_MEMORY;
6433     goto free_path;
6434   }
6435
6436   * result = return_path;
6437   * index = cur_token;
6438
6439   return MAILIMF_NO_ERROR;
6440
6441  free_path:
6442   mailimf_path_free(path);
6443  err:
6444   return res;
6445 }
6446
6447 /*
6448 path            =       ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) /
6449                         obs-path
6450 */
6451
6452 static int mailimf_path_parse(const char * message, size_t length,
6453                               size_t * index, struct mailimf_path ** result)
6454 {
6455   size_t cur_token;
6456   char * addr_spec;
6457   struct mailimf_path * path;
6458   int res;
6459   int r;
6460
6461   cur_token = * index;
6462   addr_spec = NULL;
6463
6464   r = mailimf_cfws_parse(message, length, &cur_token);
6465   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
6466     res = r;
6467     goto err;
6468   }
6469
6470   r = mailimf_lower_parse(message, length, &cur_token);
6471   if (r != MAILIMF_NO_ERROR) {
6472     res = r;
6473     goto err;
6474   }
6475
6476   r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec);
6477   switch (r) {
6478   case MAILIMF_NO_ERROR:
6479     break;
6480   case MAILIMF_ERROR_PARSE:
6481     r = mailimf_cfws_parse(message, length, &cur_token);
6482     if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
6483       res = r;
6484       goto err;
6485     }
6486     break;
6487   default:
6488     return r;
6489   }
6490   
6491   r = mailimf_greater_parse(message, length, &cur_token);
6492   if (r != MAILIMF_NO_ERROR) {
6493     res = r;
6494     goto free_addr_spec;
6495   }
6496
6497   path = mailimf_path_new(addr_spec);
6498   if (path == NULL) {
6499     res = MAILIMF_ERROR_MEMORY;
6500     goto free_addr_spec;
6501   }
6502
6503   * index = cur_token;
6504   * result = path;
6505
6506   return MAILIMF_NO_ERROR;
6507
6508  free_addr_spec:
6509   if (addr_spec != NULL)
6510     mailimf_addr_spec_free(addr_spec);
6511  err:
6512   return res;
6513 }
6514
6515 /*
6516 received        =       "Received:" name-val-list ";" date-time CRLF
6517 */
6518
6519 #if 0
6520 static int mailimf_received_parse(const char * message, size_t length,
6521                                   size_t * index,
6522                                   struct mailimf_received ** result)
6523 {
6524   size_t cur_token;
6525   struct mailimf_received * received;
6526   struct mailimf_name_val_list * name_val_list;
6527   struct mailimf_date_time * date_time;
6528   int r;
6529   int res;
6530
6531   cur_token = * index;
6532
6533   r = mailimf_token_case_insensitive_parse(message, length,
6534                                            &cur_token, "Received");
6535   if (r != MAILIMF_NO_ERROR) {
6536     res = r;
6537     goto err;
6538   }
6539   
6540   r = mailimf_colon_parse(message, length, &cur_token);
6541   if (r != MAILIMF_NO_ERROR) {
6542     res = r;
6543     goto err;
6544   }
6545
6546   r = mailimf_name_val_list_parse(message, length,
6547                                   &cur_token, &name_val_list);
6548   if (r != MAILIMF_NO_ERROR) {
6549     res = r;
6550     goto err;
6551   }
6552
6553   r = mailimf_semi_colon_parse(message, length, &cur_token);
6554   if (r != MAILIMF_NO_ERROR) {
6555     res = r;
6556     goto free_name_val_list;
6557   }
6558
6559   r = mailimf_date_time_parse(message, length, &cur_token, &date_time);
6560   if (r != MAILIMF_NO_ERROR) {
6561     res = r;
6562     goto free_name_val_list;
6563   }
6564
6565   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6566   if (r != MAILIMF_NO_ERROR) {
6567     res = r;
6568     goto free_date_time;
6569   }
6570
6571   received = mailimf_received_new(name_val_list, date_time);
6572   if (received == NULL) {
6573     res = MAILIMF_ERROR_MEMORY;
6574     goto free_date_time;
6575   }
6576
6577   * index = cur_token;
6578   * result = received;
6579
6580   return MAILIMF_NO_ERROR;
6581
6582  free_date_time:
6583   mailimf_date_time_free(date_time);
6584  free_name_val_list:
6585   mailimf_name_val_list_free(name_val_list);
6586  err:
6587   return res;
6588 }
6589 #endif
6590
6591 /*
6592 name-val-list   =       [CFWS] [name-val-pair *(CFWS name-val-pair)]
6593 */
6594
6595 #if 0
6596 static int
6597 mailimf_name_val_list_parse(const char * message, size_t length,
6598                             size_t * index,
6599                             struct mailimf_name_val_list ** result)
6600 {
6601   size_t cur_token;
6602   struct mailimf_name_val_pair * pair;
6603   struct mailimf_name_val_list * name_val_list;
6604   clist* list;
6605   int res;
6606   int r;
6607
6608   cur_token = * index;
6609   list = NULL;
6610
6611   r = mailimf_name_val_pair_parse(message, length, &cur_token, &pair);
6612
6613   if (r == MAILIMF_NO_ERROR){
6614     size_t final_token;
6615
6616     list = clist_new();
6617     if (list == NULL) {
6618       mailimf_name_val_pair_free(pair);
6619       res = MAILIMF_ERROR_MEMORY;
6620       goto err;
6621     }
6622
6623     r = clist_append(list, pair);
6624     if (r < 0) {
6625       mailimf_name_val_pair_free(pair);
6626       res = MAILIMF_ERROR_MEMORY;
6627       goto free_list;
6628     }
6629
6630     final_token = cur_token;
6631     
6632     while (1) {
6633       r = mailimf_cfws_parse(message, length, &cur_token);
6634       if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
6635         res = r;
6636         goto free_list;
6637       }
6638
6639       r = mailimf_name_val_pair_parse(message, length, &cur_token, &pair);
6640       if (r == MAILIMF_NO_ERROR) {
6641         /* do nothing */
6642       }
6643       else if (r == MAILIMF_ERROR_PARSE)
6644         break;
6645       else {
6646         res = r;
6647         goto free_list;
6648       }
6649
6650       r = clist_append(list, pair);
6651       if (r < 0) {
6652         mailimf_name_val_pair_free(pair);
6653         res = MAILIMF_ERROR_MEMORY;
6654         goto free_list;
6655       }
6656
6657       final_token = cur_token;
6658     }
6659     cur_token = final_token;
6660   }
6661
6662   name_val_list = mailimf_name_val_list_new(list);
6663   if (name_val_list == NULL) {
6664     res = MAILIMF_ERROR_MEMORY;
6665     goto free_list;
6666   }
6667
6668   * index = cur_token;
6669   * result = name_val_list;
6670
6671   return MAILIMF_NO_ERROR;
6672
6673  free_list:
6674   if (list != NULL) {
6675     clist_foreach(list, (clist_func) mailimf_name_val_pair_free, NULL);
6676     clist_free(list);
6677   }
6678  err:
6679   return res;
6680 }
6681 #endif
6682
6683 /*
6684 name-val-pair   =       item-name CFWS item-value
6685 */
6686
6687 #if 0
6688 static int
6689 mailimf_name_val_pair_parse(const char * message, size_t length,
6690                             size_t * index,
6691                             struct mailimf_name_val_pair ** result)
6692 {
6693   size_t cur_token;
6694   char * item_name;
6695   struct mailimf_item_value * item_value;
6696   struct mailimf_name_val_pair * name_val_pair;
6697   int r;
6698   int res;
6699
6700   cur_token = * index;
6701
6702   r = mailimf_cfws_parse(message, length, &cur_token);
6703   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
6704     res = r;
6705     goto err;
6706   }
6707   
6708   r = mailimf_item_name_parse(message, length, &cur_token, &item_name);
6709   if (r != MAILIMF_NO_ERROR) {
6710     res = r;
6711     goto err;
6712   }
6713
6714   r = mailimf_cfws_parse(message, length, &cur_token);
6715   if (r != MAILIMF_NO_ERROR) {
6716     res = r;
6717     goto free_item_name;
6718   }
6719
6720   r = mailimf_item_value_parse(message, length, &cur_token, &item_value);
6721   if (r != MAILIMF_NO_ERROR) {
6722     res = r;
6723     goto free_item_name;
6724   }
6725
6726   name_val_pair = mailimf_name_val_pair_new(item_name, item_value);
6727   if (name_val_pair == NULL) {
6728     res = MAILIMF_ERROR_MEMORY;
6729     goto free_item_value;
6730   }
6731
6732   * result = name_val_pair;
6733   * index = cur_token;
6734
6735   return MAILIMF_NO_ERROR;
6736
6737  free_item_value:
6738   mailimf_item_value_free(item_value);
6739  free_item_name:
6740   mailimf_item_name_free(item_name);
6741  err:
6742   return res;
6743 }
6744 #endif
6745
6746 /*
6747 item-name       =       ALPHA *(["-"] (ALPHA / DIGIT))
6748 */
6749
6750 #if 0
6751 static int mailimf_item_name_parse(const char * message, size_t length,
6752                                    size_t * index, char ** result)
6753 {
6754   size_t cur_token;
6755   size_t begin;
6756   char * item_name;
6757   char ch;
6758   int digit;
6759   int r;
6760   int res;
6761
6762   cur_token = * index;
6763
6764   begin = cur_token;
6765
6766   r = mailimf_alpha_parse(message, length, &cur_token, &ch);
6767   if (r != MAILIMF_NO_ERROR) {
6768     res = r;
6769     goto err;
6770   }
6771
6772   while (1) {
6773     int minus_sign;
6774
6775     minus_sign = mailimf_minus_parse(message, length, &cur_token);
6776
6777     r = mailimf_alpha_parse(message, length, &cur_token, &ch);
6778     if (r == MAILIMF_ERROR_PARSE)
6779       r = mailimf_digit_parse(message, length, &cur_token, &digit);
6780
6781     if (r == MAILIMF_NO_ERROR) {
6782       /* do nothing */
6783     }
6784     if (r == MAILIMF_ERROR_PARSE)
6785       break;
6786     else if (r != MAILIMF_NO_ERROR) {
6787       res = r;
6788       goto err;
6789     }
6790   }
6791
6792   item_name = strndup(message + begin, cur_token - begin);
6793   if (item_name == NULL) {
6794     res = MAILIMF_ERROR_MEMORY;
6795     goto err;
6796   }
6797
6798   * index = cur_token;
6799   * result = item_name;
6800
6801   return MAILIMF_NO_ERROR;
6802
6803  err:
6804   return res;
6805 }
6806 #endif
6807
6808 /*
6809 item-value      =       1*angle-addr / addr-spec /
6810                          atom / domain / msg-id
6811 */
6812
6813 #if 0
6814 static int is_item_value_atext(char ch)
6815 {
6816   switch (ch) {
6817   case '\t':
6818   case ' ':
6819   case '\r':
6820   case '\n':
6821   case ';':
6822     return FALSE;
6823   default:
6824     return TRUE;
6825   }
6826 }
6827
6828 static int mailimf_item_value_atom_parse(const char * message, size_t length,
6829                                          size_t * index, char ** result)
6830 {
6831   char * atom;
6832   size_t cur_token;
6833   int r;
6834
6835   cur_token = * index;
6836
6837   r = mailimf_cfws_parse(message, length, &cur_token);
6838   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
6839     return r;
6840
6841   r = mailimf_custom_string_parse(message, length, &cur_token,
6842                                   &atom, is_item_value_atext);
6843   if (r != MAILIMF_NO_ERROR)
6844     return r;
6845
6846   r = mailimf_cfws_parse(message, length, &cur_token);
6847   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
6848     return r;
6849
6850   * index = cur_token;
6851   * result = atom;
6852
6853   return MAILIMF_NO_ERROR;
6854 }
6855
6856 static int mailimf_item_value_parse(const char * message, size_t length,
6857                                     size_t * index,
6858                                     struct mailimf_item_value ** result)
6859 {
6860   size_t cur_token;
6861   clist * angle_addr_list;
6862   char * addr_spec;
6863   char * atom;
6864   char * domain;
6865   char * msg_id;
6866   int type;
6867   struct mailimf_item_value * item_value;
6868   int r;
6869   int res;
6870
6871   cur_token = * index;
6872   
6873   angle_addr_list = NULL;
6874   addr_spec = NULL;
6875   atom = NULL;
6876   domain = NULL;
6877   msg_id = NULL;
6878
6879   r = mailimf_struct_multiple_parse(message, length, &cur_token,
6880                                     &angle_addr_list,
6881                                     (mailimf_struct_parser *)
6882                                     mailimf_angle_addr_parse,
6883                                     (mailimf_struct_destructor *)
6884                                     mailimf_angle_addr_free);
6885   if (r == MAILIMF_NO_ERROR)
6886     type = MAILIMF_ITEM_VALUE_ANGLE_ADDR_LIST;
6887
6888   if (r == MAILIMF_ERROR_PARSE) {
6889     r = mailimf_addr_spec_parse(message, length, &cur_token,
6890                                 &addr_spec);
6891     if (r == MAILIMF_NO_ERROR)
6892       type = MAILIMF_ITEM_VALUE_ADDR_SPEC;
6893   }
6894
6895   if (r == MAILIMF_ERROR_PARSE) {
6896     r = mailimf_msg_id_parse(message, length, &cur_token,
6897                              &msg_id);
6898     if (r == MAILIMF_NO_ERROR)
6899       type = MAILIMF_ITEM_VALUE_MSG_ID;
6900   }
6901
6902   /*
6903   else if (mailimf_domain_parse(message, length, &cur_token,
6904                                 &domain))
6905     type = MAILIMF_ITEM_VALUE_DOMAIN;
6906   */
6907   /*
6908   else if (mailimf_atom_parse(message, length, &cur_token,
6909                               &atom))
6910     type = MAILIMF_ITEM_VALUE_ATOM;
6911   */
6912
6913   if (r == MAILIMF_ERROR_PARSE) {
6914     r = mailimf_item_value_atom_parse(message, length, &cur_token,
6915                                       &atom);
6916     if (r == MAILIMF_NO_ERROR)
6917       type = MAILIMF_ITEM_VALUE_ATOM;
6918   }
6919
6920   if (r != MAILIMF_NO_ERROR) {
6921     res = r;
6922     goto err;
6923   }
6924
6925   item_value = mailimf_item_value_new(type, angle_addr_list, addr_spec,
6926                                       atom, domain, msg_id);
6927   if (item_value == NULL) {
6928     res = MAILIMF_ERROR_MEMORY;
6929     goto free;
6930   }
6931
6932   * result = item_value;
6933   * index = cur_token;
6934
6935   return MAILIMF_NO_ERROR;
6936
6937  free:
6938   if (angle_addr_list != NULL) {
6939     clist_foreach(angle_addr_list, (clist_func) mailimf_angle_addr_free, NULL);
6940     clist_free(angle_addr_list);
6941   }
6942   if (addr_spec != NULL)
6943     mailimf_addr_spec_free(addr_spec);
6944   if (atom != NULL)
6945     mailimf_atom_free(atom);
6946   if (domain != NULL)
6947     mailimf_domain_free(domain);
6948   if (msg_id != NULL)
6949     mailimf_msg_id_free(msg_id);
6950  err:
6951   return res;
6952 }
6953 #endif
6954
6955 /*
6956 optional-field  =       field-name ":" unstructured CRLF
6957 */
6958
6959 static int
6960 mailimf_optional_field_parse(const char * message, size_t length,
6961                              size_t * index,
6962                              struct mailimf_optional_field ** result)
6963 {
6964   char * name;
6965   char * value;
6966   struct mailimf_optional_field * optional_field;
6967   size_t cur_token;
6968   int r;
6969   int res;
6970
6971   cur_token = * index;
6972
6973   r = mailimf_field_name_parse(message, length, &cur_token, &name);
6974   if (r != MAILIMF_NO_ERROR) {
6975     res = r;
6976     goto err;
6977   }
6978
6979   r = mailimf_colon_parse(message, length, &cur_token);
6980   if (r != MAILIMF_NO_ERROR) {
6981     res = r;
6982     goto free_name;
6983   }
6984
6985   r = mailimf_unstructured_parse(message, length, &cur_token, &value);
6986   if (r != MAILIMF_NO_ERROR) {
6987     res = r;
6988     goto free_name;
6989   }
6990
6991   r = mailimf_unstrict_crlf_parse(message, length, &cur_token);
6992   if (r != MAILIMF_NO_ERROR) {
6993     res = r;
6994     goto free_value;
6995   }
6996
6997   optional_field = mailimf_optional_field_new(name, value);
6998   if (optional_field == NULL) {
6999     res = MAILIMF_ERROR_MEMORY;
7000     goto free_value;
7001   }
7002
7003   * result = optional_field;
7004   * index = cur_token;
7005
7006   return MAILIMF_NO_ERROR;
7007
7008  free_value:
7009   mailimf_unstructured_free(value);
7010  free_name:
7011   mailimf_field_name_free(name);
7012  err:
7013   return res;
7014 }
7015      
7016 /*
7017 field-name      =       1*ftext
7018 */
7019
7020 static inline int is_ftext(char ch);
7021
7022 static int mailimf_field_name_parse(const char * message, size_t length,
7023                                     size_t * index, char ** result)
7024 {
7025   char * field_name;
7026   size_t cur_token;
7027   size_t end;
7028   
7029   cur_token = * index;
7030
7031   end = cur_token;
7032   if (end >= length) {
7033     return MAILIMF_ERROR_PARSE;
7034   }
7035
7036   while (is_ftext(message[end])) {
7037     end ++;
7038     if (end >= length)
7039       break;
7040   }
7041   if (end == cur_token) {
7042     return MAILIMF_ERROR_PARSE;
7043   }
7044
7045   /*  field_name = strndup(message + cur_token, end - cur_token); */
7046   field_name = malloc(end - cur_token + 1);
7047   if (field_name == NULL) {
7048     return MAILIMF_ERROR_MEMORY;
7049   }
7050   strncpy(field_name, message + cur_token, end - cur_token);
7051   field_name[end - cur_token] = '\0';
7052
7053   cur_token = end;
7054   
7055   * index = cur_token;
7056   * result = field_name;
7057   
7058   return MAILIMF_NO_ERROR;
7059 }
7060
7061 /*
7062 ftext           =       %d33-57 /               ; Any character except
7063                         %d59-126                ;  controls, SP, and
7064                                                 ;  ":".
7065 */
7066
7067 static inline int is_ftext(char ch)
7068 {
7069   unsigned char uch = (unsigned char) ch;
7070
7071   if (uch < 33)
7072     return FALSE;
7073
7074   if (uch == 58)
7075     return FALSE;
7076
7077   return TRUE;
7078 }
7079
7080 /*
7081 static int mailimf_ftext_parse(const char * message, size_t length,
7082                                     size_t * index, gchar * result)
7083 {
7084   return mailimf_typed_text_parse(message, length, index, result, is_ftext);
7085 }
7086 */
7087
7088
7089
7090
7091 static int mailimf_envelope_field_parse(const char * message, size_t length,
7092                                         size_t * index,
7093                                         struct mailimf_field ** result)
7094 {
7095   size_t cur_token;
7096   int type;
7097   struct mailimf_orig_date * orig_date;
7098   struct mailimf_from * from;
7099   struct mailimf_sender * sender;
7100   struct mailimf_reply_to * reply_to;
7101   struct mailimf_to * to;
7102   struct mailimf_cc * cc;
7103   struct mailimf_bcc * bcc;
7104   struct mailimf_message_id * message_id;
7105   struct mailimf_in_reply_to * in_reply_to;
7106   struct mailimf_references * references;
7107   struct mailimf_subject * subject;
7108   struct mailimf_optional_field * optional_field;
7109   struct mailimf_field * field;
7110   int guessed_type;
7111   int r;
7112   int res;
7113   
7114   cur_token = * index;
7115
7116   orig_date = NULL;
7117   from = NULL;
7118   sender = NULL;
7119   reply_to = NULL;
7120   to = NULL;
7121   cc = NULL;
7122   bcc = NULL;
7123   message_id = NULL;
7124   in_reply_to = NULL;
7125   references = NULL;
7126   subject = NULL;
7127   optional_field = NULL;
7128
7129   guessed_type = guess_header_type(message, length, cur_token);
7130   type = MAILIMF_FIELD_NONE;
7131
7132   switch (guessed_type) {
7133   case MAILIMF_FIELD_ORIG_DATE:
7134     r = mailimf_orig_date_parse(message, length, &cur_token,
7135                                 &orig_date);
7136     if (r == MAILIMF_NO_ERROR)
7137       type = guessed_type;
7138     else if (r == MAILIMF_ERROR_PARSE) {
7139       /* do nothing */
7140     }
7141     else {
7142       res = r;
7143       goto err;
7144     }
7145     break;
7146   case MAILIMF_FIELD_FROM:
7147     r = mailimf_from_parse(message, length, &cur_token,
7148                            &from);
7149     if (r == MAILIMF_NO_ERROR)
7150       type = guessed_type;
7151     else if (r == MAILIMF_ERROR_PARSE) {
7152       /* do nothing */
7153     }
7154     else {
7155       res = r;
7156       goto err;
7157     }
7158     break;
7159   case MAILIMF_FIELD_SENDER:
7160     r = mailimf_sender_parse(message, length, &cur_token,
7161                              &sender);
7162     if (r == MAILIMF_NO_ERROR)
7163       type = guessed_type;
7164     else if (r == MAILIMF_ERROR_PARSE) {
7165       /* do nothing */
7166     }
7167     else {
7168       res = r;
7169       goto err;
7170     }
7171     break;
7172   case MAILIMF_FIELD_REPLY_TO:
7173     r = mailimf_reply_to_parse(message, length, &cur_token,
7174                                &reply_to);
7175     if (r == MAILIMF_NO_ERROR)
7176       type = guessed_type;
7177     else if (r == MAILIMF_ERROR_PARSE) {
7178       /* do nothing */
7179     }
7180     else {
7181       res = r;
7182       goto err;
7183     }
7184     break;
7185   case MAILIMF_FIELD_TO:
7186     r = mailimf_to_parse(message, length, &cur_token,
7187                          &to);
7188     if (r == MAILIMF_NO_ERROR)
7189       type = guessed_type;
7190     else if (r == MAILIMF_ERROR_PARSE) {
7191       /* do nothing */
7192     }
7193     else {
7194       res = r;
7195       goto err;
7196     }
7197     break;
7198   case MAILIMF_FIELD_CC:
7199     r = mailimf_cc_parse(message, length, &cur_token,
7200                          &cc);
7201     if (r == MAILIMF_NO_ERROR)
7202       type = guessed_type;
7203     else if (r == MAILIMF_ERROR_PARSE) {
7204       /* do nothing */
7205     }
7206     else {
7207       res = r;
7208       goto err;
7209     }
7210     break;
7211   case MAILIMF_FIELD_BCC:
7212     r = mailimf_bcc_parse(message, length, &cur_token,
7213                           &bcc);
7214     if (r == MAILIMF_NO_ERROR)
7215       type = guessed_type;
7216     else if (r == MAILIMF_ERROR_PARSE) {
7217       /* do nothing */
7218     }
7219     else {
7220       res = r;
7221       goto err;
7222     }
7223     break;
7224   case MAILIMF_FIELD_MESSAGE_ID:
7225     r = mailimf_message_id_parse(message, length, &cur_token,
7226                                  &message_id);
7227     if (r == MAILIMF_NO_ERROR)
7228       type = guessed_type;
7229     else if (r == MAILIMF_ERROR_PARSE) {
7230       /* do nothing */
7231     }
7232     else {
7233       res = r;
7234       goto err;
7235     }
7236     break;
7237   case MAILIMF_FIELD_IN_REPLY_TO:
7238     r = mailimf_in_reply_to_parse(message, length, &cur_token,
7239                                   &in_reply_to);
7240     if (r == MAILIMF_NO_ERROR)
7241       type = guessed_type;
7242     else if (r == MAILIMF_ERROR_PARSE) {
7243       /* do nothing */
7244     }
7245     else {
7246       res = r;
7247       goto err;
7248     }
7249     break;
7250   case MAILIMF_FIELD_REFERENCES:
7251     r = mailimf_references_parse(message, length, &cur_token,
7252                                  &references);
7253     if (r == MAILIMF_NO_ERROR)
7254       type = guessed_type;
7255     else if (r == MAILIMF_ERROR_PARSE) {
7256       /* do nothing */
7257     }
7258     else {
7259       res = r;
7260       goto err;
7261     }
7262     break;
7263   case MAILIMF_FIELD_SUBJECT:
7264     r = mailimf_subject_parse(message, length, &cur_token,
7265                               &subject);
7266     if (r == MAILIMF_NO_ERROR)
7267       type = guessed_type;
7268     else if (r == MAILIMF_ERROR_PARSE) {
7269       /* do nothing */
7270     }
7271     else {
7272       res = r;
7273       goto err;
7274     }
7275     break;
7276   }
7277
7278   if (type == MAILIMF_FIELD_NONE) {
7279     res = MAILIMF_ERROR_PARSE;
7280     goto err;
7281   }
7282
7283   field = mailimf_field_new(type, NULL, NULL, NULL, NULL, NULL,
7284       NULL, NULL, NULL,
7285       orig_date, from, sender, reply_to, to,
7286       cc, bcc, message_id, in_reply_to, references,
7287       subject, NULL, NULL, optional_field);
7288   if (field == NULL) {
7289     res = MAILIMF_ERROR_MEMORY;
7290     goto free_fields;
7291   }
7292   
7293   * result = field;
7294   * index = cur_token;
7295
7296   return MAILIMF_NO_ERROR;
7297
7298  free_fields:
7299   if (orig_date != NULL)
7300     mailimf_orig_date_free(orig_date);
7301   if (from != NULL)
7302     mailimf_from_free(from);
7303   if (sender != NULL)
7304     mailimf_sender_free(sender);
7305   if (reply_to != NULL)
7306     mailimf_reply_to_free(reply_to);
7307   if (to != NULL)
7308     mailimf_to_free(to);
7309   if (cc != NULL)
7310     mailimf_cc_free(cc);
7311   if (bcc != NULL)
7312     mailimf_bcc_free(bcc);
7313   if (message_id != NULL)
7314     mailimf_message_id_free(message_id);
7315   if (in_reply_to != NULL)
7316     mailimf_in_reply_to_free(in_reply_to);
7317   if (references != NULL)
7318     mailimf_references_free(references);
7319   if (subject != NULL)
7320     mailimf_subject_free(subject);
7321   if (optional_field != NULL)
7322     mailimf_optional_field_free(optional_field);
7323  err:
7324   return res;
7325 }
7326
7327 int mailimf_envelope_fields_parse(const char * message, size_t length,
7328                                   size_t * index,
7329                                   struct mailimf_fields ** result)
7330 {
7331   size_t cur_token;
7332   clist * list;
7333   struct mailimf_fields * fields;
7334   int r;
7335   int res;
7336
7337   cur_token = * index;
7338
7339   list = clist_new();
7340   if (list == NULL) {
7341     res = MAILIMF_ERROR_MEMORY;
7342     goto err;
7343   }
7344
7345   while (1) {
7346     struct mailimf_field * elt;
7347
7348     r = mailimf_envelope_field_parse(message, length, &cur_token, &elt);
7349     if (r == MAILIMF_NO_ERROR) {
7350       r = clist_append(list, elt);
7351       if (r < 0) {
7352         res = MAILIMF_ERROR_MEMORY;
7353         goto free;
7354       }
7355     }
7356     else if (r == MAILIMF_ERROR_PARSE) {
7357       r = mailimf_ignore_field_parse(message, length, &cur_token);
7358       if (r == MAILIMF_NO_ERROR) {
7359         /* do nothing */
7360       }
7361       else if (r == MAILIMF_ERROR_PARSE) {
7362         break;
7363       }
7364       else {
7365         res = r;
7366         goto free;
7367       }
7368     }
7369     else {
7370       res = r;
7371       goto free;
7372     }
7373   }
7374
7375   fields = mailimf_fields_new(list);
7376   if (fields == NULL) {
7377     res = MAILIMF_ERROR_MEMORY;
7378     goto free;
7379   }
7380
7381   * result = fields;
7382   * index = cur_token;
7383
7384   return MAILIMF_NO_ERROR;
7385
7386  free:
7387   if (list != NULL) {
7388     clist_foreach(list, (clist_func) mailimf_field_free, NULL);
7389     clist_free(list);
7390   }
7391  err:
7392   return res;
7393 }
7394
7395
7396 static int
7397 mailimf_envelope_or_optional_field_parse(const char * message,
7398                                          size_t length,
7399                                          size_t * index,
7400                                          struct mailimf_field ** result)
7401 {
7402   int r;
7403   size_t cur_token;
7404   struct mailimf_optional_field * optional_field;
7405   struct mailimf_field * field;
7406
7407   r = mailimf_envelope_field_parse(message, length, index, result);
7408   if (r == MAILIMF_NO_ERROR)
7409     return MAILIMF_NO_ERROR;
7410
7411   cur_token = * index;
7412
7413   r = mailimf_optional_field_parse(message, length, &cur_token,
7414                                    &optional_field);
7415   if (r != MAILIMF_NO_ERROR)
7416     return r;
7417
7418   field = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD, NULL,
7419       NULL, NULL, NULL,
7420       NULL, NULL, NULL,
7421       NULL, NULL, NULL,
7422       NULL, NULL, NULL,
7423       NULL, NULL, NULL, NULL, NULL,
7424       NULL, NULL, NULL, optional_field);
7425   if (field == NULL) {
7426     mailimf_optional_field_free(optional_field);
7427     return MAILIMF_ERROR_MEMORY;
7428   }
7429
7430   * result = field;
7431   * index = cur_token;
7432
7433   return MAILIMF_NO_ERROR;
7434 }
7435
7436
7437 int
7438 mailimf_envelope_and_optional_fields_parse(const char * message, size_t length,
7439                                            size_t * index,
7440                                            struct mailimf_fields ** result)
7441 {
7442   size_t cur_token;
7443   clist * list;
7444   struct mailimf_fields * fields;
7445   int r;
7446   int res;
7447
7448   cur_token = * index;
7449
7450   list = NULL;
7451
7452   r = mailimf_struct_multiple_parse(message, length, &cur_token,
7453                                     &list,
7454                                     (mailimf_struct_parser *)
7455                                     mailimf_envelope_or_optional_field_parse,
7456                                     (mailimf_struct_destructor *)
7457                                     mailimf_field_free);
7458   switch (r) {
7459   case MAILIMF_NO_ERROR:
7460     /* do nothing */
7461     break;
7462
7463   case MAILIMF_ERROR_PARSE:
7464     list = clist_new();
7465     if (list == NULL) {
7466       res = MAILIMF_ERROR_MEMORY;
7467       goto err;
7468     }
7469     break;
7470
7471   default:
7472     res = r;
7473     goto err;
7474   }
7475
7476   fields = mailimf_fields_new(list);
7477   if (fields == NULL) {
7478     res = MAILIMF_ERROR_MEMORY;
7479     goto free;
7480   }
7481
7482   * result = fields;
7483   * index = cur_token;
7484
7485   return MAILIMF_NO_ERROR;
7486
7487  free:
7488   if (list != NULL) {
7489     clist_foreach(list, (clist_func) mailimf_field_free, NULL);
7490     clist_free(list);
7491   }
7492  err:
7493   return res;
7494 }
7495
7496
7497
7498 static int
7499 mailimf_only_optional_field_parse(const char * message,
7500                                   size_t length,
7501                                   size_t * index,
7502                                   struct mailimf_field ** result)
7503 {
7504   int r;
7505   size_t cur_token;
7506   struct mailimf_optional_field * optional_field;
7507   struct mailimf_field * field;
7508
7509   cur_token = * index;
7510
7511   r = mailimf_optional_field_parse(message, length, &cur_token,
7512                                    &optional_field);
7513   if (r != MAILIMF_NO_ERROR)
7514     return r;
7515
7516   field = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD, NULL, NULL, NULL,
7517       NULL, NULL, NULL, NULL, NULL,
7518       NULL, NULL, NULL, NULL, NULL,
7519       NULL, NULL, NULL, NULL, NULL,
7520       NULL, NULL, NULL, optional_field);
7521   if (field == NULL) {
7522     mailimf_optional_field_free(optional_field);
7523     return MAILIMF_ERROR_MEMORY;
7524   }
7525
7526   * result = field;
7527   * index = cur_token;
7528
7529   return MAILIMF_NO_ERROR;
7530 }
7531
7532
7533 int
7534 mailimf_optional_fields_parse(const char * message, size_t length,
7535                               size_t * index,
7536                               struct mailimf_fields ** result)
7537 {
7538   size_t cur_token;
7539   clist * list;
7540   struct mailimf_fields * fields;
7541   int r;
7542   int res;
7543
7544   cur_token = * index;
7545
7546   list = NULL;
7547
7548   r = mailimf_struct_multiple_parse(message, length, &cur_token,
7549                                     &list,
7550                                     (mailimf_struct_parser *)
7551                                     mailimf_only_optional_field_parse,
7552                                     (mailimf_struct_destructor *)
7553                                     mailimf_field_free);
7554   switch (r) {
7555   case MAILIMF_NO_ERROR:
7556     /* do nothing */
7557     break;
7558
7559   case MAILIMF_ERROR_PARSE:
7560     list = clist_new();
7561     if (list == NULL) {
7562       res = MAILIMF_ERROR_MEMORY;
7563       goto err;
7564     }
7565     break;
7566
7567   default:
7568     res = r;
7569     goto err;
7570   }
7571
7572   fields = mailimf_fields_new(list);
7573   if (fields == NULL) {
7574     res = MAILIMF_ERROR_MEMORY;
7575     goto free;
7576   }
7577
7578   * result = fields;
7579   * index = cur_token;
7580
7581   return MAILIMF_NO_ERROR;
7582
7583  free:
7584   if (list != NULL) {
7585     clist_foreach(list, (clist_func) mailimf_field_free, NULL);
7586     clist_free(list);
7587   }
7588  err:
7589   return res;
7590 }