Fix build warning
[claws.git] / src / plugins / mailmbox / mailimf.c
1 /*
2  * libEtPan! -- a mail stuff library
3  *
4  * Copyright (C) 2001, 2002 - DINH Viet Hoa
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the libEtPan! project nor the names of its
16  *    contributors may be used to endorse or promote products derived
17  *    from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 /*
33  * $Id$
34  */
35
36 #include "mailimf.h"
37
38 /*
39   RFC 2822
40
41   RFC 2821 ... 
42    A message-originating SMTP system SHOULD NOT send a message that
43    already contains a Return-path header.  SMTP servers performing a
44    relay function MUST NOT inspect the message data, and especially not
45    to the extent needed to determine if Return-path headers are present.
46    SMTP servers making final delivery MAY remove Return-path headers
47    before adding their own.
48 */
49
50 #include <ctype.h>
51 #include <mmapstring.h>
52 #include <stdlib.h>
53 #include <string.h>
54
55 #ifndef TRUE
56 #define TRUE 1
57 #endif
58
59 #ifndef FALSE
60 #define FALSE 0
61 #endif
62
63
64
65
66
67
68
69 static inline int is_dtext(char ch);
70
71 static int mailimf_quoted_pair_parse(const char * message, size_t length,
72                                      size_t * index, char * result);
73
74 static int mailimf_ccontent_parse(const char * message, size_t length,
75                                   size_t * index);
76
77 static int
78 mailimf_comment_fws_ccontent_parse(const char * message, size_t length,
79                                    size_t * index);
80
81 static inline int mailimf_comment_parse(const char * message, size_t length,
82                                  size_t * index);
83
84 static int mailimf_qcontent_parse(const char * message, size_t length,
85                                   size_t * index, char * ch);
86
87 static int mailimf_phrase_parse(const char * message, size_t length,
88                                 size_t * index, char ** result);
89
90 static int mailimf_unstructured_parse(const char * message, size_t length,
91                                       size_t * index, char ** result);
92
93 static int mailimf_ignore_unstructured_parse(const char * message, size_t length,
94                                              size_t * index);
95
96 static int mailimf_day_of_week_parse(const char * message, size_t length,
97                                      size_t * index, int * result);
98
99 static int mailimf_day_name_parse(const char * message, size_t length,
100                                   size_t * index, int * result);
101
102 static int mailimf_date_parse(const char * message, size_t length,
103                               size_t * index,
104                               int * pday, int * pmonth, int * pyear);
105
106 static int mailimf_year_parse(const char * message, size_t length,
107                               size_t * index, int * result);
108
109 static int mailimf_month_parse(const char * message, size_t length,
110                                size_t * index, int * result);
111
112 static int mailimf_month_name_parse(const char * message, size_t length,
113                                     size_t * index, int * result);
114
115 static int mailimf_day_parse(const char * message, size_t length,
116                                   size_t * index, int * result);
117
118 static int mailimf_time_parse(const char * message, size_t length,
119                               size_t * index, 
120                               int * phour, int * pmin,
121                               int * psec,
122                               int * zone);
123 static int mailimf_time_of_day_parse(const char * message, size_t length,
124                                      size_t * index,
125                                      int * phour, int * pmin,
126                                      int * psec);
127
128 static int mailimf_hour_parse(const char * message, size_t length,
129                               size_t * index, int * result);
130
131 static int mailimf_minute_parse(const char * message, size_t length,
132                                 size_t * index, int * result);
133
134 static int mailimf_second_parse(const char * message, size_t length,
135                                 size_t * index, int * result);
136
137 static int mailimf_zone_parse(const char * message, size_t length,
138                               size_t * index, int * result);
139
140 static int mailimf_name_addr_parse(const char * message, size_t length,
141                                    size_t * index,
142                                    char ** pdisplay_name,
143                                    char ** pangle_addr);
144
145 static int mailimf_angle_addr_parse(const char * message, size_t length,
146                                     size_t * index, char ** result);
147
148 static int mailimf_group_parse(const char * message, size_t length,
149                                size_t * index,
150                                struct mailimf_group ** result);
151
152 static int mailimf_display_name_parse(const char * message, size_t length,
153                                       size_t * index, char ** result);
154
155 static int mailimf_addr_spec_parse(const char * message, size_t length,
156                                    size_t * index,
157                                    char ** address);
158
159 #if 0
160 static int mailimf_local_part_parse(const char * message, size_t length,
161                                     size_t * index,
162                                     char ** result);
163
164 static int mailimf_domain_parse(const char * message, size_t length,
165                                 size_t * index,
166                                 char ** result);
167 #endif
168
169 #if 0
170 static int mailimf_domain_literal_parse(const char * message, size_t length,
171                                         size_t * index, char ** result);
172 #endif
173
174 #if 0
175 static int mailimf_dcontent_parse(const char * message, size_t length,
176                                   size_t * index, char * result);
177 #endif
178
179 static int
180 mailimf_orig_date_parse(const char * message, size_t length,
181                         size_t * index, struct mailimf_orig_date ** result);
182
183 static int
184 mailimf_from_parse(const char * message, size_t length,
185                    size_t * index, struct mailimf_from ** result);
186
187 static int
188 mailimf_sender_parse(const char * message, size_t length,
189                      size_t * index, struct mailimf_sender ** result);
190
191 static int
192 mailimf_reply_to_parse(const char * message, size_t length,
193                        size_t * index, struct mailimf_reply_to ** result);
194
195 static int
196 mailimf_to_parse(const char * message, size_t length,
197                  size_t * index, struct mailimf_to ** result);
198
199 static int
200 mailimf_cc_parse(const char * message, size_t length,
201                  size_t * index, struct mailimf_cc ** result);
202
203 static int
204 mailimf_bcc_parse(const char * message, size_t length,
205                   size_t * index, struct mailimf_bcc ** result);
206
207 static int mailimf_message_id_parse(const char * message, size_t length,
208                                     size_t * index,
209                                     struct mailimf_message_id ** result);
210
211 static int
212 mailimf_in_reply_to_parse(const char * message, size_t length,
213                           size_t * index,
214                           struct mailimf_in_reply_to ** result);
215
216 #if 0
217 static int mailimf_references_parse(const char * message, size_t length,
218                                     size_t * index,
219                                     struct mailimf_references **
220                                     result);
221 #endif
222
223 static int mailimf_unstrict_msg_id_parse(const char * message, size_t length,
224                                          size_t * index,
225                                          char ** result);
226
227 #if 0
228 static int mailimf_id_left_parse(const char * message, size_t length,
229                                  size_t * index, char ** result);
230
231 static int mailimf_id_right_parse(const char * message, size_t length,
232                                   size_t * index, char ** result);
233 #endif
234
235 #if 0
236 static int mailimf_no_fold_quote_parse(const char * message, size_t length,
237                                        size_t * index, char ** result);
238
239 static int mailimf_no_fold_literal_parse(const char * message, size_t length,
240                                          size_t * index, char ** result);
241 #endif
242
243 static int mailimf_subject_parse(const char * message, size_t length,
244                                  size_t * index,
245                                  struct mailimf_subject ** result);
246
247 static int mailimf_comments_parse(const char * message, size_t length,
248                                   size_t * index,
249                                   struct mailimf_comments ** result);
250
251 static int mailimf_keywords_parse(const char * message, size_t length,
252                                   size_t * index,
253                                   struct mailimf_keywords ** result);
254
255 static int
256 mailimf_resent_date_parse(const char * message, size_t length,
257                           size_t * index, struct mailimf_orig_date ** result);
258
259 static int
260 mailimf_resent_from_parse(const char * message, size_t length,
261                           size_t * index, struct mailimf_from ** result);
262
263 static int
264 mailimf_resent_sender_parse(const char * message, size_t length,
265                             size_t * index, struct mailimf_sender ** result);
266
267 static int
268 mailimf_resent_to_parse(const char * message, size_t length,
269                         size_t * index, struct mailimf_to ** result);
270
271 static int
272 mailimf_resent_cc_parse(const char * message, size_t length,
273                         size_t * index, struct mailimf_cc ** result);
274
275 static int
276 mailimf_resent_bcc_parse(const char * message, size_t length,
277                          size_t * index, struct mailimf_bcc ** result);
278
279 static int
280 mailimf_resent_msg_id_parse(const char * message, size_t length,
281                             size_t * index,
282                             struct mailimf_message_id ** result);
283
284 static int mailimf_return_parse(const char * message, size_t length,
285                                 size_t * index,
286                                 struct mailimf_return ** result);
287
288 static int
289 mailimf_path_parse(const char * message, size_t length,
290                    size_t * index, struct mailimf_path ** result);
291
292 static int
293 mailimf_optional_field_parse(const char * message, size_t length,
294                              size_t * index,
295                              struct mailimf_optional_field ** result);
296
297 static int mailimf_field_name_parse(const char * message, size_t length,
298                                     size_t * index, char ** result);
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324 /* *************************************************************** */
325
326 static inline int is_digit(char ch)
327 {
328   return (ch >= '0') && (ch <= '9');
329 }
330
331 static int mailimf_digit_parse(const char * message, size_t length,
332                                size_t * index, int * result)
333 {
334   size_t cur_token;
335
336   cur_token = * index;
337   
338   if (cur_token >= length)
339     return MAILIMF_ERROR_PARSE;
340
341   if (is_digit(message[cur_token])) {
342     * result = message[cur_token] - '0';
343     cur_token ++;
344     * index = cur_token;
345     return MAILIMF_NO_ERROR;
346   }
347   else
348     return MAILIMF_ERROR_PARSE;
349 }
350
351 int
352 mailimf_number_parse(const char * message, size_t length,
353                      size_t * index, uint32_t * result)
354 {
355   size_t cur_token;
356   int digit;
357   uint32_t number;
358   int parsed;
359   int r;
360
361   cur_token = * index;
362   parsed = FALSE;
363
364   number = 0;
365   while (1) {
366     r = mailimf_digit_parse(message, length, &cur_token, &digit);
367     if (r != MAILIMF_NO_ERROR) {
368       if (r == MAILIMF_ERROR_PARSE)
369         break;
370       else
371         return r;
372     }
373     number *= 10;
374     number += digit;
375     parsed = TRUE;
376   }
377
378   if (!parsed)
379     return MAILIMF_ERROR_PARSE;
380
381   * result = number;
382   * index = cur_token;
383
384   return MAILIMF_NO_ERROR;
385 }
386
387 int mailimf_char_parse(const char * message, size_t length,
388                        size_t * index, char token)
389 {
390   size_t cur_token;
391
392   cur_token = * index;
393
394   if (cur_token >= length)
395     return MAILIMF_ERROR_PARSE;
396
397   if (message[cur_token] == token) {
398     cur_token ++;
399     * index = cur_token;
400     return MAILIMF_NO_ERROR;
401   }
402   else
403     return MAILIMF_ERROR_PARSE;
404 }
405
406 int mailimf_unstrict_char_parse(const char * message, size_t length,
407                                 size_t * index, char token)
408 {
409   size_t cur_token;
410   int r;
411
412   cur_token = * index;
413
414   r = mailimf_cfws_parse(message, length, &cur_token);
415   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
416     return r;
417
418   r = mailimf_char_parse(message, length, &cur_token, token);
419   if (r != MAILIMF_NO_ERROR)
420     return r;
421   
422   * index = cur_token;
423
424   return MAILIMF_NO_ERROR;
425 }
426
427 int
428 mailimf_token_case_insensitive_len_parse(const char * message, size_t length,
429                                          size_t * index, char * token,
430                                          size_t token_length)
431 {
432   size_t cur_token;
433
434   cur_token = * index;
435
436   if (cur_token + token_length - 1 >= length)
437     return MAILIMF_ERROR_PARSE;
438
439   if (strncasecmp(message + cur_token, token, token_length) == 0) {
440     cur_token += token_length;
441     * index = cur_token;
442     return MAILIMF_NO_ERROR;
443   }
444   else
445     return MAILIMF_ERROR_PARSE;
446 }
447
448 static int mailimf_oparenth_parse(const char * message, size_t length,
449                                   size_t * index)
450 {
451   return mailimf_char_parse(message, length, index, '(');
452 }
453
454 static int mailimf_cparenth_parse(const char * message, size_t length,
455                                   size_t * index)
456 {
457   return mailimf_char_parse(message, length, index, ')');
458 }
459
460 static int mailimf_comma_parse(const char * message, size_t length,
461                                size_t * index)
462 {
463   return mailimf_unstrict_char_parse(message, length, index, ',');
464 }
465
466 static int mailimf_dquote_parse(const char * message, size_t length,
467                                 size_t * index)
468 {
469   return mailimf_char_parse(message, length, index, '\"');
470 }
471
472 static int mailimf_colon_parse(const char * message, size_t length,
473                                size_t * index)
474 {
475   return mailimf_unstrict_char_parse(message, length, index, ':');
476 }
477
478 static int mailimf_semi_colon_parse(const char * message, size_t length,
479                                     size_t * index)
480 {
481   return mailimf_unstrict_char_parse(message, length, index, ';');
482 }
483
484 static int mailimf_plus_parse(const char * message, size_t length,
485                               size_t * index)
486 {
487   return mailimf_unstrict_char_parse(message, length, index, '+');
488 }
489
490 static int mailimf_minus_parse(const char * message, size_t length,
491                                size_t * index)
492 {
493   return mailimf_unstrict_char_parse(message, length, index, '-');
494 }
495
496 static int mailimf_lower_parse(const char * message, size_t length,
497                                size_t * index)
498 {
499   return mailimf_unstrict_char_parse(message, length, index, '<');
500 }
501
502 static int mailimf_greater_parse(const char * message, size_t length,
503                                       size_t * index)
504 {
505   return mailimf_unstrict_char_parse(message, length, index, '>');
506 }
507
508 #if 0
509 static int mailimf_obracket_parse(const char * message, size_t length,
510                                        size_t * index)
511 {
512   return mailimf_unstrict_char_parse(message, length, index, '[');
513 }
514
515 static int mailimf_cbracket_parse(const char * message, size_t length,
516                                        size_t * index)
517 {
518   return mailimf_unstrict_char_parse(message, length, index, ']');
519 }
520 #endif
521
522 static int mailimf_at_sign_parse(const char * message, size_t length,
523                                       size_t * index)
524 {
525   return mailimf_unstrict_char_parse(message, length, index, '@');
526 }
527
528 static int mailimf_point_parse(const char * message, size_t length,
529                                       size_t * index)
530 {
531   return mailimf_unstrict_char_parse(message, length, index, '.');
532 }
533
534 int
535 mailimf_custom_string_parse(const char * message, size_t length,
536                             size_t * index, char ** result,
537                             int (* is_custom_char)(char))
538 {
539   size_t begin;
540   size_t end;
541   char * gstr;
542
543   begin = * index;
544
545   end = begin;
546
547   if (end >= length)
548     return MAILIMF_ERROR_PARSE;
549
550   while (is_custom_char(message[end])) {
551     end ++;
552     if (end >= length)
553       break;
554   }
555
556   if (end != begin) {
557     /*
558     gstr = strndup(message + begin, end - begin);
559     */
560     gstr = malloc(end - begin + 1);
561     if (gstr == NULL)
562       return MAILIMF_ERROR_MEMORY;
563     strncpy(gstr, message + begin, end - begin);
564     gstr[end - begin] = '\0';
565
566     * index = end;
567     * result = gstr;
568     return MAILIMF_NO_ERROR;
569   }
570   else
571     return MAILIMF_ERROR_PARSE;
572 }
573
574
575
576
577
578
579
580 typedef int mailimf_struct_parser(const char * message, size_t length,
581                                   size_t * index, void * result);
582
583 typedef int mailimf_struct_destructor(void * result);
584
585
586 static int
587 mailimf_struct_multiple_parse(const char * message, size_t length,
588                               size_t * index, clist ** result,
589                               mailimf_struct_parser * parser,
590                               mailimf_struct_destructor * destructor)
591 {
592   clist * struct_list;
593   size_t cur_token;
594   void * value;
595   int r;
596   int res;
597
598   cur_token = * index;
599
600   r = parser(message, length, &cur_token, &value);
601   if (r != MAILIMF_NO_ERROR) {
602     res = r;
603     goto err;
604   }
605
606   struct_list = clist_new();
607   if (struct_list == NULL) {
608     destructor(value);
609     res = MAILIMF_ERROR_MEMORY;
610     goto err;
611   }
612
613   r = clist_append(struct_list, value);
614   if (r < 0) {
615     destructor(value);
616     res = MAILIMF_ERROR_MEMORY;
617     goto free;
618   }
619
620   while (1) {
621     r = parser(message, length, &cur_token, &value);
622     if (r != MAILIMF_NO_ERROR) {
623       if (r == MAILIMF_ERROR_PARSE)
624         break;
625       else {
626         res = r;
627         goto free;
628       }
629     }
630     r = clist_append(struct_list, value);
631     if (r < 0) {
632       (* destructor)(value);
633       res = MAILIMF_ERROR_MEMORY;
634       goto free;
635     }
636   }
637
638   * result = struct_list;
639   * index = cur_token;
640   
641   return MAILIMF_NO_ERROR;
642
643  free:
644   clist_foreach(struct_list, (clist_func) destructor, NULL);
645   clist_free(struct_list);
646  err:
647   return res;
648 }
649
650
651
652 static int
653 mailimf_struct_list_parse(const char * message, size_t length,
654                           size_t * index, clist ** result,
655                           char symbol,
656                           mailimf_struct_parser * parser,
657                           mailimf_struct_destructor * destructor)
658 {
659   clist * struct_list;
660   size_t cur_token;
661   void * value;
662   size_t final_token;
663   int r;
664   int res;
665
666   cur_token = * index;
667
668   r = parser(message, length, &cur_token, &value);
669   if (r != MAILIMF_NO_ERROR) {
670     res = r;
671     goto err;
672   }
673
674   struct_list = clist_new();
675   if (struct_list == NULL) {
676     destructor(value);
677     res = MAILIMF_ERROR_MEMORY;
678     goto err;
679   }
680
681   r = clist_append(struct_list, value);
682   if (r < 0) {
683     destructor(value);
684     res = MAILIMF_ERROR_MEMORY;
685     goto free;
686   }
687
688   final_token = cur_token;
689
690   while (1) {
691     r = mailimf_unstrict_char_parse(message, length, &cur_token, symbol);
692     if (r != MAILIMF_NO_ERROR) {
693       if (r == MAILIMF_ERROR_PARSE)
694         break;
695       else {
696         res = r;
697         goto free;
698       }
699     }
700
701     r = parser(message, length, &cur_token, &value);
702     if (r != MAILIMF_NO_ERROR) {
703       if (r == MAILIMF_ERROR_PARSE)
704         break;
705       else {
706         res = r;
707         goto free;
708       }
709     }
710
711     r = clist_append(struct_list, value);
712     if (r < 0) {
713       destructor(value);
714       res = MAILIMF_ERROR_MEMORY;
715       goto free;
716     }
717
718     final_token = cur_token;
719   }
720   
721   * result = struct_list;
722   * index = final_token;
723   
724   return MAILIMF_NO_ERROR;
725   
726  free:
727   clist_foreach(struct_list, (clist_func) destructor, NULL);
728   clist_free(struct_list);
729  err:
730   return res;
731 }
732
733 static inline int mailimf_wsp_parse(const char * message, size_t length,
734                                     size_t * index)
735 {
736   size_t cur_token;
737
738   cur_token = * index;
739
740   if (cur_token >= length)
741     return MAILIMF_ERROR_PARSE;
742
743   if ((message[cur_token] != ' ') && (message[cur_token] != '\t'))
744     return MAILIMF_ERROR_PARSE;
745
746   cur_token ++;
747   * index = cur_token;
748
749   return MAILIMF_NO_ERROR;
750 }
751
752
753 int mailimf_crlf_parse(const char * message, size_t length, size_t * index)
754 {
755   size_t cur_token;
756   int r;
757
758   cur_token = * index;
759
760   r = mailimf_char_parse(message, length, &cur_token, '\r');
761   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
762     return r;
763
764   r = mailimf_char_parse(message, length, &cur_token, '\n');
765   if (r != MAILIMF_NO_ERROR)
766     return r;
767
768   * index = cur_token;
769   return MAILIMF_NO_ERROR;
770 }
771
772 static int mailimf_unstrict_crlf_parse(const char * message,
773                                        size_t length, size_t * index)
774 {
775   size_t cur_token;
776   int r;
777
778   cur_token = * index;
779
780   mailimf_cfws_parse(message, length, &cur_token);
781
782   r = mailimf_char_parse(message, length, &cur_token, '\r');
783   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
784     return r;
785
786   r = mailimf_char_parse(message, length, &cur_token, '\n');
787   if (r != MAILIMF_NO_ERROR)
788     return r;
789
790   * index = cur_token;
791   return MAILIMF_NO_ERROR;
792 }
793
794 /* ************************************************************************ */
795
796
797
798 /* RFC 2822 grammar */
799
800 /*
801 NO-WS-CTL       =       %d1-8 /         ; US-ASCII control characters
802                         %d11 /          ;  that do not include the
803                         %d12 /          ;  carriage return, line feed,
804                         %d14-31 /       ;  and white space characters
805                         %d127
806 */
807
808 static inline int is_no_ws_ctl(char ch)
809 {
810   if ((ch == 9) || (ch == 10) || (ch == 13))
811     return FALSE;
812
813   if (ch == 127)
814      return TRUE;
815
816   return (ch >= 1) && (ch <= 31);
817 }
818
819 /*
820 text            =       %d1-9 /         ; Characters excluding CR and LF
821                         %d11 /
822                         %d12 /
823                         %d14-127 /
824                         obs-text
825 */
826
827 /*
828 specials        =       "(" / ")" /     ; Special characters used in
829                         "<" / ">" /     ;  other parts of the syntax
830                         "[" / "]" /
831                         ":" / ";" /
832                         "@" / "\" /
833                         "," / "." /
834                         DQUOTE
835 */
836
837 /*
838 quoted-pair     =       ("\" text) / obs-qp
839 */
840
841 static inline int mailimf_quoted_pair_parse(const char * message, size_t length,
842                                             size_t * index, char * result)
843 {
844   size_t cur_token;
845
846   cur_token = * index;
847   
848   if (cur_token + 1 >= length)
849     return MAILIMF_ERROR_PARSE;
850
851   if (message[cur_token] != '\\')
852     return MAILIMF_ERROR_PARSE;
853
854   cur_token ++;
855   * result = message[cur_token];
856   cur_token ++;
857   * index = cur_token;
858
859   return MAILIMF_NO_ERROR;
860 }
861
862 /*
863 FWS             =       ([*WSP CRLF] 1*WSP) /   ; Folding white space
864                         obs-FWS
865 */
866
867 int mailimf_fws_parse(const char * message, size_t length, size_t * index)
868 {
869   size_t cur_token;
870   size_t final_token;
871   int fws_1;
872   int fws_2;
873   int fws_3;
874   int r;
875   
876   cur_token = * index;
877
878   fws_1 = FALSE;
879   while (1) {
880     r = mailimf_wsp_parse(message, length, &cur_token);
881     if (r != MAILIMF_NO_ERROR) {
882       if (r == MAILIMF_ERROR_PARSE)
883         break;
884       else
885         return r;
886     }
887     fws_1 = TRUE;
888   }
889   final_token = cur_token;
890
891   r = mailimf_crlf_parse(message, length, &cur_token);
892   switch (r) {
893   case MAILIMF_NO_ERROR:
894     fws_2 = TRUE;
895     break;
896   case MAILIMF_ERROR_PARSE:
897     fws_2 = FALSE;
898     break;
899   default:
900       return r;
901   }
902   
903   fws_3 = FALSE;
904   if (fws_2) {
905     while (1) {
906       r = mailimf_wsp_parse(message, length, &cur_token);
907       if (r != MAILIMF_NO_ERROR) {
908         if (r == MAILIMF_ERROR_PARSE)
909           break;
910         else
911           return r;
912       }
913       fws_3 = TRUE;
914     }
915   }
916
917   if ((!fws_1) && (!fws_3))
918     return MAILIMF_ERROR_PARSE;
919
920   if (!fws_3)
921     cur_token = final_token;
922
923   * index = cur_token;
924
925   return MAILIMF_NO_ERROR;
926 }
927
928
929 /*
930 ctext           =       NO-WS-CTL /     ; Non white space controls
931
932                         %d33-39 /       ; The rest of the US-ASCII
933                         %d42-91 /       ;  characters not including "(",
934                         %d93-126        ;  ")", or "\"
935 */
936
937 static inline int is_ctext(char ch)
938 {
939   unsigned char uch = (unsigned char) ch;
940
941   if (is_no_ws_ctl(ch))
942     return TRUE;
943
944   if (uch < 33)
945     return FALSE;
946
947   if ((uch == 40) || (uch == 41))
948     return FALSE;
949   
950   if (uch == 92)
951     return FALSE;
952
953   if (uch == 127)
954     return FALSE;
955
956   return TRUE;
957 }
958
959 /*
960 ccontent        =       ctext / quoted-pair / comment
961 */
962
963 static inline int mailimf_ccontent_parse(const char * message, size_t length,
964                                          size_t * index)
965 {
966   size_t cur_token;
967   char ch;
968   int r;
969   
970   cur_token = * index;
971
972   if (cur_token >= length)
973     return MAILIMF_ERROR_PARSE;
974
975   if (is_ctext(message[cur_token])) {
976     cur_token ++;
977   }
978   else {
979     r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
980     
981     if (r == MAILIMF_ERROR_PARSE)
982       r = mailimf_comment_parse(message, length, &cur_token);
983     
984     if (r == MAILIMF_ERROR_PARSE)
985       return r;
986   }
987
988   * index = cur_token;
989
990   return MAILIMF_NO_ERROR;
991 }
992
993 /*
994 [FWS] ccontent
995 */
996
997 static inline int
998 mailimf_comment_fws_ccontent_parse(const char * message, size_t length,
999                                    size_t * index)
1000 {
1001   size_t cur_token;
1002   int r;
1003
1004   cur_token = * index;
1005
1006   r = mailimf_fws_parse(message, length, &cur_token);
1007   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
1008     return r;
1009
1010   r = mailimf_ccontent_parse(message, length, &cur_token);
1011   if (r != MAILIMF_NO_ERROR)
1012     return r;
1013
1014   * index = cur_token;
1015
1016   return MAILIMF_NO_ERROR;
1017 }
1018
1019 /*
1020 comment         =       "(" *([FWS] ccontent) [FWS] ")"
1021 */
1022
1023 static inline int mailimf_comment_parse(const char * message, size_t length,
1024                                  size_t * index)
1025 {
1026   size_t cur_token;
1027   int r;
1028
1029   cur_token = * index;
1030
1031   r = mailimf_oparenth_parse(message, length, &cur_token);
1032   if (r != MAILIMF_NO_ERROR)
1033     return r;
1034
1035   while (1) {
1036     r = mailimf_comment_fws_ccontent_parse(message, length, &cur_token);
1037     if (r != MAILIMF_NO_ERROR) {
1038       if (r == MAILIMF_ERROR_PARSE)
1039         break;
1040       else
1041         return r;
1042     }
1043   }
1044
1045   r = mailimf_fws_parse(message, length, &cur_token);
1046   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
1047     return r;
1048
1049   r = mailimf_cparenth_parse(message, length, &cur_token);
1050   if (r != MAILIMF_NO_ERROR)
1051     return r;
1052
1053   * index = cur_token;
1054
1055   return MAILIMF_NO_ERROR;
1056 }
1057
1058 /*
1059 [FWS] comment
1060 */
1061
1062 static inline int mailimf_cfws_fws_comment_parse(const char * message, size_t length,
1063                                                  size_t * index)
1064 {
1065   size_t cur_token;
1066   int r;
1067
1068   cur_token = * index;
1069
1070   r = mailimf_fws_parse(message, length, &cur_token);
1071   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
1072     return r;
1073
1074   r = mailimf_comment_parse(message, length, &cur_token);
1075   if (r != MAILIMF_NO_ERROR)
1076     return r;
1077
1078   * index = cur_token;
1079
1080   return MAILIMF_NO_ERROR;
1081 }
1082
1083 /*
1084 CFWS            =       *([FWS] comment) (([FWS] comment) / FWS)
1085 */
1086
1087 int mailimf_cfws_parse(const char * message, size_t length,
1088                        size_t * index)
1089 {
1090   size_t cur_token;
1091   int has_comment;
1092   int r;
1093
1094   cur_token = * index;
1095
1096   has_comment = FALSE;
1097   while (1) {
1098     r = mailimf_cfws_fws_comment_parse(message, length, &cur_token);
1099     if (r != MAILIMF_NO_ERROR) {
1100       if (r == MAILIMF_ERROR_PARSE)
1101         break;
1102       else
1103         return r;
1104     }
1105     has_comment = TRUE;
1106   }
1107
1108   if (!has_comment) {
1109     r = mailimf_fws_parse(message, length, &cur_token);
1110     if (r != MAILIMF_NO_ERROR)
1111       return r;
1112   }
1113
1114   * index = cur_token;
1115
1116   return MAILIMF_NO_ERROR;
1117 }
1118
1119 /*
1120 atext           =       ALPHA / DIGIT / ; Any character except controls,
1121                         "!" / "#" /     ;  SP, and specials.
1122                         "$" / "%" /     ;  Used for atoms
1123                         "&" / "'" /
1124                         "*" / "+" /
1125                         "-" / "/" /
1126                         "=" / "?" /
1127                         "^" / "_" /
1128                         "`" / "{" /
1129                         "|" / "}" /
1130                         "~"
1131 */
1132
1133 static inline int is_atext(char ch)
1134 {
1135   switch (ch) {
1136   case ' ':
1137   case '\t':
1138   case '\n':
1139   case '\r':
1140 #if 0
1141   case '(':
1142   case ')':
1143 #endif
1144   case '<':
1145   case '>':
1146 #if 0
1147   case '@':
1148 #endif
1149   case ',':
1150   case '"':
1151   case ':':
1152   case ';':
1153     return FALSE;
1154   default:
1155     return TRUE;
1156   }
1157 }
1158
1159 /*
1160 atom            =       [CFWS] 1*atext [CFWS]
1161 */
1162
1163 int mailimf_atom_parse(const char * message, size_t length,
1164                        size_t * index, char ** result)
1165 {
1166   size_t cur_token;
1167   int r;
1168   int res;
1169   char * atom;
1170   size_t end;
1171
1172   cur_token = * index;
1173
1174   r = mailimf_cfws_parse(message, length, &cur_token);
1175   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
1176     res = r;
1177     goto err;
1178   }
1179   
1180   end = cur_token;
1181   if (end >= length) {
1182     res = MAILIMF_ERROR_PARSE;
1183     goto err;
1184   }
1185
1186   while (is_atext(message[end])) {
1187     end ++;
1188     if (end >= length)
1189       break;
1190   }
1191   if (end == cur_token) {
1192     res = MAILIMF_ERROR_PARSE;
1193     goto err;
1194   }
1195
1196   atom = malloc(end - cur_token + 1);
1197   if (atom == NULL) {
1198     res = MAILIMF_ERROR_MEMORY;
1199     goto err;
1200   }
1201   strncpy(atom, message + cur_token, end - cur_token);
1202   atom[end - cur_token] = '\0';
1203
1204   cur_token = end;
1205
1206   * index = cur_token;
1207   * result = atom;
1208
1209   return MAILIMF_NO_ERROR;
1210
1211  err:
1212   return res;
1213 }
1214
1215 int mailimf_fws_atom_parse(const char * message, size_t length,
1216                            size_t * index, char ** result)
1217 {
1218   size_t cur_token;
1219   int r;
1220   int res;
1221   char * atom;
1222   size_t end;
1223
1224   cur_token = * index;
1225
1226   r = mailimf_fws_parse(message, length, &cur_token);
1227   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
1228     res = r;
1229     goto err;
1230   }
1231
1232   end = cur_token;
1233   if (end >= length) {
1234     res = MAILIMF_ERROR_PARSE;
1235     goto err;
1236   }
1237
1238   while (is_atext(message[end])) {
1239     end ++;
1240     if (end >= length)
1241       break;
1242   }
1243   if (end == cur_token) {
1244     res = MAILIMF_ERROR_PARSE;
1245     goto err;
1246   }
1247
1248   atom = malloc(end - cur_token + 1);
1249   if (atom == NULL) {
1250     res = MAILIMF_ERROR_MEMORY;
1251     goto err;
1252   }
1253   strncpy(atom, message + cur_token, end - cur_token);
1254   atom[end - cur_token] = '\0';
1255
1256   cur_token = end;
1257
1258   * index = cur_token;
1259   * result = atom;
1260
1261   return MAILIMF_NO_ERROR;
1262
1263  err:
1264   return res;
1265 }
1266
1267 /*
1268 dot-atom        =       [CFWS] dot-atom-text [CFWS]
1269 */
1270
1271 #if 0
1272 static int mailimf_dot_atom_parse(const char * message, size_t length,
1273                                   size_t * index, char ** result)
1274 {
1275   return mailimf_atom_parse(message, length, index, result);
1276 }
1277 #endif
1278
1279 /*
1280 dot-atom-text   =       1*atext *("." 1*atext)
1281 */
1282
1283 #if 0
1284 static int
1285 mailimf_dot_atom_text_parse(const char * message, size_t length,
1286                             size_t * index, char ** result)
1287 {
1288   return mailimf_atom_parse(message, length, index, result);
1289 }
1290 #endif
1291
1292 /*
1293 qtext           =       NO-WS-CTL /     ; Non white space controls
1294
1295                         %d33 /          ; The rest of the US-ASCII
1296                         %d35-91 /       ;  characters not including "\"
1297                         %d93-126        ;  or the quote character
1298 */
1299
1300 static inline int is_qtext(char ch)
1301 {
1302   unsigned char uch = (unsigned char) ch;
1303
1304   if (is_no_ws_ctl(ch))
1305     return TRUE;
1306
1307   if (uch < 33)
1308     return FALSE;
1309
1310   if (uch == 34)
1311     return FALSE;
1312
1313   if (uch == 92)
1314     return FALSE;
1315
1316   if (uch == 127)
1317     return FALSE;
1318
1319   return TRUE;
1320 }
1321
1322 /*
1323 qcontent        =       qtext / quoted-pair
1324 */
1325
1326 static int mailimf_qcontent_parse(const char * message, size_t length,
1327                                   size_t * index, char * result)
1328 {
1329   size_t cur_token;
1330   char ch;
1331   int r;
1332
1333   cur_token = * index;
1334
1335   if (cur_token >= length)
1336     return MAILIMF_ERROR_PARSE;
1337
1338   if (is_qtext(message[cur_token])) {
1339     ch = message[cur_token];
1340     cur_token ++;
1341   }
1342   else {
1343     r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
1344     
1345     if (r != MAILIMF_NO_ERROR)
1346       return r;
1347   }
1348   
1349   * result = ch;
1350   * index = cur_token;
1351
1352   return MAILIMF_NO_ERROR;
1353 }
1354
1355 /*
1356 quoted-string   =       [CFWS]
1357                         DQUOTE *([FWS] qcontent) [FWS] DQUOTE
1358                         [CFWS]
1359 */
1360
1361 int mailimf_quoted_string_parse(const char * message, size_t length,
1362                                 size_t * index, char ** result)
1363 {
1364   size_t cur_token;
1365   MMAPString * gstr;
1366   char ch;
1367   char * str;
1368   int r;
1369   int res;
1370
1371   cur_token = * index;
1372
1373   r = mailimf_cfws_parse(message, length, &cur_token);
1374   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
1375     res = r;
1376     goto err;
1377   }
1378
1379   r = mailimf_dquote_parse(message, length, &cur_token);
1380   if (r != MAILIMF_NO_ERROR) {
1381     res = r;
1382     goto err;
1383   }
1384
1385   gstr = mmap_string_new("");
1386   if (gstr == NULL) {
1387     res = MAILIMF_ERROR_MEMORY;
1388     goto err;
1389   }
1390
1391 #if 0
1392   if (mmap_string_append_c(gstr, '\"') == NULL) {
1393     res = MAILIMF_ERROR_MEMORY;
1394     goto free_gstr;
1395   }
1396 #endif
1397
1398   while (1) {
1399     r = mailimf_fws_parse(message, length, &cur_token);
1400     if (r == MAILIMF_NO_ERROR) {
1401       if (mmap_string_append_c(gstr, ' ') == NULL) {
1402         res = MAILIMF_ERROR_MEMORY;
1403         goto free_gstr;
1404       }
1405     }
1406     else if (r != MAILIMF_ERROR_PARSE) {
1407       res = r;
1408       goto free_gstr;
1409     }
1410
1411     r = mailimf_qcontent_parse(message, length, &cur_token, &ch);
1412     if (r == MAILIMF_NO_ERROR) {
1413       if (mmap_string_append_c(gstr, ch) == NULL) {
1414         res = MAILIMF_ERROR_MEMORY;
1415         goto free_gstr;
1416       }
1417     }
1418     else if (r == MAILIMF_ERROR_PARSE)
1419       break;
1420     else {
1421       res = r;
1422       goto free_gstr;
1423     }
1424   }
1425
1426   r = mailimf_dquote_parse(message, length, &cur_token);
1427   if (r != MAILIMF_NO_ERROR) {
1428     res = r;
1429     goto free_gstr;
1430   }
1431
1432 #if 0
1433   if (mmap_string_append_c(gstr, '\"') == NULL) {
1434     res = MAILIMF_ERROR_MEMORY;
1435     goto free_gstr;
1436   }
1437 #endif
1438
1439   str = strdup(gstr->str);
1440   if (str == NULL) {
1441     res = MAILIMF_ERROR_MEMORY;
1442     goto free_gstr;
1443   }
1444   mmap_string_free(gstr);
1445
1446   * index = cur_token;
1447   * result = str;
1448
1449   return MAILIMF_NO_ERROR;
1450
1451  free_gstr:
1452   mmap_string_free(gstr);
1453  err:
1454   return res;
1455 }
1456
1457 int mailimf_fws_quoted_string_parse(const char * message, size_t length,
1458                                     size_t * index, char ** result)
1459 {
1460   size_t cur_token;
1461   MMAPString * gstr;
1462   char ch;
1463   char * str;
1464   int r;
1465   int res;
1466
1467   cur_token = * index;
1468
1469   r = mailimf_fws_parse(message, length, &cur_token);
1470   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
1471     res = r;
1472     goto err;
1473   }
1474
1475   r = mailimf_dquote_parse(message, length, &cur_token);
1476   if (r != MAILIMF_NO_ERROR) {
1477     res = r;
1478     goto err;
1479   }
1480
1481   gstr = mmap_string_new("");
1482   if (gstr == NULL) {
1483     res = MAILIMF_ERROR_MEMORY;
1484     goto err;
1485   }
1486
1487 #if 0
1488   if (mmap_string_append_c(gstr, '\"') == NULL) {
1489     res = MAILIMF_ERROR_MEMORY;
1490     goto free_gstr;
1491   }
1492 #endif
1493
1494   while (1) {
1495     r = mailimf_fws_parse(message, length, &cur_token);
1496     if (r == MAILIMF_NO_ERROR) {
1497       if (mmap_string_append_c(gstr, ' ') == NULL) {
1498         res = MAILIMF_ERROR_MEMORY;
1499         goto free_gstr;
1500       }
1501     }
1502     else if (r != MAILIMF_ERROR_PARSE) {
1503       res = r;
1504       goto free_gstr;
1505     }
1506
1507     r = mailimf_qcontent_parse(message, length, &cur_token, &ch);
1508     if (r == MAILIMF_NO_ERROR) {
1509       if (mmap_string_append_c(gstr, ch) == NULL) {
1510         res = MAILIMF_ERROR_MEMORY;
1511         goto free_gstr;
1512       }
1513     }
1514     else if (r == MAILIMF_ERROR_PARSE)
1515       break;
1516     else {
1517       res = r;
1518       goto free_gstr;
1519     }
1520   }
1521
1522   r = mailimf_dquote_parse(message, length, &cur_token);
1523   if (r != MAILIMF_NO_ERROR) {
1524     res = r;
1525     goto free_gstr;
1526   }
1527
1528 #if 0
1529   if (mmap_string_append_c(gstr, '\"') == NULL) {
1530     res = MAILIMF_ERROR_MEMORY;
1531     goto free_gstr;
1532   }
1533 #endif
1534
1535   str = strdup(gstr->str);
1536   if (str == NULL) {
1537     res = MAILIMF_ERROR_MEMORY;
1538     goto free_gstr;
1539   }
1540   mmap_string_free(gstr);
1541
1542   * index = cur_token;
1543   * result = str;
1544
1545   return MAILIMF_NO_ERROR;
1546
1547  free_gstr:
1548   mmap_string_free(gstr);
1549  err:
1550   return res;
1551 }
1552
1553 /*
1554 word            =       atom / quoted-string
1555 */
1556
1557 int mailimf_word_parse(const char * message, size_t length,
1558                        size_t * index, char ** result)
1559 {
1560   size_t cur_token;
1561   char * word;
1562   int r;
1563
1564   cur_token = * index;
1565
1566   r = mailimf_atom_parse(message, length, &cur_token, &word);
1567
1568   if (r == MAILIMF_ERROR_PARSE)
1569     r = mailimf_quoted_string_parse(message, length, &cur_token, &word);
1570
1571   if (r != MAILIMF_NO_ERROR)
1572     return r;
1573
1574   * result = word;
1575   * index = cur_token;
1576
1577   return MAILIMF_NO_ERROR;
1578 }
1579
1580 int mailimf_fws_word_parse(const char * message, size_t length,
1581                            size_t * index, char ** result)
1582 {
1583   size_t cur_token;
1584   char * word;
1585   int r;
1586
1587   cur_token = * index;
1588
1589   r = mailimf_fws_atom_parse(message, length, &cur_token, &word);
1590
1591   if (r == MAILIMF_ERROR_PARSE)
1592     r = mailimf_fws_quoted_string_parse(message, length, &cur_token, &word);
1593
1594   if (r != MAILIMF_NO_ERROR)
1595     return r;
1596
1597   * result = word;
1598   * index = cur_token;
1599
1600   return MAILIMF_NO_ERROR;
1601 }
1602
1603 /*
1604 phrase          =       1*word / obs-phrase
1605 */
1606
1607 static int mailimf_phrase_parse(const char * message, size_t length,
1608                                 size_t * index, char ** result)
1609 {
1610   MMAPString * gphrase;
1611   char * word;
1612   int first;
1613   size_t cur_token;
1614   int r;
1615   int res;
1616   char * str;
1617
1618   cur_token = * index;
1619
1620   gphrase = mmap_string_new("");
1621   if (gphrase == NULL) {
1622     res = MAILIMF_ERROR_MEMORY;
1623     goto err;
1624   }
1625
1626   first = TRUE;
1627
1628   while (1) {
1629     r = mailimf_fws_word_parse(message, length, &cur_token, &word);
1630     if (r == MAILIMF_NO_ERROR) {
1631       if (!first) {
1632         if (mmap_string_append_c(gphrase, ' ') == NULL) {
1633           mailimf_word_free(word);
1634           res = MAILIMF_ERROR_MEMORY;
1635           goto free;
1636         }
1637       }
1638       if (mmap_string_append(gphrase, word) == NULL) {
1639         mailimf_word_free(word);
1640         res = MAILIMF_ERROR_MEMORY;
1641         goto free;
1642       }
1643       mailimf_word_free(word);
1644       first = FALSE;
1645     }
1646     else if (r == MAILIMF_ERROR_PARSE)
1647       break;
1648     else {
1649       res = r;
1650       goto free;
1651     }
1652   }
1653
1654   if (first) {
1655     res = MAILIMF_ERROR_PARSE;
1656     goto free;
1657   }
1658
1659   str = strdup(gphrase->str);
1660   if (str == NULL) {
1661     res = MAILIMF_ERROR_MEMORY;
1662     goto free;
1663   }
1664   mmap_string_free(gphrase);
1665
1666   * result = str;
1667   * index = cur_token;
1668
1669   return MAILIMF_NO_ERROR;
1670
1671  free:
1672   mmap_string_free(gphrase);
1673  err:
1674   return res;
1675 }
1676
1677 /*
1678 utext           =       NO-WS-CTL /     ; Non white space controls
1679                         %d33-126 /      ; The rest of US-ASCII
1680                         obs-utext
1681
1682 added : WSP
1683 */
1684
1685 enum {
1686   UNSTRUCTURED_START,
1687   UNSTRUCTURED_CR,
1688   UNSTRUCTURED_LF,
1689   UNSTRUCTURED_WSP,
1690   UNSTRUCTURED_OUT
1691 };
1692
1693 static int mailimf_unstructured_parse(const char * message, size_t length,
1694                                       size_t * index, char ** result)
1695 {
1696   size_t cur_token;
1697   int state;
1698   size_t begin;
1699   size_t terminal;
1700   char * str;
1701
1702   cur_token = * index;
1703
1704
1705   while (1) {
1706     int r;
1707
1708     r = mailimf_wsp_parse(message, length, &cur_token);
1709     if (r == MAILIMF_NO_ERROR) {
1710       /* do nothing */
1711     }
1712     else if (r == MAILIMF_ERROR_PARSE)
1713       break;
1714     else {
1715       return r;
1716     }
1717   }
1718
1719   state = UNSTRUCTURED_START;
1720   begin = cur_token;
1721   terminal = cur_token;
1722
1723   while (state != UNSTRUCTURED_OUT) {
1724
1725     switch(state) {
1726     case UNSTRUCTURED_START:
1727       if (cur_token >= length)
1728         return MAILIMF_ERROR_PARSE;
1729
1730       terminal = cur_token;
1731       switch(message[cur_token]) {
1732       case '\r':
1733         state = UNSTRUCTURED_CR;
1734         break;
1735       case '\n':
1736         state = UNSTRUCTURED_LF;
1737         break;
1738       default:
1739         state = UNSTRUCTURED_START;
1740         break;
1741       }
1742       break;
1743     case UNSTRUCTURED_CR:
1744       if (cur_token >= length)
1745         return MAILIMF_ERROR_PARSE;
1746
1747       switch(message[cur_token]) {
1748       case '\n':
1749         state = UNSTRUCTURED_LF;
1750         break;
1751       default:
1752         state = UNSTRUCTURED_START;
1753         break;
1754       }
1755       break;
1756
1757     case UNSTRUCTURED_LF:
1758       if (cur_token >= length) {
1759         state = UNSTRUCTURED_OUT;
1760         break;
1761       }
1762
1763       switch(message[cur_token]) {
1764       case '\t':
1765       case ' ':
1766         state = UNSTRUCTURED_WSP;
1767         break;
1768       default:
1769         state = UNSTRUCTURED_OUT;
1770         break;
1771       }
1772       break;
1773     case UNSTRUCTURED_WSP:
1774       if (cur_token >= length)
1775         return MAILIMF_ERROR_PARSE;
1776
1777       switch(message[cur_token]) {
1778       case '\r':
1779         state = UNSTRUCTURED_CR;
1780         break;
1781       case '\n':
1782         state = UNSTRUCTURED_LF;
1783         break;
1784       default:
1785         state = UNSTRUCTURED_START;
1786         break;
1787       }
1788       break;
1789     }
1790
1791     cur_token ++;
1792   }
1793
1794   str = malloc(terminal - begin + 1);
1795   if (str == NULL)
1796     return MAILIMF_ERROR_MEMORY;
1797   strncpy(str, message + begin,  terminal - begin);
1798   str[terminal - begin] = '\0';
1799
1800   * index = terminal;
1801   * result = str;
1802
1803   return MAILIMF_NO_ERROR;
1804 }
1805
1806
1807 static int mailimf_ignore_unstructured_parse(const char * message, size_t length,
1808                                              size_t * index)
1809 {
1810   size_t cur_token;
1811   int state;
1812   size_t terminal;
1813
1814   cur_token = * index;
1815
1816   state = UNSTRUCTURED_START;
1817   terminal = cur_token;
1818
1819   while (state != UNSTRUCTURED_OUT) {
1820
1821     switch(state) {
1822     case UNSTRUCTURED_START:
1823       if (cur_token >= length)
1824         return MAILIMF_ERROR_PARSE;
1825       terminal = cur_token;
1826       switch(message[cur_token]) {
1827       case '\r':
1828         state = UNSTRUCTURED_CR;
1829         break;
1830       case '\n':
1831         state = UNSTRUCTURED_LF;
1832         break;
1833       default:
1834         state = UNSTRUCTURED_START;
1835         break;
1836       }
1837       break;
1838     case UNSTRUCTURED_CR:
1839       if (cur_token >= length)
1840         return MAILIMF_ERROR_PARSE;
1841       switch(message[cur_token]) {
1842       case '\n':
1843         state = UNSTRUCTURED_LF;
1844         break;
1845       default:
1846         state = UNSTRUCTURED_START;
1847         break;
1848       }
1849       break;
1850     case UNSTRUCTURED_LF:
1851       if (cur_token >= length) {
1852         state = UNSTRUCTURED_OUT;
1853         break;
1854       }
1855       switch(message[cur_token]) {
1856       case '\t':
1857       case ' ':
1858         state = UNSTRUCTURED_WSP;
1859         break;
1860       default:
1861         state = UNSTRUCTURED_OUT;
1862         break;
1863       }
1864       break;
1865     case UNSTRUCTURED_WSP:
1866       if (cur_token >= length)
1867         return MAILIMF_ERROR_PARSE;
1868       switch(message[cur_token]) {
1869       case '\r':
1870         state = UNSTRUCTURED_CR;
1871         break;
1872       case '\n':
1873         state = UNSTRUCTURED_LF;
1874         break;
1875       default:
1876         state = UNSTRUCTURED_START;
1877         break;
1878       }
1879       break;
1880     }
1881
1882     cur_token ++;
1883   }
1884
1885   * index = terminal;
1886
1887   return MAILIMF_NO_ERROR;
1888 }
1889
1890
1891 int mailimf_ignore_field_parse(const char * message, size_t length,
1892                                size_t * index)
1893 {
1894   int has_field;
1895   size_t cur_token;
1896   int state;
1897   size_t terminal;
1898
1899   has_field = FALSE;
1900   cur_token = * index;
1901
1902   terminal = cur_token;
1903   state = UNSTRUCTURED_START;
1904
1905   /* check if this is not a beginning CRLF */
1906
1907   if (cur_token >= length)
1908     return MAILIMF_ERROR_PARSE;
1909
1910   switch (message[cur_token]) {
1911   case '\r':
1912     return MAILIMF_ERROR_PARSE;
1913   case '\n':
1914     return MAILIMF_ERROR_PARSE;
1915   }
1916
1917   while (state != UNSTRUCTURED_OUT) {
1918
1919     switch(state) {
1920     case UNSTRUCTURED_START:
1921       if (cur_token >= length)
1922         return MAILIMF_ERROR_PARSE;
1923
1924       switch(message[cur_token]) {
1925       case '\r':
1926         state = UNSTRUCTURED_CR;
1927         break;
1928       case '\n':
1929         state = UNSTRUCTURED_LF;
1930         break;
1931       case ':':
1932         has_field = TRUE;
1933         state = UNSTRUCTURED_START;
1934         break;
1935       default:
1936         state = UNSTRUCTURED_START;
1937         break;
1938       }
1939       break;
1940     case UNSTRUCTURED_CR:
1941       if (cur_token >= length)
1942         return MAILIMF_ERROR_PARSE;
1943
1944       switch(message[cur_token]) {
1945       case '\n':
1946         state = UNSTRUCTURED_LF;
1947         break;
1948       case ':':
1949         has_field = TRUE;
1950         state = UNSTRUCTURED_START;
1951         break;
1952       default:
1953         state = UNSTRUCTURED_START;
1954         break;
1955       }
1956       break;
1957     case UNSTRUCTURED_LF:
1958       if (cur_token >= length) {
1959         terminal = cur_token;
1960         state = UNSTRUCTURED_OUT;
1961         break;
1962       }
1963
1964       switch(message[cur_token]) {
1965       case '\t':
1966       case ' ':
1967         state = UNSTRUCTURED_WSP;
1968         break;
1969       default:
1970         terminal = cur_token;
1971         state = UNSTRUCTURED_OUT;
1972         break;
1973       }
1974       break;
1975     case UNSTRUCTURED_WSP:
1976       if (cur_token >= length)
1977         return MAILIMF_ERROR_PARSE;
1978
1979       switch(message[cur_token]) {
1980       case '\r':
1981         state = UNSTRUCTURED_CR;
1982         break;
1983       case '\n':
1984         state = UNSTRUCTURED_LF;
1985         break;
1986       case ':':
1987         has_field = TRUE;
1988         state = UNSTRUCTURED_START;
1989         break;
1990       default:
1991         state = UNSTRUCTURED_START;
1992         break;
1993       }
1994       break;
1995     }
1996
1997     cur_token ++;
1998   }
1999
2000   if (!has_field)
2001     return MAILIMF_ERROR_PARSE;
2002
2003   * index = terminal;
2004
2005   return MAILIMF_NO_ERROR;
2006 }
2007
2008
2009 /*
2010 date-time       =       [ day-of-week "," ] date FWS time [CFWS]
2011 */
2012
2013 int mailimf_date_time_parse(const char * message, size_t length,
2014                             size_t * index,
2015                             struct mailimf_date_time ** result)
2016 {
2017   size_t cur_token;
2018   int day_of_week;
2019   struct mailimf_date_time * date_time;
2020   int day;
2021   int month;
2022   int year;
2023   int hour;
2024   int min;
2025   int sec;
2026   int zone;
2027   int r;
2028
2029   cur_token = * index;
2030
2031   day_of_week = -1;
2032   r = mailimf_day_of_week_parse(message, length, &cur_token, &day_of_week);
2033   if (r == MAILIMF_NO_ERROR) {
2034     r = mailimf_comma_parse(message, length, &cur_token);
2035     if (r != MAILIMF_NO_ERROR)
2036       return r;
2037   }
2038   else if (r != MAILIMF_ERROR_PARSE)
2039     return r;
2040
2041   r = mailimf_date_parse(message, length, &cur_token, &day, &month, &year);
2042   if (r != MAILIMF_NO_ERROR)
2043     return r;
2044
2045   r = mailimf_fws_parse(message, length, &cur_token);
2046   if (r != MAILIMF_NO_ERROR)
2047     return r;
2048
2049   r = mailimf_time_parse(message, length, &cur_token,
2050                          &hour, &min, &sec, &zone);
2051   if (r != MAILIMF_NO_ERROR)
2052     return r;
2053
2054   date_time = mailimf_date_time_new(day, month, year, hour, min, sec, zone);
2055   if (date_time == NULL)
2056     return MAILIMF_ERROR_MEMORY;
2057
2058   * index = cur_token;
2059   * result = date_time;
2060
2061   return MAILIMF_NO_ERROR;
2062 }
2063
2064 /*
2065 day-of-week     =       ([FWS] day-name) / obs-day-of-week
2066 */
2067
2068 static int mailimf_day_of_week_parse(const char * message, size_t length,
2069                                      size_t * index, int * result)
2070 {
2071   size_t cur_token;
2072   int day_of_week;
2073   int r;
2074
2075   cur_token = * index;
2076
2077   r = mailimf_cfws_parse(message, length, &cur_token);
2078   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
2079     return r;
2080
2081   r = mailimf_day_name_parse(message, length, &cur_token, &day_of_week);
2082   if (r != MAILIMF_NO_ERROR)
2083     return r;
2084
2085   * index = cur_token;
2086   * result = day_of_week;
2087
2088   return MAILIMF_NO_ERROR;
2089 }
2090
2091 /*
2092 day-name        =       "Mon" / "Tue" / "Wed" / "Thu" /
2093                         "Fri" / "Sat" / "Sun"
2094 */
2095
2096 struct mailimf_token_value {
2097   int value;
2098   char * str;
2099 };
2100
2101 static struct mailimf_token_value day_names[] = {
2102   {1, "Mon"},
2103   {2, "Tue"},
2104   {3, "Wed"},
2105   {4, "Thu"},
2106   {5, "Fri"},
2107   {6, "Sat"},
2108   {7, "Sun"},
2109 };
2110
2111 enum {
2112   DAY_NAME_START,
2113   DAY_NAME_T,
2114   DAY_NAME_S
2115 };
2116
2117 static int guess_day_name(const char * message, size_t length, size_t index)
2118 {
2119   int state;
2120
2121   state = DAY_NAME_START;
2122
2123   while (1) {
2124
2125     if (index >= length)
2126       return -1;
2127
2128     switch(state) {
2129     case DAY_NAME_START:
2130       switch((char) toupper((unsigned char) message[index])) {
2131       case 'M': /* Mon */
2132         return 1;
2133         break;
2134       case 'T': /* Tue Thu */
2135         state = DAY_NAME_T;
2136         break;
2137       case 'W': /* Wed */
2138         return 3;
2139       case 'F':
2140         return 5;
2141       case 'S': /* Sat Sun */
2142         state = DAY_NAME_S;
2143         break;
2144       default:
2145         return -1;
2146       }
2147       break;
2148     case DAY_NAME_T:
2149       switch((char) toupper((unsigned char) message[index])) {
2150       case 'U':
2151         return 2;
2152       case 'H':
2153         return 4;
2154       default:
2155         return -1;
2156       }
2157       break;
2158     case DAY_NAME_S:
2159       switch((char) toupper((unsigned char) message[index])) {
2160       case 'A':
2161         return 6;
2162       case 'U':
2163         return 7;
2164       default:
2165         return -1;
2166       }
2167       break;
2168     }
2169
2170     index ++;
2171   }
2172 }
2173
2174 static int mailimf_day_name_parse(const char * message, size_t length,
2175                                   size_t * index, int * result)
2176 {
2177   size_t cur_token;
2178   int day_of_week;
2179   int guessed_day;
2180   int r;
2181
2182   cur_token = * index;
2183
2184   guessed_day = guess_day_name(message, length, cur_token);
2185   if (guessed_day == -1)
2186     return MAILIMF_ERROR_PARSE;
2187
2188   r = mailimf_token_case_insensitive_parse(message, length,
2189                                            &cur_token,
2190                                            day_names[guessed_day - 1].str);
2191   if (r != MAILIMF_NO_ERROR)
2192     return r;
2193
2194   day_of_week = guessed_day;
2195
2196   * result = day_of_week;
2197   * index = cur_token;
2198
2199   return MAILIMF_NO_ERROR;
2200 }
2201
2202 /*
2203 date            =       day month year
2204 */
2205
2206 static int mailimf_date_parse(const char * message, size_t length,
2207                               size_t * index,
2208                               int * pday, int * pmonth, int * pyear)
2209 {
2210   size_t cur_token;
2211   int day;
2212   int month;
2213   int year;
2214   int r;
2215
2216   cur_token = * index;
2217
2218   r = mailimf_day_parse(message, length, &cur_token, &day);
2219   if (r != MAILIMF_NO_ERROR)
2220     return r;
2221
2222   r = mailimf_month_parse(message, length, &cur_token, &month);
2223   if (r != MAILIMF_NO_ERROR)
2224     return r;
2225
2226   r = mailimf_year_parse(message, length, &cur_token, &year);
2227   if (r != MAILIMF_NO_ERROR)
2228     return r;
2229
2230   * pday = day;
2231   * pmonth = month;
2232   * pyear = year;
2233
2234   * index = cur_token;
2235
2236   return MAILIMF_NO_ERROR;
2237 }
2238
2239 /*
2240 year            =       4*DIGIT / obs-year
2241 */
2242
2243 static int mailimf_year_parse(const char * message, size_t length,
2244                               size_t * index, int * result)
2245 {
2246   uint32_t number;
2247   size_t cur_token;
2248   int r;
2249
2250   cur_token = * index;
2251
2252   r = mailimf_cfws_parse(message, length, &cur_token);
2253   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
2254     return r;
2255
2256   r = mailimf_number_parse(message, length, &cur_token, &number);
2257   if (r != MAILIMF_NO_ERROR)
2258     return r;
2259
2260   * index = cur_token;
2261   * result = number;
2262
2263   return MAILIMF_NO_ERROR;
2264 }
2265
2266 /*
2267 month           =       (FWS month-name FWS) / obs-month
2268 */
2269
2270 static int mailimf_month_parse(const char * message, size_t length,
2271                                size_t * index, int * result)
2272 {
2273   size_t cur_token;
2274   int month;
2275   int r;
2276
2277   cur_token = * index;
2278
2279   r = mailimf_cfws_parse(message, length, &cur_token);
2280   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
2281     return r;
2282
2283   r = mailimf_month_name_parse(message, length, &cur_token, &month);
2284   if (r != MAILIMF_NO_ERROR)
2285     return r;
2286
2287   * result = month;
2288   * index = cur_token;
2289
2290   return MAILIMF_NO_ERROR;
2291 }
2292
2293 /*
2294 month-name      =       "Jan" / "Feb" / "Mar" / "Apr" /
2295                         "May" / "Jun" / "Jul" / "Aug" /
2296                         "Sep" / "Oct" / "Nov" / "Dec"
2297 */
2298
2299 static struct mailimf_token_value month_names[] = {
2300   {1, "Jan"},
2301   {2, "Feb"},
2302   {3, "Mar"},
2303   {4, "Apr"},
2304   {5, "May"},
2305   {6, "Jun"},
2306   {7, "Jul"},
2307   {8, "Aug"},
2308   {9, "Sep"},
2309   {10, "Oct"},
2310   {11, "Nov"},
2311   {12, "Dec"},
2312 };
2313
2314 enum {
2315   MONTH_START,
2316   MONTH_J,
2317   MONTH_JU,
2318   MONTH_M,
2319   MONTH_MA,
2320   MONTH_A
2321 };
2322
2323 static int guess_month(const char * message, size_t length, size_t index)
2324 {
2325   int state;
2326
2327   state = MONTH_START;
2328
2329   while (1) {
2330
2331     if (index >= length)
2332       return -1;
2333
2334     switch(state) {
2335     case MONTH_START:
2336       switch((char) toupper((unsigned char) message[index])) {
2337       case 'J': /* Jan Jun Jul */
2338         state = MONTH_J;
2339         break;
2340       case 'F': /* Feb */
2341         return 2;
2342       case 'M': /* Mar May */
2343         state = MONTH_M;
2344         break;
2345       case 'A': /* Apr Aug */
2346         state = MONTH_A;
2347         break;
2348       case 'S': /* Sep */
2349         return 9;
2350       case 'O': /* Oct */
2351         return 10;
2352       case 'N': /* Nov */
2353         return 11;
2354       case 'D': /* Dec */
2355         return 12;
2356       default:
2357         return -1;
2358       }
2359       break;
2360     case MONTH_J:
2361       switch((char) toupper((unsigned char) message[index])) {
2362       case 'A':
2363         return 1;
2364       case 'U':
2365         state = MONTH_JU;
2366         break;
2367       default:
2368         return -1;
2369       }
2370       break;
2371     case MONTH_JU:
2372       switch((char) toupper((unsigned char) message[index])) {
2373       case 'N':
2374         return 6;
2375       case 'L':
2376         return 7;
2377       default:
2378         return -1;
2379       }
2380       break;
2381     case MONTH_M:
2382       switch((char) toupper((unsigned char) message[index])) {
2383       case 'A':
2384         state = MONTH_MA;
2385         break;
2386       default:
2387         return -1;
2388       }
2389       break;
2390     case MONTH_MA:
2391       switch((char) toupper((unsigned char) message[index])) {
2392       case 'Y':
2393         return 5;
2394       case 'R':
2395         return 3;
2396       default:
2397         return -1;
2398       }
2399       break;
2400     case MONTH_A:
2401       switch((char) toupper((unsigned char) message[index])) {
2402       case 'P':
2403         return 4;
2404       case 'U':
2405         return 8;
2406       default:
2407         return -1;
2408       }
2409       break;
2410     }
2411
2412     index ++;
2413   }
2414 }
2415
2416 static int mailimf_month_name_parse(const char * message, size_t length,
2417                                     size_t * index, int * result)
2418 {
2419   size_t cur_token;
2420   int month;
2421   int guessed_month;
2422   int r;
2423
2424   cur_token = * index;
2425
2426   guessed_month = guess_month(message, length, cur_token);
2427   if (guessed_month == -1)
2428     return MAILIMF_ERROR_PARSE;
2429
2430   r = mailimf_token_case_insensitive_parse(message, length,
2431                                            &cur_token,
2432                                            month_names[guessed_month - 1].str);
2433   if (r != MAILIMF_NO_ERROR)
2434     return r;
2435
2436   month = guessed_month;
2437
2438   * result = month;
2439   * index = cur_token;
2440
2441   return MAILIMF_NO_ERROR;
2442 }
2443
2444 /*
2445 day             =       ([FWS] 1*2DIGIT) / obs-day
2446 */
2447
2448 static int mailimf_day_parse(const char * message, size_t length,
2449                              size_t * index, int * result)
2450 {
2451   size_t cur_token;
2452   uint32_t day;
2453   int r;
2454
2455   cur_token = * index;
2456
2457   r = mailimf_cfws_parse(message, length, &cur_token);
2458   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
2459     return r;
2460
2461   r = mailimf_number_parse(message, length, &cur_token, &day);
2462   if (r != MAILIMF_NO_ERROR)
2463     return r;
2464
2465   * result = day;
2466   * index = cur_token;
2467
2468   return MAILIMF_NO_ERROR;
2469 }
2470
2471 /*
2472 time            =       time-of-day FWS zone
2473 */
2474
2475 static int mailimf_time_parse(const char * message, size_t length,
2476                               size_t * index, 
2477                               int * phour, int * pmin,
2478                               int * psec,
2479                               int * pzone)
2480 {
2481   size_t cur_token;
2482   int hour;
2483   int min;
2484   int sec;
2485   int zone;
2486   int r;
2487
2488   cur_token = * index;
2489
2490   r = mailimf_cfws_parse(message, length, &cur_token);
2491   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
2492     return r;
2493
2494   r = mailimf_time_of_day_parse(message, length, &cur_token,
2495                                 &hour, &min, &sec);
2496   if (r != MAILIMF_NO_ERROR)
2497     return r;
2498
2499   r = mailimf_fws_parse(message, length, &cur_token);
2500   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
2501     return r;
2502
2503   r = mailimf_zone_parse(message, length, &cur_token, &zone);
2504   if (r == MAILIMF_NO_ERROR) {
2505     /* do nothing */
2506   }
2507   else if (r == MAILIMF_ERROR_PARSE) {
2508     zone = 0;
2509   }
2510   else {
2511     return r;
2512   }
2513
2514   * phour = hour;
2515   * pmin = min;
2516   * psec = sec;
2517   * pzone = zone;
2518
2519   * index = cur_token;
2520
2521   return MAILIMF_NO_ERROR;
2522 }
2523
2524 /*
2525 time-of-day     =       hour ":" minute [ ":" second ]
2526 */
2527
2528 static int mailimf_time_of_day_parse(const char * message, size_t length,
2529                                      size_t * index,
2530                                      int * phour, int * pmin,
2531                                      int * psec)
2532 {
2533   int hour;
2534   int min;
2535   int sec;
2536   size_t cur_token;
2537   int r;
2538
2539   cur_token = * index;
2540
2541   r = mailimf_hour_parse(message, length, &cur_token, &hour);
2542   if (r != MAILIMF_NO_ERROR)
2543     return r;
2544
2545   r = mailimf_colon_parse(message, length, &cur_token);
2546   if (r != MAILIMF_NO_ERROR)
2547     return r;
2548
2549   r = mailimf_minute_parse(message, length, &cur_token, &min);
2550   if (r != MAILIMF_NO_ERROR)
2551     return r;
2552
2553   r = mailimf_colon_parse(message, length, &cur_token);
2554   if (r == MAILIMF_NO_ERROR) {
2555     r = mailimf_second_parse(message, length, &cur_token, &sec);
2556     if (r != MAILIMF_NO_ERROR)
2557       return r;
2558   }
2559   else if (r == MAILIMF_ERROR_PARSE)
2560     sec = 0;
2561   else
2562     return r;
2563
2564   * phour = hour;
2565   * pmin = min;
2566   * psec = sec;
2567   * index = cur_token;
2568
2569   return MAILIMF_NO_ERROR;
2570 }
2571
2572 /*
2573 hour            =       2DIGIT / obs-hour
2574 */
2575
2576 static int mailimf_hour_parse(const char * message, size_t length,
2577                               size_t * index, int * result)
2578 {
2579   uint32_t hour;
2580   int r;
2581
2582   r = mailimf_number_parse(message, length, index, &hour);
2583   if (r != MAILIMF_NO_ERROR)
2584     return r;
2585
2586   * result = hour;
2587
2588   return MAILIMF_NO_ERROR;
2589 }
2590
2591 /*
2592 minute          =       2DIGIT / obs-minute
2593 */
2594
2595 static int mailimf_minute_parse(const char * message, size_t length,
2596                                 size_t * index, int * result)
2597 {
2598   uint32_t minute;
2599   int r;
2600
2601   r = mailimf_number_parse(message, length, index, &minute);
2602   if (r != MAILIMF_NO_ERROR)
2603     return r;
2604
2605   * result = minute;
2606
2607   return MAILIMF_NO_ERROR;
2608 }
2609
2610 /*
2611 second          =       2DIGIT / obs-second
2612 */
2613
2614 static int mailimf_second_parse(const char * message, size_t length,
2615                                 size_t * index, int * result)
2616 {
2617   uint32_t second;
2618   int r;
2619
2620   r = mailimf_number_parse(message, length, index, &second);
2621   if (r != MAILIMF_NO_ERROR)
2622     return r;
2623
2624   * result = second;
2625
2626   return MAILIMF_NO_ERROR;
2627 }
2628
2629 /*
2630 zone            =       (( "+" / "-" ) 4DIGIT) / obs-zone
2631 */
2632
2633 /*
2634 obs-zone        =       "UT" / "GMT" /          ; Universal Time
2635                                                 ; North American UT
2636                                                 ; offsets
2637                         "EST" / "EDT" /         ; Eastern:  - 5/ - 4
2638                         "CST" / "CDT" /         ; Central:  - 6/ - 5
2639                         "MST" / "MDT" /         ; Mountain: - 7/ - 6
2640                         "PST" / "PDT" /         ; Pacific:  - 8/ - 7
2641
2642                         %d65-73 /               ; Military zones - "A"
2643                         %d75-90 /               ; through "I" and "K"
2644                         %d97-105 /              ; through "Z", both
2645                         %d107-122               ; upper and lower case
2646 */
2647
2648 enum {
2649   STATE_ZONE_1 = 0,
2650   STATE_ZONE_2 = 1,
2651   STATE_ZONE_3 = 2,
2652   STATE_ZONE_OK  = 3,
2653   STATE_ZONE_ERR = 4,
2654   STATE_ZONE_CONT = 5,
2655 };
2656
2657 static int mailimf_zone_parse(const char * message, size_t length,
2658                               size_t * index, int * result)
2659 {
2660   uint32_t zone;
2661   int sign;
2662   size_t cur_token;
2663   int r;
2664
2665   cur_token = * index;
2666
2667   if (cur_token + 1 < length) {
2668     if ((message[cur_token] == 'U') && (message[cur_token + 1] == 'T')) {
2669       * result = TRUE;
2670       * index = cur_token + 2;
2671
2672       return MAILIMF_NO_ERROR;
2673     }
2674   }
2675
2676   if (cur_token + 2 < length) {
2677     int state;
2678
2679     state = STATE_ZONE_1;
2680     
2681     while (state <= 2) {
2682       switch (state) {
2683       case STATE_ZONE_1:
2684         switch (message[cur_token]) {
2685         case 'G':
2686           if (message[cur_token + 1] == 'M' && message[cur_token + 2] == 'T') {
2687             zone = 0;
2688             state = STATE_ZONE_OK;
2689           }
2690           else {
2691             state = STATE_ZONE_ERR;
2692           }
2693           break;
2694         case 'E':
2695           zone = -5;
2696           state = STATE_ZONE_2;
2697           break;
2698         case 'C':
2699           zone = -6;
2700           state = STATE_ZONE_2;
2701           break;
2702         case 'M':
2703           zone = -7;
2704           state = STATE_ZONE_2;
2705           break;
2706         case 'P':
2707           zone = -8;
2708           state = STATE_ZONE_2;
2709           break;
2710         default:
2711           state = STATE_ZONE_CONT;
2712           break;
2713         }
2714         break;
2715       case STATE_ZONE_2:
2716         switch (message[cur_token + 1]) {
2717         case 'S':
2718           state = STATE_ZONE_3;
2719           break;
2720         case 'D':
2721           zone ++;
2722           state = STATE_ZONE_3;
2723           break;
2724         default:
2725           state = STATE_ZONE_ERR;
2726           break;
2727         }
2728         break;
2729       case STATE_ZONE_3:
2730         if (message[cur_token + 2] == 'T') {
2731           zone *= 100;
2732           state = STATE_ZONE_OK;
2733         }
2734         else
2735           state = STATE_ZONE_ERR;
2736         break;
2737       }
2738     }
2739
2740     switch (state) {
2741     case STATE_ZONE_OK:
2742       * result = zone;
2743       * index = cur_token + 3;
2744       return MAILIMF_NO_ERROR;
2745       
2746     case STATE_ZONE_ERR:
2747       return MAILIMF_ERROR_PARSE;
2748     }
2749   }
2750
2751   sign = 1;
2752   r = mailimf_plus_parse(message, length, &cur_token);
2753   if (r == MAILIMF_NO_ERROR)
2754     sign = 1;
2755
2756   if (r == MAILIMF_ERROR_PARSE) {
2757     r = mailimf_minus_parse(message, length, &cur_token);
2758     if (r == MAILIMF_NO_ERROR)
2759       sign = -1;
2760   }
2761
2762   if (r == MAILIMF_NO_ERROR) {
2763     /* do nothing */
2764   }
2765   else if (r == MAILIMF_ERROR_PARSE)
2766     sign = 1;
2767   else
2768     return r;
2769
2770   r = mailimf_number_parse(message, length, &cur_token, &zone);
2771   if (r != MAILIMF_NO_ERROR)
2772     return r;
2773
2774   zone = zone * sign;
2775
2776   * index = cur_token;
2777   * result = zone;
2778
2779   return MAILIMF_NO_ERROR;
2780 }
2781
2782 /*
2783 address         =       mailbox / group
2784 */
2785
2786 int mailimf_address_parse(const char * message, size_t length,
2787                           size_t * index,
2788                           struct mailimf_address ** result)
2789 {
2790   int type;
2791   size_t cur_token;
2792   struct mailimf_mailbox * mailbox;
2793   struct mailimf_group * group;
2794   struct mailimf_address * address;
2795   int r;
2796   int res;
2797
2798   cur_token = * index;
2799
2800   mailbox = NULL;
2801   group = NULL;
2802
2803   type = MAILIMF_ADDRESS_ERROR; /* XXX - removes a gcc warning */
2804   r = mailimf_group_parse(message, length, &cur_token, &group);
2805   if (r == MAILIMF_NO_ERROR)
2806     type = MAILIMF_ADDRESS_GROUP;
2807   
2808   if (r == MAILIMF_ERROR_PARSE) {
2809     r = mailimf_mailbox_parse(message, length, &cur_token, &mailbox);
2810     if (r == MAILIMF_NO_ERROR)
2811       type = MAILIMF_ADDRESS_MAILBOX;
2812   }
2813
2814   if (r != MAILIMF_NO_ERROR) {
2815     res = r;
2816     goto err;
2817   }
2818
2819   address = mailimf_address_new(type, mailbox, group);
2820   if (address == NULL) {
2821     res = MAILIMF_ERROR_MEMORY;
2822     goto free;
2823   }
2824
2825   * result = address;
2826   * index = cur_token;
2827
2828   return MAILIMF_NO_ERROR;
2829   
2830  free:
2831   if (mailbox != NULL)
2832     mailimf_mailbox_free(mailbox);
2833   if (group != NULL)
2834     mailimf_group_free(group);
2835  err:
2836   return res;
2837 }
2838
2839
2840 /*
2841 mailbox         =       name-addr / addr-spec
2842 */
2843
2844
2845 int mailimf_mailbox_parse(const char * message, size_t length,
2846                           size_t * index,
2847                           struct mailimf_mailbox ** result)
2848 {
2849   size_t cur_token;
2850   char * display_name;
2851   struct mailimf_mailbox * mailbox;
2852   char * addr_spec;
2853   int r;
2854   int res;
2855
2856   cur_token = * index;
2857   display_name = NULL;
2858   addr_spec = NULL;
2859
2860   r = mailimf_name_addr_parse(message, length, &cur_token,
2861                               &display_name, &addr_spec);
2862   if (r == MAILIMF_ERROR_PARSE)
2863     r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec);
2864
2865   if (r != MAILIMF_NO_ERROR) {
2866     res = r;
2867     goto err;
2868   }
2869
2870   mailbox = mailimf_mailbox_new(display_name, addr_spec);
2871   if (mailbox == NULL) {
2872     res = MAILIMF_ERROR_MEMORY;
2873     goto free;
2874   }
2875
2876   * result = mailbox;
2877   * index = cur_token;
2878
2879   return MAILIMF_NO_ERROR;
2880
2881  free:
2882   if (display_name != NULL)
2883     mailimf_display_name_free(display_name);
2884   if (addr_spec != NULL)
2885     mailimf_addr_spec_free(addr_spec);
2886  err:
2887   return res;
2888 }
2889
2890 /*
2891 name-addr       =       [display-name] angle-addr
2892 */
2893
2894 static int mailimf_name_addr_parse(const char * message, size_t length,
2895                                    size_t * index,
2896                                    char ** pdisplay_name,
2897                                    char ** pangle_addr)
2898 {
2899   char * display_name;
2900   char * angle_addr;
2901   size_t cur_token;
2902   int r;
2903   int res;
2904
2905   cur_token = * index;
2906
2907   display_name = NULL;
2908   angle_addr = NULL;
2909
2910   r = mailimf_display_name_parse(message, length, &cur_token, &display_name);
2911   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
2912     res = r;
2913     goto err;
2914   }
2915
2916   r = mailimf_angle_addr_parse(message, length, &cur_token, &angle_addr);
2917   if (r != MAILIMF_NO_ERROR) {
2918     res = r;
2919     goto free_display_name;
2920   }
2921
2922   * pdisplay_name = display_name;
2923   * pangle_addr = angle_addr;
2924   * index = cur_token;
2925
2926   return MAILIMF_NO_ERROR;
2927
2928  free_display_name:
2929   if (display_name != NULL)
2930     mailimf_display_name_free(display_name);
2931  err:
2932   return res;
2933 }
2934
2935 /*
2936 angle-addr      =       [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
2937 */
2938
2939 static int mailimf_angle_addr_parse(const char * message, size_t length,
2940                                     size_t * index, char ** result)
2941 {
2942   size_t cur_token;
2943   char * addr_spec;
2944   int r;
2945   
2946   cur_token = * index;
2947   
2948   r = mailimf_cfws_parse(message, length, &cur_token);
2949   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
2950     return r;
2951   
2952   r = mailimf_lower_parse(message, length, &cur_token);
2953   if (r != MAILIMF_NO_ERROR)
2954     return r;
2955   
2956   r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec);
2957   if (r != MAILIMF_NO_ERROR)
2958     return r;
2959   
2960   r = mailimf_greater_parse(message, length, &cur_token);
2961   if (r != MAILIMF_NO_ERROR) {
2962     free(addr_spec);
2963     return r;
2964   }
2965
2966   * result = addr_spec;
2967   * index = cur_token;
2968
2969   return MAILIMF_NO_ERROR;
2970 }
2971
2972 /*
2973 group           =       display-name ":" [mailbox-list / CFWS] ";"
2974                         [CFWS]
2975 */
2976
2977 static int mailimf_group_parse(const char * message, size_t length,
2978                                size_t * index,
2979                                struct mailimf_group ** result)
2980 {
2981   size_t cur_token;
2982   char * display_name;
2983   struct mailimf_mailbox_list * mailbox_list;
2984   struct mailimf_group * group;
2985   int r;
2986   int res;
2987   clist * list;
2988
2989   cur_token = * index;
2990
2991   mailbox_list = NULL;
2992
2993   r = mailimf_display_name_parse(message, length, &cur_token, &display_name);
2994   if (r != MAILIMF_NO_ERROR) {
2995     res = r;
2996     goto err;
2997   }
2998
2999   r = mailimf_colon_parse(message, length, &cur_token);
3000   if (r != MAILIMF_NO_ERROR) {
3001     res = r;
3002     goto free_display_name;
3003   }
3004
3005   r = mailimf_mailbox_list_parse(message, length, &cur_token, &mailbox_list);
3006   switch (r) {
3007   case MAILIMF_NO_ERROR:
3008     break;
3009   case MAILIMF_ERROR_PARSE:
3010     r = mailimf_cfws_parse(message, length, &cur_token);
3011     if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
3012       res = r;
3013       goto free_display_name;
3014     }
3015     list = clist_new();
3016     if (list == NULL) {
3017       res = MAILIMF_ERROR_MEMORY;
3018       goto free_display_name;
3019     }
3020     mailbox_list = mailimf_mailbox_list_new(list);
3021     if (mailbox_list == NULL) {
3022       res = MAILIMF_ERROR_MEMORY;
3023       clist_free(list);
3024       goto free_display_name;
3025     }
3026     break;
3027   default:
3028     res = r;
3029     goto free_display_name;
3030   }
3031
3032   r = mailimf_semi_colon_parse(message, length, &cur_token);
3033   if (r != MAILIMF_NO_ERROR) {
3034     res = r;
3035     goto free_mailbox_list;
3036   }
3037
3038   group = mailimf_group_new(display_name, mailbox_list);
3039   if (group == NULL) {
3040     res = MAILIMF_ERROR_MEMORY;
3041     goto free_mailbox_list;
3042   }
3043
3044   * index = cur_token;
3045   * result = group;
3046
3047   return MAILIMF_NO_ERROR;
3048
3049  free_mailbox_list:
3050   mailimf_mailbox_list_free(mailbox_list);
3051  free_display_name:
3052   mailimf_display_name_free(display_name);
3053  err:
3054   return res;
3055 }
3056
3057 /*
3058 display-name    =       phrase
3059 */
3060
3061 static int mailimf_display_name_parse(const char * message, size_t length,
3062                                       size_t * index, char ** result)
3063 {
3064   return mailimf_phrase_parse(message, length, index, result);
3065 }
3066
3067 /*
3068 mailbox-list    =       (mailbox *("," mailbox)) / obs-mbox-list
3069 */
3070
3071 int
3072 mailimf_mailbox_list_parse(const char * message, size_t length,
3073                            size_t * index,
3074                            struct mailimf_mailbox_list ** result)
3075 {
3076   size_t cur_token;
3077   clist * list;
3078   struct mailimf_mailbox_list * mailbox_list;
3079   int r;
3080   int res;
3081
3082   cur_token = * index;
3083
3084   r = mailimf_struct_list_parse(message, length, 
3085                                 &cur_token, &list, ',',
3086                                 (mailimf_struct_parser *)
3087                                 mailimf_mailbox_parse,
3088                                 (mailimf_struct_destructor *)
3089                                 mailimf_mailbox_free);
3090   if (r != MAILIMF_NO_ERROR) {
3091     res = r;
3092     goto err;
3093   }
3094
3095   mailbox_list = mailimf_mailbox_list_new(list);
3096   if (mailbox_list == NULL) {
3097     res = MAILIMF_ERROR_MEMORY;
3098     goto free_list;
3099   }
3100
3101   * result = mailbox_list;
3102   * index = cur_token;
3103
3104   return MAILIMF_NO_ERROR;
3105
3106  free_list:
3107   clist_foreach(list, (clist_func) mailimf_mailbox_free, NULL);
3108   clist_free(list);
3109  err:
3110   return res;
3111 }                                  
3112
3113 /*
3114 address-list    =       (address *("," address)) / obs-addr-list
3115 */
3116
3117
3118 int
3119 mailimf_address_list_parse(const char * message, size_t length,
3120                            size_t * index,
3121                            struct mailimf_address_list ** result)
3122 {
3123   size_t cur_token;
3124   clist * list;
3125   struct mailimf_address_list * address_list;
3126   int r;
3127   int res;
3128
3129   cur_token = * index;
3130
3131   r = mailimf_struct_list_parse(message, length,
3132                                 &cur_token, &list, ',',
3133                                 (mailimf_struct_parser *)
3134                                 mailimf_address_parse,
3135                                 (mailimf_struct_destructor *)
3136                                 mailimf_address_free);
3137   if (r != MAILIMF_NO_ERROR) {
3138     res = r;
3139     goto err;
3140   }
3141
3142   address_list = mailimf_address_list_new(list);
3143   if (address_list == NULL) {
3144     res = MAILIMF_ERROR_MEMORY;
3145     goto free_list;
3146   }
3147
3148   * result = address_list;
3149   * index = cur_token;
3150
3151   return MAILIMF_NO_ERROR;
3152
3153  free_list:
3154   clist_foreach(list, (clist_func) mailimf_address_free, NULL);
3155   clist_free(list);
3156  err:
3157   return res;
3158 }                                  
3159
3160 /*
3161 addr-spec       =       local-part "@" domain
3162 */
3163
3164
3165 static int mailimf_addr_spec_parse(const char * message, size_t length,
3166                                    size_t * index,
3167                                    char ** result)
3168 {
3169   size_t cur_token;
3170 #if 0
3171   char * local_part;
3172   char * domain;
3173 #endif
3174   char * addr_spec;
3175   int r;
3176   int res;
3177   size_t begin;
3178   size_t end;
3179   int final;
3180   size_t count;
3181   const char * src;
3182   char * dest;
3183   size_t i;
3184   
3185   cur_token = * index;
3186   
3187   r = mailimf_cfws_parse(message, length, &cur_token);
3188   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
3189     res = r;
3190     goto err;
3191   }
3192
3193   end = cur_token;
3194   if (end >= length) {
3195     res = MAILIMF_ERROR_PARSE;
3196     goto err;
3197   }
3198
3199   begin = cur_token;
3200
3201   final = FALSE;
3202   while (1) {
3203     switch (message[end]) {
3204     case '>':
3205     case ',':
3206     case '\r':
3207     case '\n':
3208     case '(':
3209     case ')':
3210     case ':':
3211     case ';':
3212       final = TRUE;
3213       break;
3214     }
3215
3216     if (final)
3217       break;
3218
3219     end ++;
3220     if (end >= length)
3221       break;
3222   }
3223
3224   if (end == begin) {
3225     res = MAILIMF_ERROR_PARSE;
3226     goto err;
3227   }
3228   
3229   addr_spec = malloc(end - cur_token + 1);
3230   if (addr_spec == NULL) {
3231     res = MAILIMF_ERROR_MEMORY;
3232     goto err;
3233   }
3234   
3235   count = end - cur_token;
3236   src = message + cur_token;
3237   dest = addr_spec;
3238   for(i = 0 ; i < count ; i ++) {
3239     if ((* src != ' ') && (* src != '\t')) {
3240       * dest = * src;
3241       dest ++;
3242     }
3243     src ++;
3244   }
3245   * dest = '\0';
3246   
3247 #if 0
3248   strncpy(addr_spec, message + cur_token, end - cur_token);
3249   addr_spec[end - cur_token] = '\0';
3250 #endif
3251
3252   cur_token = end;
3253
3254 #if 0
3255   r = mailimf_local_part_parse(message, length, &cur_token, &local_part);
3256   if (r != MAILIMF_NO_ERROR) {
3257     res = r;
3258     goto err;
3259   }
3260
3261   r = mailimf_at_sign_parse(message, length, &cur_token);
3262   switch (r) {
3263   case MAILIMF_NO_ERROR:
3264     r = mailimf_domain_parse(message, length, &cur_token, &domain);
3265     if (r != MAILIMF_NO_ERROR) {
3266       res = r;
3267       goto free_local_part;
3268     }
3269     break;
3270
3271   case MAILIMF_ERROR_PARSE:
3272     domain = NULL;
3273     break;
3274
3275   default:
3276     res = r;
3277     goto free_local_part;
3278   }
3279
3280   if (domain) {
3281     addr_spec = malloc(strlen(local_part) + strlen(domain) + 2);
3282     if (addr_spec == NULL) {
3283       res = MAILIMF_ERROR_MEMORY;
3284       goto free_domain;
3285     }
3286     
3287     strcpy(addr_spec, local_part);
3288     strcat(addr_spec, "@");
3289     strcat(addr_spec, domain);
3290
3291     mailimf_domain_free(domain);
3292     mailimf_local_part_free(local_part);
3293   }
3294   else {
3295     addr_spec = local_part;
3296   }
3297 #endif
3298
3299   * result = addr_spec;
3300   * index = cur_token;
3301
3302   return MAILIMF_NO_ERROR;
3303
3304 #if 0
3305  free_domain:
3306   mailimf_domain_free(domain);
3307  free_local_part:
3308   mailimf_local_part_free(local_part);
3309 #endif
3310  err:
3311   return res;
3312 }
3313
3314 /*
3315 local-part      =       dot-atom / quoted-string / obs-local-part
3316 */
3317
3318 #if 0
3319 static int mailimf_local_part_parse(const char * message, size_t length,
3320                                     size_t * index,
3321                                     char ** result)
3322 {
3323   int r;
3324
3325   r = mailimf_dot_atom_parse(message, length, index, result);
3326   switch (r) {
3327   case MAILIMF_NO_ERROR:
3328     return r;
3329   case MAILIMF_ERROR_PARSE:
3330     break;
3331   default:
3332     return r;
3333   }
3334
3335   r = mailimf_quoted_string_parse(message, length, index, result);
3336   if (r != MAILIMF_NO_ERROR)
3337     return r;
3338
3339   return MAILIMF_NO_ERROR;
3340 }
3341 #endif
3342
3343 /*
3344 domain          =       dot-atom / domain-literal / obs-domain
3345 */
3346
3347 #if 0
3348 static int mailimf_domain_parse(const char * message, size_t length,
3349                                 size_t * index,
3350                                 char ** result)
3351 {
3352   int r;
3353
3354   r = mailimf_dot_atom_parse(message, length, index, result);
3355   switch (r) {
3356   case MAILIMF_NO_ERROR:
3357     return r;
3358   case MAILIMF_ERROR_PARSE:
3359     break;
3360   default:
3361     return r;
3362   }
3363
3364   r = mailimf_domain_literal_parse(message, length, index, result);
3365   if (r != MAILIMF_NO_ERROR)
3366     return r;
3367
3368   return MAILIMF_NO_ERROR;
3369 }
3370 #endif
3371
3372 /*
3373 [FWS] dcontent
3374 */
3375
3376 #if 0
3377 static int
3378 mailimf_domain_literal_fws_dcontent_parse(const char * message, size_t length,
3379                                           size_t * index)
3380 {
3381   size_t cur_token;
3382   char ch;
3383   int r;
3384
3385   cur_token = * index;
3386
3387   r = mailimf_cfws_parse(message, length, &cur_token);
3388   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
3389     return r;
3390   
3391   r = mailimf_dcontent_parse(message, length, &cur_token, &ch);
3392   if (r != MAILIMF_NO_ERROR)
3393     return r;
3394
3395   * index = cur_token;
3396
3397   return MAILIMF_NO_ERROR;
3398 }
3399 #endif
3400
3401 /*
3402 domain-literal  =       [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
3403 */
3404
3405 #if 0
3406 static int mailimf_domain_literal_parse(const char * message, size_t length,
3407                                         size_t * index, char ** result)
3408 {
3409   size_t cur_token;
3410   int len;
3411   int begin;
3412   char * domain_literal;
3413   int r;
3414
3415   cur_token = * index;
3416
3417   r = mailimf_cfws_parse(message, length, &cur_token);
3418   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
3419     return r;
3420
3421   begin = cur_token;
3422   r = mailimf_obracket_parse(message, length, &cur_token);
3423   if (r != MAILIMF_NO_ERROR)
3424     return r;
3425
3426   while (1) {
3427     r = mailimf_domain_literal_fws_dcontent_parse(message, length,
3428                                                   &cur_token);
3429     if (r == MAILIMF_NO_ERROR) {
3430       /* do nothing */
3431     }
3432     else if (r == MAILIMF_ERROR_PARSE)
3433       break;
3434     else
3435       return r;
3436   }
3437
3438   r = mailimf_fws_parse(message, length, &cur_token);
3439   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
3440     return r;
3441
3442   r = mailimf_cbracket_parse(message, length, &cur_token);
3443   if (r != MAILIMF_NO_ERROR)
3444     return r;
3445
3446   len = cur_token - begin;
3447
3448   domain_literal = malloc(len + 1);
3449   if (domain_literal == NULL)
3450     return MAILIMF_ERROR_MEMORY;
3451   strncpy(domain_literal, message + begin, len);
3452   domain_literal[len] = '\0';
3453
3454   * result = domain_literal;
3455   * index = cur_token;
3456
3457   return MAILIMF_NO_ERROR;
3458 }
3459 #endif
3460
3461 /*
3462 dcontent        =       dtext / quoted-pair
3463 */
3464
3465 #if 0
3466 static int mailimf_dcontent_parse(const char * message, size_t length,
3467                                   size_t * index, char * result)
3468 {
3469   size_t cur_token;
3470   char ch;
3471   int r;
3472   
3473   cur_token = * index;
3474
3475   if (cur_token >= length)
3476     return MAILIMF_ERROR_PARSE;
3477
3478   if (is_dtext(message[cur_token])) {
3479     ch = message[cur_token];
3480     cur_token ++;
3481   }
3482   else {
3483     r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch);
3484     
3485     if (r != MAILIMF_NO_ERROR)
3486       return r;
3487   }
3488     
3489   * index = cur_token;
3490   * result = ch;
3491
3492   return MAILIMF_NO_ERROR;
3493 }
3494 #endif
3495
3496
3497 /*
3498 dtext           =       NO-WS-CTL /     ; Non white space controls
3499
3500                         %d33-90 /       ; The rest of the US-ASCII
3501                         %d94-126        ;  characters not including "[",
3502                                         ;  "]", or "\"
3503 */
3504
3505 static inline int is_dtext(char ch)
3506 {
3507   unsigned char uch = (unsigned char) ch;
3508
3509   if (is_no_ws_ctl(ch))
3510     return TRUE;
3511
3512   if (uch < 33)
3513     return FALSE;
3514
3515   if ((uch >= 91) && (uch <= 93))
3516     return FALSE;
3517
3518   if (uch == 127)
3519     return FALSE;
3520
3521   return TRUE;
3522 }
3523
3524 /*
3525 message         =       (fields / obs-fields)
3526                         [CRLF body]
3527 */
3528
3529 int mailimf_message_parse(const char * message, size_t length,
3530                           size_t * index,
3531                           struct mailimf_message ** result)
3532 {
3533   struct mailimf_fields * fields;
3534   struct mailimf_body * body;
3535   struct mailimf_message * msg;
3536   size_t cur_token;
3537   int r;
3538   int res;
3539
3540   cur_token = * index;
3541
3542   r = mailimf_fields_parse(message, length, &cur_token, &fields);
3543   if (r != MAILIMF_NO_ERROR) {
3544     res = r;
3545     goto err;
3546   }
3547
3548   r = mailimf_crlf_parse(message, length, &cur_token);
3549   if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
3550     res = r;
3551     goto err;
3552   }
3553
3554   r = mailimf_body_parse(message, length, &cur_token, &body);
3555   if (r != MAILIMF_NO_ERROR) {
3556     res = r;
3557     goto free_fields;
3558   }
3559
3560   msg = mailimf_message_new(fields, body);
3561   if (msg == NULL) {
3562     res = MAILIMF_ERROR_MEMORY;
3563     goto free_body;
3564   }
3565
3566   * index = cur_token;
3567   * result = msg;
3568
3569   return MAILIMF_NO_ERROR;
3570
3571  free_body:
3572   mailimf_body_free(body);
3573  free_fields:
3574   mailimf_fields_free(fields);
3575  err:
3576   return res;
3577 }
3578
3579 /*
3580 body            =       *(*998text CRLF) *998text
3581 */
3582
3583 int mailimf_body_parse(const char * message, size_t length,
3584                        size_t * index,
3585                        struct mailimf_body ** result)
3586 {
3587   size_t cur_token;
3588   struct mailimf_body * body;
3589
3590   cur_token = * index;
3591
3592   body = mailimf_body_new(message + cur_token, length - cur_token);
3593   if (body == NULL)
3594     return MAILIMF_ERROR_MEMORY;
3595
3596   cur_token = length;
3597
3598   * result = body;
3599   * index = cur_token;
3600
3601   return MAILIMF_NO_ERROR;
3602 }
3603
3604 /*
3605 CHANGE TO THE RFC 2822
3606
3607 original :
3608
3609 fields          =       *(trace
3610                           *(resent-date /
3611                            resent-from /
3612                            resent-sender /
3613                            resent-to /
3614                            resent-cc /
3615                            resent-bcc /
3616                            resent-msg-id))
3617                         *(orig-date /
3618                         from /
3619                         sender /
3620                         reply-to /
3621                         to /
3622                         cc /
3623                         bcc /
3624                         message-id /
3625                         in-reply-to /
3626                         references /
3627                         subject /
3628                         comments /
3629                         keywords /
3630                         optional-field)
3631
3632 INTO THE FOLLOWING :
3633 */
3634
3635 /*
3636 resent-fields-list =      *(resent-date /
3637                            resent-from /
3638                            resent-sender /
3639                            resent-to /
3640                            resent-cc /
3641                            resent-bcc /
3642                            resent-msg-id))
3643 */
3644
3645 #if 0
3646 enum {
3647   RESENT_HEADER_START,
3648 };
3649
3650 static int guess_resent_header_type(char * message,
3651                                     size_t length, size_t index)
3652 {
3653   int r;
3654
3655   r = mailimf_token_case_insensitive_parse(message,
3656                                            length, &index, "Resent-");
3657   if (r != MAILIMF_NO_ERROR)
3658     return MAILIMF_RESENT_FIELD_NONE;
3659   
3660   if (index >= length)
3661     return MAILIMF_RESENT_FIELD_NONE;
3662
3663   switch(toupper(message[index])) {
3664   case 'D':
3665     return MAILIMF_RESENT_FIELD_DATE;
3666   case 'F':
3667     return MAILIMF_RESENT_FIELD_FROM;
3668   case 'S':
3669     return MAILIMF_RESENT_FIELD_SENDER;
3670   case 'T':
3671     return MAILIMF_RESENT_FIELD_TO;
3672   case 'C':
3673     return MAILIMF_RESENT_FIELD_CC;
3674   case 'B':
3675     return MAILIMF_RESENT_FIELD_BCC;
3676   case 'M':
3677     return MAILIMF_RESENT_FIELD_MSG_ID;
3678   default:
3679     return MAILIMF_RESENT_FIELD_NONE;
3680   }
3681 }
3682 #endif
3683
3684 #if 0
3685 static int
3686 mailimf_resent_field_parse(const char * message, size_t length,
3687                            size_t * index,
3688                            struct mailimf_resent_field ** result)
3689 {
3690   struct mailimf_orig_date * resent_date;
3691   struct mailimf_from * resent_from;
3692   struct mailimf_sender * resent_sender;
3693   struct mailimf_to* resent_to;
3694   struct mailimf_cc * resent_cc;
3695   struct mailimf_bcc * resent_bcc;
3696   struct mailimf_message_id * resent_msg_id;
3697   size_t cur_token;
3698   int type;
3699   struct mailimf_resent_field * resent_field;
3700   int r;
3701   int res;
3702
3703   cur_token = * index;
3704
3705   resent_date = NULL;
3706   resent_from = NULL;
3707   resent_sender = NULL;
3708   resent_to = NULL;
3709   resent_cc = NULL;
3710   resent_bcc = NULL;
3711   resent_msg_id = NULL;
3712
3713   type = guess_resent_header_type(message, length, cur_token);
3714
3715   switch(type) {
3716   case MAILIMF_RESENT_FIELD_DATE:
3717     r = mailimf_resent_date_parse(message, length, &cur_token,
3718                                   &resent_date);
3719     if (r != MAILIMF_NO_ERROR) {
3720       res = r;
3721       goto free_resent;
3722     }
3723     break;
3724   case MAILIMF_RESENT_FIELD_FROM:
3725     r = mailimf_resent_from_parse(message, length, &cur_token,
3726                                   &resent_from);
3727     if (r != MAILIMF_NO_ERROR) {
3728       res = r;
3729       goto free_resent;
3730     }
3731     break;
3732   case MAILIMF_RESENT_FIELD_SENDER:
3733     r = mailimf_resent_sender_parse(message, length, &cur_token,
3734                                     &resent_sender);
3735     if (r != MAILIMF_NO_ERROR) {
3736       res = r;
3737       goto free_resent;
3738     }
3739     break;
3740   case MAILIMF_RESENT_FIELD_TO:
3741     r = mailimf_resent_to_parse(message, length, &cur_token,
3742                                 &resent_to);
3743     if (r != MAILIMF_NO_ERROR) {
3744       res = r;
3745       goto free_resent;
3746     }
3747     break;
3748   case MAILIMF_RESENT_FIELD_CC:
3749     r= mailimf_resent_cc_parse(message, length, &cur_token,
3750                                &resent_cc);
3751     if (r != MAILIMF_NO_ERROR) {
3752       res = r;
3753       goto free_resent;
3754     }
3755     break;
3756   case MAILIMF_RESENT_FIELD_BCC:
3757     r = mailimf_resent_bcc_parse(message, length, &cur_token,
3758                                  &resent_bcc);
3759     if (r != MAILIMF_NO_ERROR) {
3760       res = r;
3761       goto free_resent;
3762     }
3763     break;
3764   case MAILIMF_RESENT_FIELD_MSG_ID:
3765     r = mailimf_resent_msg_id_parse(message, length, &cur_token,
3766                                     &resent_msg_id);
3767     if (r != MAILIMF_NO_ERROR) {
3768       res = r;
3769       goto free_resent;
3770     }
3771     break;
3772   default:
3773     res = MAILIMF_ERROR_PARSE;
3774     goto free_resent;
3775   }
3776
3777   resent_field = mailimf_resent_field_new(type, resent_date,
3778                                           resent_from, resent_sender,
3779                                           resent_to, resent_cc,
3780                                           resent_bcc, resent_msg_id);
3781   if (resent_field == NULL) {
3782     res = MAILIMF_ERROR_MEMORY;
3783     goto free_resent;
3784   }
3785
3786   * result = resent_field;
3787   * index = cur_token;
3788
3789   return MAILIMF_NO_ERROR;
3790
3791  free_resent:
3792   if (resent_msg_id != NULL)
3793     mailimf_message_id_free(resent_msg_id);
3794   if (resent_bcc != NULL)
3795     mailimf_bcc_free(resent_bcc);
3796   if (resent_cc != NULL)
3797     mailimf_cc_free(resent_cc);
3798   if (resent_to != NULL)
3799     mailimf_to_free(resent_to);
3800   if (resent_sender != NULL)
3801     mailimf_sender_free(resent_sender);
3802   if (resent_from != NULL)
3803     mailimf_from_free(resent_from);
3804   if (resent_date != NULL)
3805     mailimf_orig_date_free(resent_date);
3806  err:
3807   return res;
3808 }
3809 #endif
3810
3811 #if 0
3812 static int
3813 mailimf_resent_fields_list_parse(const char * message, size_t length,
3814                                  size_t * index,
3815                                  struct mailimf_resent_fields_list ** result)
3816 {
3817   clist * list;
3818   size_t cur_token;
3819   struct mailimf_resent_fields_list * resent_fields_list;
3820   int r;
3821   int res;
3822
3823   cur_token = * index;
3824   list = NULL;
3825
3826   r = mailimf_struct_multiple_parse(message, length, &cur_token, &list,
3827                                     (mailimf_struct_parser *)
3828                                     mailimf_resent_field_parse,
3829                                     (mailimf_struct_destructor *)
3830                                     mailimf_resent_field_free);
3831   if (r != MAILIMF_NO_ERROR) {
3832     res = r;
3833     goto err;
3834   }
3835
3836   resent_fields_list = mailimf_resent_fields_list_new(list);
3837   if (resent_fields_list == NULL) {
3838     res = MAILIMF_ERROR_MEMORY;
3839     goto free_list;
3840   }
3841
3842   * result = resent_fields_list;
3843   * index = cur_token;
3844
3845   return MAILIMF_NO_ERROR;
3846
3847  free_list:
3848   clist_foreach(list, (clist_func) mailimf_resent_field_free, NULL);
3849   clist_free(list);
3850  err:
3851   return res;
3852 }
3853 #endif
3854
3855 /*
3856  ([trace]
3857   [resent-fields-list])
3858 */
3859
3860 #if 0
3861 static int
3862 mailimf_trace_resent_fields_parse(const char * message, size_t length,
3863                                   size_t * index,
3864                                   struct mailimf_trace_resent_fields ** result)
3865 {
3866   size_t cur_token;
3867   struct mailimf_return * return_path;
3868   struct mailimf_resent_fields_list * resent_fields;
3869   struct mailimf_trace_resent_fields * trace_resent_fields;