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