add configure option --enable-appdata and put all appdata in appdata/
[claws.git] / src / plugins / mailmbox / mailimf_write.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_write.h"
37
38 #include <time.h>
39 #include <string.h>
40 #include <ctype.h>
41
42 #define MAX_MAIL_COL 72
43
44 #ifndef TRUE
45 #define TRUE 1
46 #endif
47
48 #ifndef FALSE
49 #define FALSE 0
50 #endif
51
52 #define MAX_VALID_IMF_LINE 998
53
54 static int mailimf_orig_date_write(FILE * f, int * col,
55                                    struct mailimf_orig_date * date);
56 static int mailimf_date_time_write(FILE * f, int * col,
57                                    struct mailimf_date_time * date_time);
58 static int mailimf_from_write(FILE * f, int * col,
59                               struct mailimf_from * from);
60 static int mailimf_sender_write(FILE * f, int * col,
61                                 struct mailimf_sender * sender);
62 static int mailimf_reply_to_write(FILE * f, int * col,
63                                   struct mailimf_reply_to * reply_to);
64 static int mailimf_to_write(FILE * f, int * col,
65                             struct mailimf_to * to);
66 static int mailimf_cc_write(FILE * f, int * col,
67                             struct mailimf_cc * to);
68 static int mailimf_bcc_write(FILE * f, int * col,
69                              struct mailimf_bcc * to);
70 static int mailimf_message_id_write(FILE * f, int * col,
71                                     struct mailimf_message_id * message_id);
72 static int mailimf_msg_id_list_write(FILE * f, int * col,
73                                      clist * list);
74 static int mailimf_in_reply_to_write(FILE * f, int * col,
75                                      struct mailimf_in_reply_to *
76                                      in_reply_to);
77 static int mailimf_references_write(FILE * f, int * col,
78                                     struct mailimf_references * references);
79 static int mailimf_subject_write(FILE * f, int * col,
80                                  struct mailimf_subject * subject);
81
82 static int mailimf_address_write(FILE * f, int * col,
83                                  struct mailimf_address * addr);
84 static int mailimf_group_write(FILE * f, int * col,
85                                struct mailimf_group * group);
86
87 static int mailimf_mailbox_write(FILE * f, int * col,
88                                  struct mailimf_mailbox * mb);
89
90 static int mailimf_comments_write(FILE * f, int * col,
91                                   struct mailimf_comments * comments);
92
93 static int mailimf_optional_field_write(FILE * f, int * col,
94                                         struct mailimf_optional_field * field);
95
96 static int mailimf_keywords_write(FILE * f, int * col,
97                                   struct mailimf_keywords * keywords);
98
99 static int mailimf_return_write(FILE * f, int * col,
100                                 struct mailimf_return * return_path);
101
102 static int mailimf_path_write(FILE * f, int * col,
103                               struct mailimf_path * path);
104
105 static int mailimf_resent_date_write(FILE * f, int * col,
106                                      struct mailimf_orig_date * date);
107
108 static int mailimf_resent_from_write(FILE * f, int * col,
109                                      struct mailimf_from * from);
110
111 static int mailimf_resent_sender_write(FILE * f, int * col,
112                                        struct mailimf_sender * sender);
113
114 static int mailimf_resent_to_write(FILE * f, int * col,
115                                    struct mailimf_to * to);
116
117 static int mailimf_resent_cc_write(FILE * f, int * col,
118                                    struct mailimf_cc * cc);
119
120 static int mailimf_resent_bcc_write(FILE * f, int * col,
121                                     struct mailimf_bcc * bcc);
122
123 static int
124 mailimf_resent_msg_id_write(FILE * f, int * col,
125                             struct mailimf_message_id * message_id);
126
127
128
129 /* ************************ */
130
131 #if 0
132 int mailimf_string_write(FILE * f, int * col,
133                          char * str, size_t length)
134 {
135   int r;
136
137   if (length != 0) {
138     r = fwrite(str, sizeof(char), length, f);
139     if (r < 0)
140       return MAILIMF_ERROR_FILE;
141     * col += length;
142   }
143
144   return MAILIMF_NO_ERROR;
145 }
146 #endif
147
148 #define CRLF "\r\n"
149 #define HEADER_FOLD "\r\n "
150
151 static inline int flush_buf(FILE * f, const char * str, size_t length)
152 {
153   if (length != 0) {
154     int r;
155     
156     r = fwrite(str, 1, length, f);
157     if (r == 0)
158       return MAILIMF_ERROR_FILE;
159   }
160   return MAILIMF_NO_ERROR;
161 }
162
163 #define CUT_AT_MAX_VALID_IMF_LINE
164
165 int mailimf_string_write(FILE * f, int * col,
166     const char * str, size_t length)
167 {
168   int r;
169   size_t count;
170   const char * block_begin;
171   const char * p;
172   int done;
173
174   p = str;
175   block_begin = str;
176   count = 0;
177   
178   while (length > 0) {
179 #ifdef CUT_AT_MAX_VALID_IMF_LINE
180     if (count >= 998) {
181       /*
182         cut lines at maximum valid length for internet message
183         format standard (currently RFC 2822)
184         
185         This should not happen.
186         In case there are some lines larger than 998 in body,
187         the encoding must be changed into base64 or quoted-printable
188         so that wrapping to 72 columns is done.
189       */
190       
191       r = flush_buf(f, block_begin, count);
192       if (r != MAILIMF_NO_ERROR)
193         return r;
194       
195       r = fwrite(CRLF, 1, sizeof(CRLF) - 1, f);
196       if (r == 0)
197         return MAILIMF_ERROR_FILE;
198       
199       count = 0;
200       block_begin = p;
201       
202       * col = 0;
203     }
204 #endif
205     switch (* p) {
206     case '\n':
207       r = flush_buf(f, block_begin, count);
208       if (r != MAILIMF_NO_ERROR)
209         return r;
210       
211       r = fwrite(CRLF, 1, sizeof(CRLF) - 1, f);
212       if (r == 0)
213         return MAILIMF_ERROR_FILE;
214       
215       p ++;
216       length --;
217       count = 0;
218       block_begin = p;
219       
220       * col = 0;
221       break;
222       
223     case '\r':
224       done = 0;
225       if (length >= 2) {
226         if (* (p + 1) == '\n') {
227           r = flush_buf(f, block_begin, count);
228           if (r != MAILIMF_NO_ERROR)
229             return r;
230           
231           r = fwrite(CRLF, 1, sizeof(CRLF) - 1, f);
232           if (r == 0)
233             return MAILIMF_ERROR_FILE;
234           
235           p += 2;
236           length -= 2;
237           count = 0;
238           block_begin = p;
239           
240           * col = 0;
241           
242           done = 1;
243         }
244       }
245       if (!done) {
246         r = flush_buf(f, block_begin, count);
247         if (r != MAILIMF_NO_ERROR)
248           return r;
249         
250         r = fwrite(CRLF, 1, sizeof(CRLF) - 1, f);
251         if (r == 0)
252           return MAILIMF_ERROR_FILE;
253         
254         p ++;
255         length --;
256         count = 0;
257         block_begin = p;
258         
259         * col = 0;
260       }
261       break;
262       
263     default:
264       p ++;
265       count ++;
266       length --;
267       break;
268     }
269   }
270   
271   r = flush_buf(f, block_begin, count);
272   if (r != MAILIMF_NO_ERROR)
273     return r;
274   * col += count;
275   
276   return MAILIMF_NO_ERROR;
277 }
278
279 #if 0
280 int mailimf_header_string_write(FILE * f, int * col,
281     char * str, size_t length)
282 {
283   char * p;
284   char * block_begin;
285   int current_col;
286   char * last_cut;
287   int r;
288   int first;
289   
290   if (* col + length < MAX_MAIL_COL)
291     return mailimf_string_write(f, col, str, length);
292   
293   first = 1;
294   p = str;
295   block_begin = p;
296   last_cut = block_begin;
297   current_col = * col;
298   
299   while (1) {
300     if (current_col >= MAX_MAIL_COL) {
301       /* if we reach the maximum recommanded size of line */
302       if (last_cut == block_begin) {
303         /* if we could not find any place to cut */
304         if (first) {
305           /* fold the header */
306           r = mailimf_string_write(f, col, HEADER_FOLD,
307               sizeof(HEADER_FOLD) - 1);
308           if (r != MAILIMF_NO_ERROR)
309             return r;
310           current_col = * col + p - block_begin;
311           first = 0;
312         }
313         else {
314           /* cut the header */
315           r = mailimf_string_write(f, col, block_begin, p - block_begin);
316           if (r != MAILIMF_NO_ERROR)
317             return r;
318           r = mailimf_string_write(f, col, HEADER_FOLD,
319               sizeof(HEADER_FOLD) - 1);
320           if (r != MAILIMF_NO_ERROR)
321             return r;
322           first = 0;
323           block_begin = p;
324           last_cut = block_begin;
325           current_col = * col + p - block_begin;
326         }
327       }
328       else {
329         /* if we found a place to cut */
330         r = mailimf_string_write(f, col, block_begin, last_cut - block_begin);
331         if (r != MAILIMF_NO_ERROR)
332           return r;
333         r = mailimf_string_write(f, col, HEADER_FOLD,
334             sizeof(HEADER_FOLD) - 1);
335         if (r != MAILIMF_NO_ERROR)
336           return r;
337         first = 0;
338         block_begin = last_cut;
339         last_cut = block_begin;
340         current_col = * col + p - block_begin;
341         continue;
342       }
343     }
344     else {
345       if (length == 0)
346         break;
347       
348       switch (* p) {
349       case ' ':
350       case '\t':
351         last_cut = p;
352         current_col ++;
353         break;
354         
355       case '\r':
356       case '\n':
357         current_col = 0;
358         break;
359         
360       default:
361         current_col ++;
362         break;
363       }
364       
365       p ++;
366       length --;
367     }
368   }
369   
370   return mailimf_string_write(f, col, block_begin, p - block_begin);
371 }
372 #endif
373
374 #if 0
375 enum {
376   STATE_LOWER_72,
377   STATE_LOWER_72_CUT,
378   STATE_EQUAL_72,
379   STATE_LOWER_998,
380   STATE_EQUAL_998,
381 };
382
383 int mailimf_header_string_write(FILE * f, int * col,
384     const char * str, size_t length)
385 {
386   int state;
387   const char * p;
388   const char * block_begin;
389   size_t size;
390   const char * cut;
391   int r;
392   
393   if (* col < MAX_MAIL_COL)
394     state = STATE_LOWER_72_CUT;
395   else if (* col == MAX_MAIL_COL)
396     state = STATE_EQUAL_72;
397   else if (* col < MAX_VALID_IMF_LINE)
398     state = STATE_LOWER_998;
399   else
400     state = STATE_EQUAL_998;
401   
402   p = str;
403   block_begin = p;
404   size = * col;
405   cut = p;
406   
407   while (length > 0) {
408     switch (state) {
409     case STATE_LOWER_72:
410       switch (* p) {
411       case '\r':
412       case '\n':
413         p ++;
414         length --;
415         size = 0;
416         break;
417       
418       case ' ':
419       case '\t':
420         cut = p;
421         p ++;
422         length --;
423         size ++;
424         state = STATE_LOWER_72_CUT;
425         break;
426       
427       default:
428         if (size < MAX_MAIL_COL - 1) {
429           p ++;
430           length --;
431           size ++;
432         }
433         else {
434           state = STATE_EQUAL_72;
435           p ++;
436           length --;
437           size ++;
438         }
439         break;
440       }
441       break; /* end of STATE_LOWER_72 */
442     
443     case STATE_LOWER_72_CUT:
444       switch (* p) {
445       case '\r':
446       case '\n':
447         p ++;
448         length --;
449         size = 0;
450         state = STATE_LOWER_72;
451         break;
452       
453       case ' ':
454       case '\t':
455         cut = p;
456         p ++;
457         length --;
458         size ++;
459         break;
460       
461       default:
462         if (size < MAX_MAIL_COL) {
463           p ++;
464           length --;
465           size ++;
466         }
467         else {
468           r = mailimf_string_write(f, col, block_begin, cut - block_begin);
469           if (r != MAILIMF_NO_ERROR)
470             return r;
471           r = mailimf_string_write(f, col, HEADER_FOLD,
472               sizeof(HEADER_FOLD) - 1);
473           if (r != MAILIMF_NO_ERROR)
474             return r;
475           p ++;
476           length --;
477           block_begin = cut;
478           if ((* block_begin == ' ') || (* block_begin == '\t'))
479             block_begin ++;
480           size = p - block_begin + * col;
481           state = STATE_LOWER_72;
482         }
483         break;
484       }
485       break; /* end of STATE_LOWER_72_CUT */
486
487     case STATE_EQUAL_72:
488       switch (* p) {
489       case '\r':
490       case '\n':
491         p ++;
492         length --;
493         size = 0;
494         state = STATE_LOWER_72;
495         break;
496       
497       case ' ':
498       case '\t':
499         r = mailimf_string_write(f, col, block_begin, p - block_begin);
500         if (r != MAILIMF_NO_ERROR)
501           return r;
502         r = mailimf_string_write(f, col, HEADER_FOLD,
503             sizeof(HEADER_FOLD) - 1);
504         if (r != MAILIMF_NO_ERROR)
505           return r;
506         p ++;
507         length --;
508         block_begin = p;
509         size = p - block_begin + * col;
510         state = STATE_LOWER_72;
511         break;
512       
513       default:
514         p ++;
515         length --;
516         size ++;
517         state = STATE_LOWER_998;
518         break;
519       }
520       break; /* end of STATE_EQUAL_72 */
521
522     case STATE_LOWER_998:
523       switch (* p) {
524       case '\r':
525       case '\n':
526         p ++;
527         length --;
528         size = 0;
529         state = STATE_LOWER_72;
530         break;
531       
532       case ' ':
533       case '\t':
534         r = mailimf_string_write(f, col, block_begin, p - block_begin);
535         if (r != MAILIMF_NO_ERROR)
536           return r;
537         r = mailimf_string_write(f, col, HEADER_FOLD,
538             sizeof(HEADER_FOLD) - 1);
539         if (r != MAILIMF_NO_ERROR)
540           return r;
541         p ++;
542         length --;
543         block_begin = p;
544         size = p - block_begin + * col;
545         state = STATE_LOWER_72;
546         break;
547       
548       default:
549         if (size < MAX_VALID_IMF_LINE - 1) {
550           p ++;
551           length --;
552           size ++;
553         }
554         else {
555           p ++;
556           length --;
557           size = 0;
558           state = STATE_EQUAL_998;
559         }
560         break;
561       }
562       break; /* end of STATE_LOWER_998 */
563
564     case STATE_EQUAL_998:
565       switch (* p) {
566       case '\r':
567       case '\n':
568         p ++;
569         length --;
570         size = 0;
571         state = STATE_LOWER_72;
572         break;
573       
574       case ' ':
575       case '\t':
576         r = mailimf_string_write(f, col, block_begin, p - block_begin);
577         if (r != MAILIMF_NO_ERROR)
578           return r;
579         r = mailimf_string_write(f, col, HEADER_FOLD,
580             sizeof(HEADER_FOLD) - 1);
581         if (r != MAILIMF_NO_ERROR)
582           return r;
583         p ++;
584         length --;
585         block_begin = p;
586         size = p - block_begin + * col;
587         state = STATE_LOWER_72;
588         break;
589       
590       default:
591 #ifdef CUT_AT_MAX_VALID_IMF_LINE
592         r = mailimf_string_write(f, col, block_begin, p - block_begin);
593         if (r != MAILIMF_NO_ERROR)
594           return r;
595         r = mailimf_string_write(f, col, HEADER_FOLD,
596             sizeof(HEADER_FOLD) - 1);
597         if (r != MAILIMF_NO_ERROR)
598           return r;
599         p ++;
600         length --;
601         block_begin = p;
602         size = p - block_begin + * col;
603         state = STATE_LOWER_72;
604 #else
605         p ++;
606         length --;
607         size ++;
608 #endif
609         break;
610       }
611       break; /* end of STATE_EQUAL_998 */
612     }
613   }
614   
615   r = mailimf_string_write(f, col, block_begin, p - block_begin);
616   if (r != MAILIMF_NO_ERROR)
617     return r;
618   
619   return MAILIMF_NO_ERROR;
620 }
621 #endif
622
623 enum {
624   STATE_BEGIN,
625   STATE_WORD,
626   STATE_SPACE,
627 };
628
629 int mailimf_header_string_write(FILE * f, int * col,
630     const char * str, size_t length)
631 {
632   int state;
633   const char * p;
634   const char * word_begin;
635   int first;
636   
637   state = STATE_BEGIN;
638   
639   p = str;
640   word_begin = p;
641   first = 1;
642   
643   while (length > 0) {
644     switch (state) {
645     case STATE_BEGIN:
646       switch (* p) {
647       case '\r':
648       case '\n':
649       case ' ':
650       case '\t':
651         p ++;
652         length --;
653         break;
654       
655       default:
656         word_begin = p;
657         state = STATE_WORD;
658         break;
659       }
660       break;
661       
662     case STATE_SPACE:
663       switch (* p) {
664       case '\r':
665       case '\n':
666       case ' ':
667       case '\t':
668         p ++;
669         length --;
670         break;
671       
672       default:
673         word_begin = p;
674         state = STATE_WORD;
675         break;
676       }
677       break;
678
679     case STATE_WORD:
680       switch (* p) {
681       case '\r':
682       case '\n':
683       case ' ':
684       case '\t':
685         if (p - word_begin + (* col) + 1 > MAX_MAIL_COL)
686           mailimf_string_write(f, col, HEADER_FOLD,
687               sizeof(HEADER_FOLD) - 1);
688         else {
689           if (!first)
690             mailimf_string_write(f, col, " ", 1);
691         }
692         first = 0;
693         mailimf_string_write(f, col, word_begin, p - word_begin);
694         state = STATE_SPACE;
695         break;
696         
697       default:
698         if (p - word_begin + (* col) >= MAX_VALID_IMF_LINE) {
699           mailimf_string_write(f, col, word_begin, p - word_begin);
700           mailimf_string_write(f, col, HEADER_FOLD,
701               sizeof(HEADER_FOLD) - 1);
702           word_begin = p;
703         }
704         p ++;
705         length --;
706         break;
707       }
708       break;
709     }
710   }
711   
712   if (state == STATE_WORD) {
713     if (p - word_begin + (* col) >= MAX_MAIL_COL)
714       mailimf_string_write(f, col, HEADER_FOLD,
715           sizeof(HEADER_FOLD) - 1);
716     else {
717       if (!first)
718         mailimf_string_write(f, col, " ", 1);
719     }
720     first = 0;
721     mailimf_string_write(f, col, word_begin, p - word_begin);
722   }
723   
724   return MAILIMF_NO_ERROR;
725 }
726
727 int mailimf_envelope_fields_write(FILE * f, int * col,
728                                   struct mailimf_fields * fields)
729 {
730   clistiter * cur;
731
732   for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
733       cur = clist_next(cur)) {
734     int r;
735     struct mailimf_field * field;
736     
737     field = clist_content(cur);
738     if (field->fld_type != MAILIMF_FIELD_OPTIONAL_FIELD) {
739       r = mailimf_field_write(f, col, field);
740       if (r != MAILIMF_NO_ERROR)
741         return r;
742     }
743   }
744
745   return MAILIMF_NO_ERROR;
746 }
747
748 int mailimf_fields_write(FILE * f, int * col,
749                          struct mailimf_fields * fields)
750 {
751   clistiter * cur;
752
753   for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
754       cur = clist_next(cur)) {
755     int r;
756     
757     r = mailimf_field_write(f, col, clist_content(cur));
758     if (r != MAILIMF_NO_ERROR)
759       return r;
760   }
761
762   return MAILIMF_NO_ERROR;
763 }
764
765 #if 0
766 int mailimf_unparsed_fields_write(FILE * f, int * col,
767                                   struct mailimf_unparsed_fields * fields)
768 {
769   clistiter * cur;
770
771   for(cur = clist_begin(fields->list) ; cur != NULL ; cur = cur->next) {
772     int r;
773     
774     r = mailimf_optional_field_write(f, col, cur->data);
775     if (r != MAILIMF_NO_ERROR)
776       return r;
777   }
778
779   return MAILIMF_NO_ERROR;
780 }
781 #endif
782
783 int mailimf_field_write(FILE * f, int * col,
784                         struct mailimf_field * field)
785 {
786   int r;
787   
788   switch (field->fld_type) {
789   case MAILIMF_FIELD_RETURN_PATH:
790     r = mailimf_return_write(f, col, field->fld_data.fld_return_path);
791     break;
792   case MAILIMF_FIELD_RESENT_DATE:
793     r = mailimf_resent_date_write(f, col, field->fld_data.fld_resent_date);
794     break;
795   case MAILIMF_FIELD_RESENT_FROM:
796     r = mailimf_resent_from_write(f, col, field->fld_data.fld_resent_from);
797     break;
798   case MAILIMF_FIELD_RESENT_SENDER:
799     r = mailimf_resent_sender_write(f, col, field->fld_data.fld_resent_sender);
800     break;
801   case MAILIMF_FIELD_RESENT_TO:
802     r = mailimf_resent_to_write(f, col, field->fld_data.fld_resent_to);
803     break;
804   case MAILIMF_FIELD_RESENT_CC:
805     r = mailimf_resent_cc_write(f, col, field->fld_data.fld_resent_cc);
806     break;
807   case MAILIMF_FIELD_RESENT_BCC:
808     r = mailimf_resent_bcc_write(f, col, field->fld_data.fld_resent_bcc);
809     break;
810   case MAILIMF_FIELD_RESENT_MSG_ID:
811     r = mailimf_resent_msg_id_write(f, col, field->fld_data.fld_resent_msg_id);
812     break;
813   case MAILIMF_FIELD_ORIG_DATE:
814     r = mailimf_orig_date_write(f, col, field->fld_data.fld_orig_date);
815     break;
816   case MAILIMF_FIELD_FROM:
817     r = mailimf_from_write(f, col, field->fld_data.fld_from);
818     break;
819   case MAILIMF_FIELD_SENDER:
820     r = mailimf_sender_write(f, col, field->fld_data.fld_sender);
821     break;
822   case MAILIMF_FIELD_REPLY_TO:
823     r = mailimf_reply_to_write(f, col, field->fld_data.fld_reply_to);
824     break;
825   case MAILIMF_FIELD_TO:
826     r = mailimf_to_write(f, col, field->fld_data.fld_to);
827     break;
828   case MAILIMF_FIELD_CC:
829     r = mailimf_cc_write(f, col, field->fld_data.fld_cc);
830     break;
831   case MAILIMF_FIELD_BCC:
832     r = mailimf_bcc_write(f, col, field->fld_data.fld_bcc);
833     break;
834   case MAILIMF_FIELD_MESSAGE_ID:
835     r = mailimf_message_id_write(f, col, field->fld_data.fld_message_id);
836     break;
837   case MAILIMF_FIELD_IN_REPLY_TO:
838     r = mailimf_in_reply_to_write(f, col, field->fld_data.fld_in_reply_to);
839     break;
840   case MAILIMF_FIELD_REFERENCES:
841     r = mailimf_references_write(f, col, field->fld_data.fld_references);
842     break;
843   case MAILIMF_FIELD_SUBJECT:
844     r = mailimf_subject_write(f, col, field->fld_data.fld_subject);
845     break;
846   case MAILIMF_FIELD_COMMENTS:
847     r = mailimf_comments_write(f, col, field->fld_data.fld_comments);
848     break;
849   case MAILIMF_FIELD_KEYWORDS:
850     r = mailimf_keywords_write(f, col, field->fld_data.fld_keywords);
851     break;
852   case MAILIMF_FIELD_OPTIONAL_FIELD:
853     r = mailimf_optional_field_write(f, col, field->fld_data.fld_optional_field);
854     break;
855   default:
856     r = MAILIMF_ERROR_INVAL;
857     break;
858   }
859
860   if (r != MAILIMF_NO_ERROR)
861     return r;
862
863   return MAILIMF_NO_ERROR;
864 }
865
866
867 static int mailimf_orig_date_write(FILE * f, int * col,
868                                    struct mailimf_orig_date * date)
869 {
870   int r;
871
872   r = mailimf_string_write(f, col, "Date: ", 6);
873   if (r != MAILIMF_NO_ERROR)
874     return r;
875
876   r = mailimf_date_time_write(f, col, date->dt_date_time);
877   if (r != MAILIMF_NO_ERROR)
878     return r;
879
880   r = mailimf_string_write(f, col, "\r\n", 2);
881   if (r != MAILIMF_NO_ERROR)
882     return r;
883 #if 0
884   * col = 0;
885 #endif
886
887   return MAILIMF_NO_ERROR;
888 }
889
890 #define MAX_DATE_STR 256
891
892 /* 0 = Sunday */
893 /* y > 1752 */
894
895 static int dayofweek(int year, int month, int day)
896 {
897   static int offset[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
898
899   year -= month < 3;
900
901   return (year + year/4 - year/100 + year/400 + offset[month-1] + day) % 7;
902 }
903
904 static const char * week_of_day_str[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
905                                           "Fri", "Sat"};
906 static const char * month_str[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
907                                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
908
909 static int mailimf_date_time_write(FILE * f, int * col,
910                                    struct mailimf_date_time * date_time)
911 {
912   int r;
913   char date_str[MAX_DATE_STR];
914 #if 0
915   struct tm tmval;
916   time_t timeval;
917 #endif
918   int wday;
919   
920 #if 0
921   tmval.tm_sec  = date_time->sec;
922   tmval.tm_min  = date_time->min;
923   tmval.tm_hour  = date_time->hour;
924   tmval.tm_sec  = date_time->sec;
925   tmval.tm_mday = date_time->day;
926   tmval.tm_mon = date_time->month - 1;
927   tmval.tm_year = date_time->year - 1900;
928   tmval.tm_isdst = 1;
929
930   timeval = mktime(&tmval);
931   
932   localtime_r(&timeval, &tmval);
933 #endif
934
935   wday = dayofweek(date_time->dt_year, date_time->dt_month, date_time->dt_day);
936
937   snprintf(date_str, MAX_DATE_STR, "%s, %i %s %i %02i:%02i:%02i %+05i",
938       week_of_day_str[wday], date_time->dt_day,
939       month_str[date_time->dt_month - 1],
940       date_time->dt_year, date_time->dt_hour,
941       date_time->dt_min, date_time->dt_sec,
942       date_time->dt_zone);
943
944   r = mailimf_string_write(f, col, date_str, strlen(date_str));
945
946   if (r != MAILIMF_NO_ERROR)
947     return r;
948
949   return MAILIMF_NO_ERROR;
950 }
951
952 static int mailimf_from_write(FILE * f, int * col,
953                               struct mailimf_from * from)
954 {
955   int r;
956
957   r = mailimf_string_write(f, col, "From: ", 6);
958   if (r != MAILIMF_NO_ERROR)
959     return r;
960
961   r = mailimf_mailbox_list_write(f, col, from->frm_mb_list);
962   if (r != MAILIMF_NO_ERROR)
963     return r;
964
965   r = mailimf_string_write(f, col, "\r\n", 2);
966   if (r != MAILIMF_NO_ERROR)
967     return r;
968 #if 0
969   * col = 0;
970 #endif
971
972   return MAILIMF_NO_ERROR;
973 }
974
975 static int mailimf_sender_write(FILE * f, int * col,
976                                 struct mailimf_sender * sender)
977 {
978   int r;
979
980   r = mailimf_string_write(f, col, "Sender: ", 8);
981   if (r != MAILIMF_NO_ERROR)
982     return r;
983
984   r = mailimf_mailbox_write(f, col, sender->snd_mb);
985   if (r != MAILIMF_NO_ERROR)
986     return r;
987
988   r = mailimf_string_write(f, col, "\r\n", 2);
989   if (r != MAILIMF_NO_ERROR)
990     return r;
991 #if 0
992   * col = 0;
993 #endif
994
995   return MAILIMF_NO_ERROR;
996 }
997
998 static int mailimf_reply_to_write(FILE * f, int * col,
999                                   struct mailimf_reply_to * reply_to)
1000 {
1001   int r;
1002
1003   r = mailimf_string_write(f, col, "Reply-To: ", 10);
1004   if (r != MAILIMF_NO_ERROR)
1005     return r;
1006
1007   r = mailimf_address_list_write(f, col, reply_to->rt_addr_list);
1008   if (r != MAILIMF_NO_ERROR)
1009     return r;
1010
1011   r = mailimf_string_write(f, col, "\r\n", 2);
1012   if (r != MAILIMF_NO_ERROR)
1013     return r;
1014 #if 0
1015   * col = 0;
1016 #endif
1017
1018   return MAILIMF_NO_ERROR;
1019 }
1020
1021
1022 static int mailimf_to_write(FILE * f, int * col,
1023                             struct mailimf_to * to)
1024 {
1025   int r;
1026
1027   r = mailimf_string_write(f, col, "To: ", 4);
1028   if (r != MAILIMF_NO_ERROR)
1029     return r;
1030
1031   r = mailimf_address_list_write(f, col, to->to_addr_list);
1032   if (r != MAILIMF_NO_ERROR)
1033     return r;
1034
1035   r = mailimf_string_write(f, col, "\r\n", 2);
1036   if (r != MAILIMF_NO_ERROR)
1037     return r;
1038 #if 0
1039   * col = 0;
1040 #endif
1041
1042   return MAILIMF_NO_ERROR;
1043 }
1044
1045
1046 static int mailimf_cc_write(FILE * f, int * col,
1047                             struct mailimf_cc * cc)
1048 {
1049   int r;
1050
1051   r = mailimf_string_write(f, col, "Cc: ", 4);
1052   if (r != MAILIMF_NO_ERROR)
1053     return r;
1054
1055   r = mailimf_address_list_write(f, col, cc->cc_addr_list);
1056   if (r != MAILIMF_NO_ERROR)
1057     return r;
1058
1059   r = mailimf_string_write(f, col, "\r\n", 2);
1060   if (r != MAILIMF_NO_ERROR)
1061     return r;
1062 #if 0
1063   * col = 0;
1064 #endif
1065
1066   return MAILIMF_NO_ERROR;
1067 }
1068
1069
1070 static int mailimf_bcc_write(FILE * f, int * col,
1071                              struct mailimf_bcc * bcc)
1072 {
1073   int r;
1074
1075   r = mailimf_string_write(f, col, "Bcc: ", 5);
1076   if (r != MAILIMF_NO_ERROR)
1077     return r;
1078
1079   if (bcc->bcc_addr_list != NULL) {
1080     r =  mailimf_address_list_write(f, col, bcc->bcc_addr_list);
1081     if (r != MAILIMF_NO_ERROR)
1082       return r;
1083   }
1084
1085   r = mailimf_string_write(f, col, "\r\n", 2);
1086   if (r != MAILIMF_NO_ERROR)
1087     return r;
1088 #if 0
1089   * col = 0;
1090 #endif
1091
1092   return MAILIMF_NO_ERROR;
1093 }
1094
1095
1096 static int mailimf_message_id_write(FILE * f, int * col,
1097                                     struct mailimf_message_id * message_id)
1098 {
1099   int r;
1100
1101   r = mailimf_string_write(f, col, "Message-ID: ", 12);
1102   if (r != MAILIMF_NO_ERROR)
1103     return r;
1104
1105   r = mailimf_string_write(f, col, "<", 1);
1106   if (r != MAILIMF_NO_ERROR)
1107     return r;
1108
1109   r = mailimf_string_write(f, col,
1110       message_id->mid_value,
1111       strlen(message_id->mid_value));
1112   if (r != MAILIMF_NO_ERROR)
1113     return r;
1114
1115   r = mailimf_string_write(f, col, ">", 1);
1116   if (r != MAILIMF_NO_ERROR)
1117     return r;
1118
1119   r = mailimf_string_write(f, col, "\r\n", 2);
1120   if (r != MAILIMF_NO_ERROR)
1121     return r;
1122 #if 0
1123   * col = 0;
1124 #endif
1125
1126   return MAILIMF_NO_ERROR;
1127 }
1128
1129
1130 static int mailimf_msg_id_list_write(FILE * f, int * col, clist * mid_list)
1131 {
1132   clistiter * cur;
1133   int r;
1134   int first;
1135
1136   first = TRUE;
1137
1138   for(cur = clist_begin(mid_list) ; cur != NULL ; cur = clist_next(cur)) {
1139     char * msgid;
1140     size_t len;
1141
1142     msgid = clist_content(cur);
1143     len = strlen(msgid);
1144     
1145     /*
1146       XXX - if this is the first message ID, don't fold.
1147       This is a workaround for a bug of old versions of INN.
1148     */
1149     if (!first) {
1150       if (* col > 1) {
1151         
1152         if (* col + len >= MAX_MAIL_COL) {
1153           r = mailimf_string_write(f, col, "\r\n ", 3);
1154           if (r != MAILIMF_NO_ERROR)
1155             return r;
1156 #if 0
1157           * col = 1;
1158 #endif
1159           first = TRUE;
1160         }
1161       }
1162     }
1163     
1164     if (!first) {
1165       r = mailimf_string_write(f, col, " ", 1);
1166       if (r != MAILIMF_NO_ERROR)
1167         return r;
1168     }
1169     else {
1170       first = FALSE;
1171     }
1172
1173     r = mailimf_string_write(f, col, "<", 1);
1174     if (r != MAILIMF_NO_ERROR)
1175       return r;
1176
1177     r = mailimf_string_write(f, col, msgid, len);
1178     if (r != MAILIMF_NO_ERROR)
1179       return r;
1180
1181     r = mailimf_string_write(f, col, ">", 1);
1182     if (r != MAILIMF_NO_ERROR)
1183       return r;
1184   }
1185
1186   return MAILIMF_NO_ERROR;
1187 }
1188
1189
1190 static int mailimf_in_reply_to_write(FILE * f, int * col,
1191                                      struct mailimf_in_reply_to * in_reply_to)
1192 {
1193   int r;
1194
1195   r = mailimf_string_write(f, col, "In-Reply-To: ", 13);
1196   if (r != MAILIMF_NO_ERROR)
1197     return r;
1198
1199   r = mailimf_msg_id_list_write(f, col, in_reply_to->mid_list);
1200   if (r != MAILIMF_NO_ERROR)
1201     return r;
1202
1203   r = mailimf_string_write(f, col, "\r\n", 2);
1204   if (r != MAILIMF_NO_ERROR)
1205     return r;
1206 #if 0
1207   * col = 0;
1208 #endif
1209
1210   return MAILIMF_NO_ERROR;
1211 }
1212
1213
1214 static int mailimf_references_write(FILE * f, int * col,
1215                                     struct mailimf_references * references)
1216 {
1217   int r;
1218
1219   r = mailimf_string_write(f, col, "References: ", 12);
1220   if (r != MAILIMF_NO_ERROR)
1221     return r;
1222
1223   r = mailimf_msg_id_list_write(f, col, references->mid_list);
1224   if (r != MAILIMF_NO_ERROR)
1225     return r;
1226
1227   r = mailimf_string_write(f, col, "\r\n", 2);
1228   if (r != MAILIMF_NO_ERROR)
1229     return r;
1230 #if 0
1231   * col = 0;
1232 #endif
1233
1234   return MAILIMF_NO_ERROR;
1235 }
1236
1237
1238
1239 static int mailimf_subject_write(FILE * f, int * col,
1240                                  struct mailimf_subject * subject)
1241 {
1242   int r;
1243
1244   r = mailimf_string_write(f, col, "Subject: ", 9);
1245   if (r != MAILIMF_NO_ERROR)
1246     return r;
1247
1248   r = mailimf_header_string_write(f, col,
1249       subject->sbj_value, strlen(subject->sbj_value));
1250   if (r != MAILIMF_NO_ERROR)
1251     return r;
1252
1253   r = mailimf_string_write(f, col, "\r\n", 2);
1254   if (r != MAILIMF_NO_ERROR)
1255     return r;
1256 #if 0
1257   * col = 0;
1258 #endif
1259
1260   return MAILIMF_NO_ERROR;
1261 }
1262
1263 int mailimf_address_list_write(FILE * f, int * col,
1264     struct mailimf_address_list * addr_list)
1265 {
1266   clistiter * cur;
1267   int r;
1268   int first;
1269
1270   first = TRUE;
1271
1272   for(cur = clist_begin(addr_list->ad_list) ; cur != NULL ;
1273       cur = clist_next(cur)) {
1274     struct mailimf_address * addr;
1275
1276     addr = clist_content(cur);
1277
1278     if (!first) {
1279       r = mailimf_string_write(f, col, ", ", 2);
1280       if (r != MAILIMF_NO_ERROR)
1281         return r;
1282     }
1283     else {
1284       first = FALSE;
1285     }
1286
1287     r = mailimf_address_write(f, col, addr);
1288     if (r != MAILIMF_NO_ERROR)
1289       return r;
1290   }
1291
1292   return MAILIMF_NO_ERROR;
1293 }
1294
1295
1296 static int mailimf_address_write(FILE * f, int * col,
1297                                  struct mailimf_address * addr)
1298 {
1299   int r;
1300
1301   switch(addr->ad_type) {
1302   case MAILIMF_ADDRESS_MAILBOX:
1303     r = mailimf_mailbox_write(f, col, addr->ad_data.ad_mailbox);
1304     if (r != MAILIMF_NO_ERROR)
1305       return r;
1306
1307     break;
1308
1309   case MAILIMF_ADDRESS_GROUP:
1310     r = mailimf_group_write(f, col, addr->ad_data.ad_group);
1311     if (r != MAILIMF_NO_ERROR)
1312       return r;
1313     
1314     break;
1315   }
1316
1317   return MAILIMF_NO_ERROR;
1318 }
1319
1320
1321 static int mailimf_group_write(FILE * f, int * col,
1322                                struct mailimf_group * group)
1323 {
1324   int r;
1325
1326   r = mailimf_header_string_write(f, col, group->grp_display_name,
1327       strlen(group->grp_display_name));
1328   if (r != MAILIMF_NO_ERROR)
1329     return r;
1330
1331   r = mailimf_string_write(f, col, ": ", 2);
1332   if (r != MAILIMF_NO_ERROR)
1333     return r;
1334   
1335   if (group->grp_mb_list != NULL) {
1336     r = mailimf_mailbox_list_write(f, col, group->grp_mb_list);
1337     if (r != MAILIMF_NO_ERROR)
1338       return r;
1339   }
1340
1341   r = mailimf_string_write(f, col, ";", 1);
1342   if (r != MAILIMF_NO_ERROR)
1343     return r;
1344
1345   return MAILIMF_NO_ERROR;
1346 }
1347
1348
1349 int mailimf_mailbox_list_write(FILE * f, int * col,
1350     struct mailimf_mailbox_list * mb_list)
1351 {
1352   clistiter * cur;
1353   int r;
1354   int first;
1355
1356   first = TRUE;
1357
1358   for(cur = clist_begin(mb_list->mb_list) ; cur != NULL ;
1359       cur = clist_next(cur)) {
1360     struct mailimf_mailbox * mb;
1361
1362     mb = clist_content(cur);
1363
1364     if (!first) {
1365       r = mailimf_string_write(f, col, ", ", 2);
1366       if (r != MAILIMF_NO_ERROR)
1367         return r;
1368     }
1369     else {
1370       first = FALSE;
1371     }
1372
1373     r = mailimf_mailbox_write(f, col, mb);
1374     if (r != MAILIMF_NO_ERROR)
1375       return r;
1376   }
1377
1378   return MAILIMF_NO_ERROR;
1379 }
1380
1381
1382 int mailimf_quoted_string_write(FILE * f, int * col,
1383     const char * string, size_t len)
1384 {
1385   int r;
1386   size_t i;
1387
1388   fputc('\"', f);
1389   for(i = 0 ; i < len ; i ++) {
1390     switch (string[i]) {
1391     case '\\':
1392     case '\"':
1393       r = fputc('\\', f);
1394       if (r < 0)
1395         return MAILIMF_ERROR_FILE;
1396       r = fputc(string[i], f);
1397       if (r < 0)
1398         return MAILIMF_ERROR_FILE;
1399       (* col) += 2;
1400       break;
1401
1402     default:
1403       r = fputc(string[i], f);
1404       if (r < 0)
1405         return MAILIMF_ERROR_FILE;
1406       (* col) ++;
1407       break;
1408     }
1409   }
1410   fputc('\"', f);
1411
1412   return MAILIMF_NO_ERROR;
1413 }
1414
1415
1416 /*
1417 static int 
1418 atext           =       ALPHA / DIGIT / ; Any character except controls,
1419                         "!" / "#" /     ;  SP, and specials.
1420                         "$" / "%" /     ;  Used for atoms
1421                         "&" / "'" /
1422                         "*" / "+" /
1423                         "-" / "/" /
1424                         "=" / "?" /
1425                         "^" / "_" /
1426                         "`" / "{" /
1427                         "|" / "}" /
1428                         "~"
1429 */
1430
1431 static int is_atext(const char * s)
1432 {
1433   const char * p;
1434
1435   for(p = s ; * p != 0 ; p ++) {
1436     if (isalpha((unsigned char) * p))
1437       continue;
1438     if (isdigit((unsigned char) * p))
1439       continue;
1440     switch (*p) {
1441     case ' ':
1442     case '\t':
1443     case '!':
1444     case '#':
1445     case '$':
1446     case '%':
1447     case '&':
1448     case '\'':
1449     case '*':
1450     case '+':
1451     case '-':
1452     case '/':
1453     case '=':
1454     case '?':
1455     case '^':
1456     case '_':
1457     case '`':
1458     case '{':
1459     case '|':
1460     case '}':
1461     case '~':
1462       break;
1463     default:
1464       return 0;
1465     }
1466   }
1467   
1468   return 1;
1469 }
1470
1471 static int mailimf_mailbox_write(FILE * f, int * col,
1472                                  struct mailimf_mailbox * mb)
1473 {
1474   int r;
1475   int do_fold;
1476   
1477 #if 0
1478   if (* col > 1) {
1479     
1480     if (mb->mb_display_name != NULL) {
1481       if (* col + strlen(mb->mb_display_name) >= MAX_MAIL_COL) {
1482         r = mailimf_string_write(f, col, "\r\n ", 3);
1483         if (r != MAILIMF_NO_ERROR)
1484           return r;
1485 #if 0
1486         * col = 1;
1487 #endif
1488       }
1489     }
1490   }
1491 #endif
1492   
1493   if (mb->mb_display_name) {
1494
1495     if (is_atext(mb->mb_display_name)) {
1496       r = mailimf_header_string_write(f, col, mb->mb_display_name,
1497           strlen(mb->mb_display_name));
1498       if (r != MAILIMF_NO_ERROR)
1499         return r;
1500     }
1501     else {
1502       if (mb->mb_display_name != NULL) {
1503         if (* col + strlen(mb->mb_display_name) >= MAX_MAIL_COL) {
1504           r = mailimf_string_write(f, col, "\r\n ", 3);
1505           if (r != MAILIMF_NO_ERROR)
1506             return r;
1507         }
1508       }
1509       
1510       if (strlen(mb->mb_display_name) > MAX_VALID_IMF_LINE / 2)
1511         return MAILIMF_ERROR_INVAL;
1512       
1513       r = mailimf_quoted_string_write(f, col, mb->mb_display_name,
1514           strlen(mb->mb_display_name));
1515       if (r != MAILIMF_NO_ERROR)
1516         return r;
1517     }
1518     
1519     do_fold = 0;
1520     if (* col > 1) {
1521       
1522       if (* col + strlen(mb->mb_addr_spec) + 3 >= MAX_MAIL_COL) {
1523         r = mailimf_string_write(f, col, "\r\n ", 3);
1524         if (r != MAILIMF_NO_ERROR)
1525           return r;
1526 #if 0
1527         * col = 1;
1528 #endif
1529         do_fold = 1;
1530       }
1531     }
1532     
1533     if (do_fold)
1534       r = mailimf_string_write(f, col, "<", 1);
1535     else
1536       r = mailimf_string_write(f, col, " <", 2);
1537     if (r != MAILIMF_NO_ERROR)
1538       return r;
1539
1540     r = mailimf_string_write(f, col, mb->mb_addr_spec,
1541         strlen(mb->mb_addr_spec));
1542     if (r != MAILIMF_NO_ERROR)
1543       return r;
1544
1545     r = mailimf_string_write(f, col, ">", 1);
1546     if (r != MAILIMF_NO_ERROR)
1547       return r;
1548   }
1549   else {
1550     if (* col + strlen(mb->mb_addr_spec) >= MAX_MAIL_COL) {
1551       r = mailimf_string_write(f, col, "\r\n ", 3);
1552       if (r != MAILIMF_NO_ERROR)
1553         return r;
1554     }
1555     
1556     r = mailimf_string_write(f, col,
1557         mb->mb_addr_spec, strlen(mb->mb_addr_spec));
1558     if (r != MAILIMF_NO_ERROR)
1559       return r;
1560   }
1561
1562
1563   return MAILIMF_NO_ERROR;
1564 }
1565
1566 static int mailimf_comments_write(FILE * f, int * col,
1567                                   struct mailimf_comments * comments)
1568 {
1569   int r;
1570
1571   r = mailimf_string_write(f, col, "Comments: ", 10);
1572   if (r != MAILIMF_NO_ERROR)
1573     return r;
1574
1575   r = mailimf_header_string_write(f, col,
1576       comments->cm_value, strlen(comments->cm_value));
1577   if (r != MAILIMF_NO_ERROR)
1578     return r;
1579
1580   r = mailimf_string_write(f, col, "\r\n", 2);
1581   if (r != MAILIMF_NO_ERROR)
1582     return r;
1583 #if 0
1584   * col = 0;
1585 #endif
1586
1587   return MAILIMF_NO_ERROR;
1588 }
1589
1590 static int mailimf_optional_field_write(FILE * f, int * col,
1591                                         struct mailimf_optional_field * field)
1592 {
1593   int r;
1594
1595   if (strlen(field->fld_name) + 2 > MAX_VALID_IMF_LINE)
1596     return MAILIMF_ERROR_INVAL;
1597   
1598   r = mailimf_string_write(f, col, field->fld_name, strlen(field->fld_name));
1599   if (r != MAILIMF_NO_ERROR)
1600     return r;
1601
1602   r = mailimf_string_write(f, col, ": ", 2);
1603   if (r != MAILIMF_NO_ERROR)
1604     return r;
1605
1606   r = mailimf_header_string_write(f, col, field->fld_value,
1607       strlen(field->fld_value));
1608   if (r != MAILIMF_NO_ERROR)
1609     return r;
1610
1611 #if 0
1612   /* XXX parsing debug */
1613   mailimf_string_write(f, col, " (X)", 4);
1614 #endif
1615
1616   r = mailimf_string_write(f, col, "\r\n", 2);
1617   if (r != MAILIMF_NO_ERROR)
1618     return r;
1619 #if 0
1620   * col = 0;
1621 #endif
1622
1623   return MAILIMF_NO_ERROR;
1624 }
1625
1626 static int mailimf_keywords_write(FILE * f, int * col,
1627                                   struct mailimf_keywords * keywords)
1628 {
1629   int r;
1630   clistiter * cur;
1631   int first;
1632   
1633   r = mailimf_string_write(f, col, "Keywords: ", 10);
1634   if (r != MAILIMF_NO_ERROR)
1635     return r;
1636
1637   first = TRUE;
1638
1639   for(cur = clist_begin(keywords->kw_list) ; cur != NULL ;
1640       cur = clist_next(cur)) {
1641     char * keyword;
1642     size_t len;
1643
1644     keyword = clist_content(cur);
1645     len = strlen(keyword);
1646
1647     if (!first) {
1648       r = mailimf_string_write(f, col, ", ", 2);
1649       if (r != MAILIMF_NO_ERROR)
1650         return r;
1651     }
1652     else {
1653       first = FALSE;
1654     }
1655
1656 #if 0
1657     if (* col > 1) {
1658       
1659       if (* col + len >= MAX_MAIL_COL) {
1660         r = mailimf_string_write(f, col, "\r\n ", 3);
1661         if (r != MAILIMF_NO_ERROR)
1662           return r;
1663 #if 0
1664         * col = 1;
1665 #endif
1666       }
1667     }
1668 #endif
1669
1670     r = mailimf_header_string_write(f, col, keyword, len);
1671     if (r != MAILIMF_NO_ERROR)
1672       return r;
1673   }
1674
1675   r = mailimf_string_write(f, col, "\r\n", 2);
1676   if (r != MAILIMF_NO_ERROR)
1677     return r;
1678 #if 0
1679   * col = 0;
1680 #endif
1681
1682   return MAILIMF_NO_ERROR;
1683 }
1684
1685 #if 0
1686 static int mailimf_delivering_info_write(FILE * f, int * col,
1687                                          struct mailimf_delivering_info * info)
1688 {
1689   clistiter * cur;
1690   int r;
1691
1692   for(cur = clist_begin(info->received_fields) ;
1693       cur != NULL ; cur = cur->next) {
1694     struct mailimf_trace_resent_fields * field;
1695
1696     field = cur->data;
1697
1698     r = mailimf_trace_resent_fields_write(f, col, field);
1699     if (r != MAILIMF_NO_ERROR)
1700       return r;
1701   }
1702
1703   return MAILIMF_NO_ERROR;
1704 }
1705
1706
1707 static int
1708 mailimf_trace_resent_fields_write(FILE * f, int * col,
1709                                   struct mailimf_trace_resent_fields * field)
1710 {
1711   int r;
1712
1713   if (field->return_path != NULL) {
1714     r = mailimf_return_write(f, col, field->return_path);
1715     if (r != MAILIMF_NO_ERROR)
1716       return r;
1717   }
1718
1719   if (field->resent_fields != NULL) {
1720     r = mailimf_resent_fields_write(f, col, field->resent_fields);
1721     if (r != MAILIMF_NO_ERROR)
1722       return r;
1723   }
1724
1725   return MAILIMF_NO_ERROR;
1726 }
1727 #endif
1728
1729 static int mailimf_return_write(FILE * f, int * col,
1730                                 struct mailimf_return * return_path)
1731 {
1732   int r;
1733
1734   r = mailimf_string_write(f, col, "Return-Path: ", 13);
1735   if (r != MAILIMF_NO_ERROR)
1736     return r;
1737
1738   r = mailimf_path_write(f, col, return_path->ret_path);
1739   if (r != MAILIMF_NO_ERROR)
1740     return r;
1741
1742   r = mailimf_string_write(f, col, "\r\n", 2);
1743   if (r != MAILIMF_NO_ERROR)
1744     return r;
1745 #if 0
1746   * col = 0;
1747 #endif
1748
1749   return MAILIMF_NO_ERROR;
1750 }
1751
1752 static int mailimf_path_write(FILE * f, int * col,
1753                               struct mailimf_path * path)
1754 {
1755   int r;
1756
1757   r = mailimf_string_write(f, col, "<", 1);
1758   if (r != MAILIMF_NO_ERROR)
1759     return r;
1760
1761   r = mailimf_string_write(f, col, path->pt_addr_spec,
1762       strlen(path->pt_addr_spec));
1763   if (r != MAILIMF_NO_ERROR)
1764     return r;
1765
1766   r = mailimf_string_write(f, col, ">", 1);
1767   if (r != MAILIMF_NO_ERROR)
1768     return r;
1769
1770   return MAILIMF_NO_ERROR;
1771 }
1772
1773 #if 0
1774 static int mailimf_resent_fields_write(FILE * f, int * col,
1775                                        struct mailimf_resent_fields_list *
1776                                        resent_fields)
1777 {
1778   clistiter * cur;
1779   int r;
1780
1781   for(cur = clist_begin(resent_fields->list) ; cur != NULL ; cur = cur->next) {
1782     struct mailimf_resent_field * field;
1783
1784     field = cur->data;
1785
1786     r = mailimf_resent_field_write(f, col, field);
1787     if (r != MAILIMF_NO_ERROR)
1788       return r;
1789   }
1790
1791   return MAILIMF_NO_ERROR;
1792 }
1793
1794
1795
1796 static int mailimf_resent_field_write(FILE * f, int * col,
1797                                       struct mailimf_resent_field *
1798                                       resent_field)
1799 {
1800   int r;
1801
1802   switch (resent_field->type) {
1803   case MAILIMF_RESENT_FIELD_DATE:
1804     r = mailimf_resent_date_write(f, col, resent_field->resent_date);
1805     break;
1806
1807   case MAILIMF_RESENT_FIELD_FROM:
1808     r = mailimf_resent_from_write(f, col, resent_field->resent_from);
1809     break;
1810
1811   case MAILIMF_RESENT_FIELD_SENDER:
1812     r = mailimf_resent_sender_write(f, col, resent_field->resent_sender);
1813     break;
1814
1815   case MAILIMF_RESENT_FIELD_TO:
1816     r = mailimf_resent_to_write(f, col, resent_field->resent_to);
1817     break;
1818
1819   case MAILIMF_RESENT_FIELD_CC:
1820     r = mailimf_resent_cc_write(f, col, resent_field->resent_cc);
1821     break;
1822
1823   case MAILIMF_RESENT_FIELD_BCC:
1824     r = mailimf_resent_bcc_write(f, col, resent_field->resent_bcc);
1825     break;
1826
1827   case MAILIMF_RESENT_FIELD_MSG_ID:
1828     r = mailimf_resent_msg_id_write(f, col, resent_field->resent_msg_id);
1829     break;
1830   default:
1831     r = MAILIMF_ERROR_INVAL;
1832     break;
1833   }
1834
1835
1836   if (r != MAILIMF_NO_ERROR)
1837     return r;
1838
1839   return MAILIMF_NO_ERROR;
1840 }
1841 #endif
1842
1843 static int mailimf_resent_date_write(FILE * f, int * col,
1844                                      struct mailimf_orig_date * date)
1845 {
1846   int r;
1847
1848   r = mailimf_string_write(f, col, "Resent-Date: ", 13);
1849   if (r != MAILIMF_NO_ERROR)
1850     return r;
1851
1852   r = mailimf_date_time_write(f, col, date->dt_date_time);
1853   if (r != MAILIMF_NO_ERROR)
1854     return r;
1855
1856   r = mailimf_string_write(f, col, "\r\n", 2);
1857   if (r != MAILIMF_NO_ERROR)
1858     return r;
1859 #if 0
1860   * col = 0;
1861 #endif
1862
1863   return MAILIMF_NO_ERROR;
1864 }
1865
1866 static int mailimf_resent_from_write(FILE * f, int * col,
1867                                      struct mailimf_from * from)
1868 {
1869   int r;
1870
1871   r = mailimf_string_write(f, col, "Resent-From: ", 13);
1872   if (r != MAILIMF_NO_ERROR)
1873     return r;
1874
1875   r = mailimf_mailbox_list_write(f, col, from->frm_mb_list);
1876   if (r != MAILIMF_NO_ERROR)
1877     return r;
1878
1879   r = mailimf_string_write(f, col, "\r\n", 2);
1880   if (r != MAILIMF_NO_ERROR)
1881     return r;
1882 #if 0
1883   * col = 0;
1884 #endif
1885
1886   return MAILIMF_NO_ERROR;
1887 }
1888
1889 static int mailimf_resent_sender_write(FILE * f, int * col,
1890                                        struct mailimf_sender * sender)
1891 {
1892   int r;
1893
1894   r = mailimf_string_write(f, col, "Resent-Sender: ", 15);
1895   if (r != MAILIMF_NO_ERROR)
1896     return r;
1897
1898   r = mailimf_mailbox_write(f, col, sender->snd_mb);
1899   if (r != MAILIMF_NO_ERROR)
1900     return r;
1901
1902   r = mailimf_string_write(f, col, "\r\n", 2);
1903   if (r != MAILIMF_NO_ERROR)
1904     return r;
1905 #if 0
1906   * col = 0;
1907 #endif
1908
1909   return MAILIMF_NO_ERROR;
1910 }
1911
1912 static int mailimf_resent_to_write(FILE * f, int * col,
1913                                    struct mailimf_to * to)
1914 {
1915   int r;
1916
1917   r = mailimf_string_write(f, col, "Resent-To: ", 11);
1918   if (r != MAILIMF_NO_ERROR)
1919     return r;
1920
1921   r = mailimf_address_list_write(f, col, to->to_addr_list);
1922   if (r != MAILIMF_NO_ERROR)
1923     return r;
1924
1925   r = mailimf_string_write(f, col, "\r\n", 2);
1926   if (r != MAILIMF_NO_ERROR)
1927     return r;
1928 #if 0
1929   * col = 0;
1930 #endif
1931
1932   return MAILIMF_NO_ERROR;
1933 }
1934
1935
1936 static int mailimf_resent_cc_write(FILE * f, int * col,
1937                                    struct mailimf_cc * cc)
1938 {
1939   int r;
1940
1941   r = mailimf_string_write(f, col, "Resent-Cc: ", 11);
1942   if (r != MAILIMF_NO_ERROR)
1943     return r;
1944
1945   r = mailimf_address_list_write(f, col, cc->cc_addr_list);
1946   if (r != MAILIMF_NO_ERROR)
1947     return r;
1948
1949   r = mailimf_string_write(f, col, "\r\n", 2);
1950   if (r != MAILIMF_NO_ERROR)
1951     return r;
1952 #if 0
1953   * col = 0;
1954 #endif
1955
1956   return MAILIMF_NO_ERROR;
1957 }
1958
1959
1960 static int mailimf_resent_bcc_write(FILE * f, int * col,
1961                                     struct mailimf_bcc * bcc)
1962 {
1963   int r;
1964
1965   r = mailimf_string_write(f, col, "Resent-Bcc: ", 12);
1966   if (r != MAILIMF_NO_ERROR)
1967     return r;
1968
1969   if (bcc->bcc_addr_list != NULL) {
1970     r =  mailimf_address_list_write(f, col, bcc->bcc_addr_list);
1971     if (r != MAILIMF_NO_ERROR)
1972       return r;
1973   }
1974
1975   r = mailimf_string_write(f, col, "\r\n", 2);
1976   if (r != MAILIMF_NO_ERROR)
1977     return r;
1978 #if 0
1979   * col = 0;
1980 #endif
1981
1982   return MAILIMF_NO_ERROR;
1983 }
1984
1985
1986 static int
1987 mailimf_resent_msg_id_write(FILE * f, int * col,
1988                             struct mailimf_message_id * message_id)
1989 {
1990   int r;
1991
1992   r = mailimf_string_write(f, col, "Resent-Message-ID: ", 19);
1993   if (r != MAILIMF_NO_ERROR)
1994     return r;
1995
1996   r = mailimf_string_write(f, col, "<", 1);
1997   if (r != MAILIMF_NO_ERROR)
1998     return r;
1999
2000   r = mailimf_string_write(f, col,
2001       message_id->mid_value, strlen(message_id->mid_value));
2002   if (r != MAILIMF_NO_ERROR)
2003     return r;
2004
2005   r = mailimf_string_write(f, col, ">", 1);
2006   if (r != MAILIMF_NO_ERROR)
2007     return r;
2008
2009   r = mailimf_string_write(f, col, "\r\n", 2);
2010   if (r != MAILIMF_NO_ERROR)
2011     return r;
2012 #if 0
2013   * col = 0;
2014 #endif
2015
2016   return MAILIMF_NO_ERROR;
2017 }