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