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