Fix another use-after-free
[claws.git] / src / plugins / mailmbox / mailimf_types_helper.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 #include "mailimf_types_helper.h"
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 #include <unistd.h>
38
39 #include "mailimf.h"
40
41 struct mailimf_mailbox_list *
42 mailimf_mailbox_list_new_empty()
43 {
44   clist * list;
45   struct mailimf_mailbox_list * mb_list;
46
47   list = clist_new();
48   if (list == NULL)
49     return NULL;
50
51   mb_list = mailimf_mailbox_list_new(list);
52   if (mb_list == NULL)
53     return NULL;
54
55   return mb_list;
56 }
57
58 int mailimf_mailbox_list_add(struct mailimf_mailbox_list * mailbox_list,
59                              struct mailimf_mailbox * mb)
60 {
61   int r;
62
63   r = clist_append(mailbox_list->mb_list, mb);
64   if (r < 0)
65     return MAILIMF_ERROR_MEMORY;
66
67   return MAILIMF_NO_ERROR;
68 }
69
70 int mailimf_mailbox_list_add_parse(struct mailimf_mailbox_list * mailbox_list,
71                                    char * mb_str)
72 {
73   int r;
74   size_t cur_token;
75   struct mailimf_mailbox * mb;
76   int res;
77
78   cur_token = 0;
79   r = mailimf_mailbox_parse(mb_str, strlen(mb_str), &cur_token, &mb);
80   if (r != MAILIMF_NO_ERROR) {
81     res = r;
82     goto err;
83   }
84   
85   r = mailimf_mailbox_list_add(mailbox_list, mb);
86   if (r != MAILIMF_NO_ERROR) {
87     res = r;
88     goto free;
89   }
90
91   return MAILIMF_NO_ERROR;
92
93  free:
94   mailimf_mailbox_free(mb);
95  err:
96   return res;
97 }
98
99 int mailimf_mailbox_list_add_mb(struct mailimf_mailbox_list * mailbox_list,
100                                 char * display_name, char * address)
101 {
102   int r;
103   struct mailimf_mailbox * mb;
104   int res;
105
106   mb = mailimf_mailbox_new(display_name, address);
107   if (mb == NULL) {
108     res = MAILIMF_ERROR_MEMORY;
109     goto err;
110   }
111   
112   r = mailimf_mailbox_list_add(mailbox_list, mb);
113   if (r != MAILIMF_NO_ERROR) {
114     res = r;
115     goto free;
116   }
117
118   return MAILIMF_NO_ERROR;
119
120  free:
121   mailimf_mailbox_free(mb);
122  err:
123   return res;
124 }
125
126
127
128 struct mailimf_address_list *
129 mailimf_address_list_new_empty()
130 {
131   clist * list;
132   struct mailimf_address_list * addr_list;
133
134   list = clist_new();
135   if (list == NULL)
136     return NULL;
137
138   addr_list = mailimf_address_list_new(list);
139   if (addr_list == NULL)
140     return NULL;
141
142   return addr_list;
143 }
144
145 int mailimf_address_list_add(struct mailimf_address_list * address_list,
146                              struct mailimf_address * addr)
147 {
148   int r;
149
150   r = clist_append(address_list->ad_list, addr);
151   if (r < 0)
152     return MAILIMF_ERROR_MEMORY;
153
154   return MAILIMF_NO_ERROR;
155 }
156
157 int mailimf_address_list_add_parse(struct mailimf_address_list * address_list,
158                                    char * addr_str)
159 {
160   int r;
161   size_t cur_token;
162   struct mailimf_address * addr;
163   int res;
164
165   cur_token = 0;
166   r = mailimf_address_parse(addr_str, strlen(addr_str), &cur_token, &addr);
167   if (r != MAILIMF_NO_ERROR) {
168     res = r;
169     goto err;
170   }
171   
172   r = mailimf_address_list_add(address_list, addr);
173   if (r != MAILIMF_NO_ERROR) {
174     res = r;
175     goto free;
176   }
177
178   return MAILIMF_NO_ERROR;
179
180  free:
181   mailimf_address_free(addr);
182  err:
183   return res;
184 }
185
186 int mailimf_address_list_add_mb(struct mailimf_address_list * address_list,
187                                 char * display_name, char * address)
188 {
189   int r;
190   struct mailimf_mailbox * mb;
191   struct mailimf_address * addr;
192   int res;
193
194   mb = mailimf_mailbox_new(display_name, address);
195   if (mb == NULL) {
196     res = MAILIMF_ERROR_MEMORY;
197     goto err;
198   }
199
200   addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
201   if (addr == NULL) {
202     res = MAILIMF_ERROR_MEMORY;
203     goto free_mb;
204   }
205
206   r = mailimf_address_list_add(address_list, addr);
207   if (r != MAILIMF_NO_ERROR) {
208     res = r;
209     goto free_addr;
210   }
211
212   return MAILIMF_NO_ERROR;
213
214  free_addr:
215   mailimf_address_free(addr);
216  free_mb:
217   mailimf_mailbox_free(mb);
218  err:
219   return res;
220 }
221
222
223 #if 0
224 struct mailimf_resent_fields_list *
225 mailimf_resent_fields_list_new_empty()
226 {
227   clist * list;
228   struct mailimf_resent_fields_list * rf_list;
229
230   list = clist_new();
231   if (list == NULL)
232     return NULL;
233
234   rf_list = mailimf_resent_fields_list_new(list);
235   if (rf_list == NULL)
236     return NULL;
237
238   return rf_list;
239 }
240
241 int mailimf_resent_fields_add(struct mailimf_resent_fields_list * fields,
242                               struct mailimf_resent_field * field)
243 {
244   int r;
245
246   r = clist_append(fields->list, field);
247   if (r < 0)
248     return MAILIMF_ERROR_MEMORY;
249   
250   return MAILIMF_NO_ERROR;
251 }
252 #endif
253
254
255 static void detach_free_common_fields(struct mailimf_orig_date * imf_date,
256                                       struct mailimf_from * imf_from,
257                                       struct mailimf_sender * imf_sender,
258                                       struct mailimf_to * imf_to,
259                                       struct mailimf_cc * imf_cc,
260                                       struct mailimf_bcc * imf_bcc,
261                                       struct mailimf_message_id * imf_msg_id)
262 {
263   if (imf_date != NULL) {
264     imf_date->dt_date_time = NULL;
265     mailimf_orig_date_free(imf_date);
266   }
267   if (imf_from != NULL) {
268     imf_from->frm_mb_list = NULL;
269     mailimf_from_free(imf_from);
270   }
271   if (imf_sender != NULL) {
272     imf_sender->snd_mb = NULL;
273     mailimf_sender_free(imf_sender);
274   }
275   if (imf_to != NULL) {
276     imf_to->to_addr_list = NULL;
277     mailimf_to_free(imf_to);
278   }
279   if (imf_cc != NULL) {
280     imf_cc->cc_addr_list = NULL;
281     mailimf_to_free(imf_to);
282   }
283   if (imf_bcc != NULL) {
284     imf_bcc->bcc_addr_list = NULL;
285     mailimf_bcc_free(imf_bcc);
286   }
287   if (imf_msg_id != NULL) {
288     imf_msg_id->mid_value = NULL;
289     mailimf_message_id_free(imf_msg_id);
290   }
291 }
292
293 static void detach_resent_field(struct mailimf_field * field)
294 {
295   field->fld_type = MAILIMF_FIELD_NONE;
296   mailimf_field_free(field);
297 }
298
299 int
300 mailimf_resent_fields_add_data(struct mailimf_fields * fields,
301     struct mailimf_date_time * resent_date,
302     struct mailimf_mailbox_list * resent_from,
303     struct mailimf_mailbox * resent_sender,
304     struct mailimf_address_list * resent_to,
305     struct mailimf_address_list * resent_cc,
306     struct mailimf_address_list * resent_bcc,
307     char * resent_msg_id)
308 {
309   struct mailimf_orig_date * imf_resent_date;
310   struct mailimf_from * imf_resent_from;
311   struct mailimf_sender * imf_resent_sender;
312   struct mailimf_to * imf_resent_to;
313   struct mailimf_cc * imf_resent_cc;
314   struct mailimf_bcc * imf_resent_bcc;
315   struct mailimf_message_id * imf_resent_msg_id;
316   struct mailimf_field * field;
317   int r;
318
319   imf_resent_date = NULL;
320   imf_resent_from = NULL;
321   imf_resent_sender = NULL;
322   imf_resent_to = NULL;
323   imf_resent_cc = NULL;
324   imf_resent_bcc = NULL;
325   imf_resent_msg_id = NULL;
326   field = NULL;
327
328   if (resent_date != NULL) {
329     imf_resent_date = mailimf_orig_date_new(resent_date);
330     if (imf_resent_date == NULL)
331       goto free;
332     field = mailimf_field_new(MAILIMF_FIELD_RESENT_DATE,
333         NULL /* return-path */,
334         imf_resent_date /* resent date */,
335         NULL /* resent from */,
336         NULL /* resent sender */,
337         NULL /* resent to */,
338         NULL /* resent cc */,
339         NULL /* resent bcc */,
340         NULL /* resent msg id */,
341         NULL /* date */,
342         NULL /* from */,
343         NULL /* sender */,
344         NULL /* reply-to */,
345         NULL /* to */,
346         NULL /* cc */,
347         NULL /* bcc */,
348         NULL /* message id */,
349         NULL /* in reply to */,
350         NULL /* references */,
351         NULL /* subject */,
352         NULL /* comments */,
353         NULL /* keywords */,
354         NULL /* optional field */);
355     if (field == NULL)
356       goto free;
357     r =  mailimf_fields_add(fields, field);
358     if (r != MAILIMF_NO_ERROR)
359       goto free_field;
360   }
361
362   if (resent_from != NULL) {
363     imf_resent_from = mailimf_from_new(resent_from);
364     if (imf_resent_from == NULL)
365       goto free_field;
366     field = mailimf_field_new(MAILIMF_FIELD_RESENT_FROM,
367         NULL /* return-path */,
368         NULL /* resent date */,
369         imf_resent_from /* resent from */,
370         NULL /* resent sender */,
371         NULL /* resent to */,
372         NULL /* resent cc */,
373         NULL /* resent bcc */,
374         NULL /* resent msg id */,
375         NULL /* date */,
376         NULL /* from */,
377         NULL /* sender */,
378         NULL /* reply-to */,
379         NULL /* to */,
380         NULL /* cc */,
381         NULL /* bcc */,
382         NULL /* message id */,
383         NULL /* in reply to */,
384         NULL /* references */,
385         NULL /* subject */,
386         NULL /* comments */,
387         NULL /* keywords */,
388         NULL /* optional field */);
389     if (field == NULL)
390       goto free;
391     r =  mailimf_fields_add(fields, field);
392     if (r != MAILIMF_NO_ERROR)
393       goto free_field;
394   }
395
396   if (resent_sender != NULL) {
397     imf_resent_sender = mailimf_sender_new(resent_sender);
398     if (imf_resent_sender == NULL)
399       goto free;
400     field = mailimf_field_new(MAILIMF_FIELD_RESENT_SENDER,
401         NULL /* return-path */,
402         NULL /* resent date */,
403         NULL /* resent from */,
404         imf_resent_sender /* resent sender */,
405         NULL /* resent to */,
406         NULL /* resent cc */,
407         NULL /* resent bcc */,
408         NULL /* resent msg id */,
409         NULL /* date */,
410         NULL /* from */,
411         NULL /* sender */,
412         NULL /* reply-to */,
413         NULL /* to */,
414         NULL /* cc */,
415         NULL /* bcc */,
416         NULL /* message id */,
417         NULL /* in reply to */,
418         NULL /* references */,
419         NULL /* subject */,
420         NULL /* comments */,
421         NULL /* keywords */,
422         NULL /* optional field */);
423     if (field == NULL)
424       goto free;
425     r =  mailimf_fields_add(fields, field);
426     if (r != MAILIMF_NO_ERROR)
427       goto free_field;
428   }
429
430   if (resent_to != NULL) {
431     imf_resent_to = mailimf_to_new(resent_to);
432     if (imf_resent_to == NULL)
433       goto free;
434     field = mailimf_field_new(MAILIMF_FIELD_RESENT_TO,
435         NULL /* return-path */,
436         NULL /* resent date */,
437         NULL /* resent from */,
438         NULL /* resent sender */,
439         imf_resent_to /* resent to */,
440         NULL /* resent cc */,
441         NULL /* resent bcc */,
442         NULL /* resent msg id */,
443         NULL /* date */,
444         NULL /* from */,
445         NULL /* sender */,
446         NULL /* reply-to */,
447         NULL /* to */,
448         NULL /* cc */,
449         NULL /* bcc */,
450         NULL /* message id */,
451         NULL /* in reply to */,
452         NULL /* references */,
453         NULL /* subject */,
454         NULL /* comments */,
455         NULL /* keywords */,
456         NULL /* optional field */);
457     if (field == NULL)
458       goto free;
459     r =  mailimf_fields_add(fields, field);
460     if (r != MAILIMF_NO_ERROR)
461       goto free_field;
462   }
463
464   if (resent_cc != NULL) {
465     imf_resent_cc = mailimf_cc_new(resent_cc);
466     if (imf_resent_cc == NULL)
467       goto free;
468     field = mailimf_field_new(MAILIMF_FIELD_RESENT_CC,
469         NULL /* return-path */,
470         NULL /* resent date */,
471         NULL /* resent from */,
472         NULL /* resent sender */,
473         NULL /* resent to */,
474         imf_resent_cc /* resent cc */,
475         NULL /* resent bcc */,
476         NULL /* resent msg id */,
477         NULL /* date */,
478         NULL /* from */,
479         NULL /* sender */,
480         NULL /* reply-to */,
481         NULL /* to */,
482         NULL /* cc */,
483         NULL /* bcc */,
484         NULL /* message id */,
485         NULL /* in reply to */,
486         NULL /* references */,
487         NULL /* subject */,
488         NULL /* comments */,
489         NULL /* keywords */,
490         NULL /* optional field */);
491     if (field == NULL)
492       goto free;
493     r =  mailimf_fields_add(fields, field);
494     if (r != MAILIMF_NO_ERROR)
495       goto free_field;
496   }
497
498   if (resent_bcc != NULL) {
499     imf_resent_bcc = mailimf_bcc_new(resent_bcc);
500     if (imf_resent_bcc == NULL)
501       goto free;
502     field = mailimf_field_new(MAILIMF_FIELD_RESENT_BCC,
503         NULL /* return-path */,
504         NULL /* resent date */,
505         NULL /* resent from */,
506         NULL /* resent sender */,
507         NULL /* resent to */,
508         NULL /* resent cc */,
509         imf_resent_bcc /* resent bcc */,
510         NULL /* resent msg id */,
511         NULL /* date */,
512         NULL /* from */,
513         NULL /* sender */,
514         NULL /* reply-to */,
515         NULL /* to */,
516         NULL /* cc */,
517         NULL /* bcc */,
518         NULL /* message id */,
519         NULL /* in reply to */,
520         NULL /* references */,
521         NULL /* subject */,
522         NULL /* comments */,
523         NULL /* keywords */,
524         NULL /* optional field */);
525     if (field == NULL)
526       goto free;
527     r =  mailimf_fields_add(fields, field);
528     if (r != MAILIMF_NO_ERROR)
529       goto free_field;
530   }
531
532   if (resent_msg_id != NULL) {
533     imf_resent_msg_id = mailimf_message_id_new(resent_msg_id);
534     if (imf_resent_msg_id == NULL)
535       goto free;
536     field = mailimf_field_new(MAILIMF_FIELD_RESENT_MSG_ID,
537         NULL /* return-path */,
538         NULL /* resent date */,
539         NULL /* resent from */,
540         NULL /* resent sender */,
541         NULL /* resent to */,
542         NULL /* resent cc */,
543         NULL /* resent bcc */,
544         imf_resent_msg_id /* resent msg id */,
545         NULL /* date */,
546         NULL /* from */,
547         NULL /* sender */,
548         NULL /* reply-to */,
549         NULL /* to */,
550         NULL /* cc */,
551         NULL /* bcc */,
552         NULL /* message id */,
553         NULL /* in reply to */,
554         NULL /* references */,
555         NULL /* subject */,
556         NULL /* comments */,
557         NULL /* keywords */,
558         NULL /* optional field */);
559     if (field == NULL)
560       goto free;
561     r =  mailimf_fields_add(fields, field);
562     if (r != MAILIMF_NO_ERROR)
563       goto free_field;
564   }
565
566   return MAILIMF_NO_ERROR;
567
568  free_field:
569   if (field != NULL) {
570     detach_resent_field(field);
571   }
572  free:
573   detach_free_common_fields(imf_resent_date,
574                             imf_resent_from,
575                             imf_resent_sender,
576                             imf_resent_to,
577                             imf_resent_cc,
578                             imf_resent_bcc,
579                             imf_resent_msg_id);
580   return MAILIMF_ERROR_MEMORY;
581 }
582
583 struct mailimf_fields *
584 mailimf_resent_fields_new_with_data_all(struct mailimf_date_time *
585     resent_date,
586     struct mailimf_mailbox_list *
587     resent_from,
588     struct mailimf_mailbox *
589     resent_sender,
590     struct mailimf_address_list *
591     resent_to,
592     struct mailimf_address_list *
593     resent_cc,
594     struct mailimf_address_list *
595     resent_bcc,
596     char * resent_msg_id)
597 {
598   struct mailimf_fields * resent_fields;
599   int r;
600
601   resent_fields = mailimf_fields_new_empty();
602   if (resent_fields == NULL)
603     goto err;
604
605   r = mailimf_resent_fields_add_data(resent_fields,
606       resent_date, resent_from,
607       resent_sender, resent_to,
608       resent_cc, resent_bcc,
609       resent_msg_id);
610   if (r != MAILIMF_NO_ERROR)
611     goto free;
612
613   return resent_fields;
614
615  free:
616   mailimf_fields_free(resent_fields);
617  err:
618   return NULL;
619 }
620
621
622 struct mailimf_fields *
623 mailimf_resent_fields_new_with_data(struct mailimf_mailbox_list * from,
624     struct mailimf_mailbox * sender,
625     struct mailimf_address_list * to,
626     struct mailimf_address_list * cc,
627     struct mailimf_address_list * bcc)
628 {
629   struct mailimf_date_time * date;
630   char * msg_id;
631   struct mailimf_fields * fields;
632
633   date = mailimf_get_current_date();
634   if (date == NULL)
635     goto err;
636
637   msg_id = mailimf_get_message_id();
638   if (msg_id == NULL)
639     goto free_date;
640
641   fields = mailimf_resent_fields_new_with_data_all(date,
642       from, sender, to, cc, bcc, msg_id);
643   if (fields == NULL)
644     goto free_msg_id;
645
646   return fields;
647
648  free_msg_id:
649   free(msg_id);
650  free_date:
651   mailimf_date_time_free(date);
652  err:
653   return NULL;
654 }
655
656
657 struct mailimf_fields *
658 mailimf_fields_new_empty(void)
659 {
660   clist * list;
661   struct mailimf_fields * fields_list;
662
663   list = clist_new();
664   if (list == NULL)
665     return NULL;
666
667   fields_list = mailimf_fields_new(list);
668   if (fields_list == NULL)
669     return NULL;
670
671   return fields_list;
672 }
673
674 int mailimf_fields_add(struct mailimf_fields * fields,
675                        struct mailimf_field * field)
676 {
677   int r;
678
679   r = clist_append(fields->fld_list, field);
680   if (r < 0)
681     return MAILIMF_ERROR_MEMORY;
682   
683   return MAILIMF_NO_ERROR;
684 }
685
686 static void detach_free_fields(struct mailimf_orig_date * date,
687                                struct mailimf_from * from,
688                                struct mailimf_sender * sender,
689                                struct mailimf_reply_to * reply_to,
690                                struct mailimf_to * to,
691                                struct mailimf_cc * cc,
692                                struct mailimf_bcc * bcc,
693                                struct mailimf_message_id * msg_id,
694                                struct mailimf_in_reply_to * in_reply_to,
695                                struct mailimf_references * references,
696                                struct mailimf_subject * subject)
697 {
698   detach_free_common_fields(date,
699       from,
700       sender,
701       to,
702       cc,
703       bcc,
704       msg_id);
705
706   if (reply_to != NULL) {
707     reply_to->rt_addr_list = NULL;
708     mailimf_reply_to_free(reply_to);
709   }
710
711   if (in_reply_to != NULL) {
712     in_reply_to->mid_list = NULL;
713     mailimf_in_reply_to_free(in_reply_to);
714   }
715
716   if (references != NULL) {
717     references->mid_list = NULL;
718     mailimf_references_free(references);
719   }
720
721   if (subject != NULL) {
722     subject->sbj_value = NULL;
723     mailimf_subject_free(subject);
724   }
725 }
726
727
728 static void detach_field(struct mailimf_field * field)
729 {
730   field->fld_type = MAILIMF_FIELD_NONE;
731   mailimf_field_free(field);
732 }
733
734 int mailimf_fields_add_data(struct mailimf_fields * fields,
735                             struct mailimf_date_time * date,
736                             struct mailimf_mailbox_list * from,
737                             struct mailimf_mailbox * sender,
738                             struct mailimf_address_list * reply_to,
739                             struct mailimf_address_list * to,
740                             struct mailimf_address_list * cc,
741                             struct mailimf_address_list * bcc,
742                             char * msg_id,
743                             clist * in_reply_to,
744                             clist * references,
745                             char * subject)
746 {
747   struct mailimf_orig_date * imf_date;
748   struct mailimf_from * imf_from;
749   struct mailimf_sender * imf_sender;
750   struct mailimf_reply_to * imf_reply_to;
751   struct mailimf_to * imf_to;
752   struct mailimf_cc * imf_cc;
753   struct mailimf_bcc * imf_bcc;
754   struct mailimf_message_id * imf_msg_id;
755   struct mailimf_references * imf_references;
756   struct mailimf_in_reply_to * imf_in_reply_to;
757   struct mailimf_subject * imf_subject;
758   struct mailimf_field * field;
759   int r;
760
761   imf_date = NULL;
762   imf_from = NULL;
763   imf_sender = NULL;
764   imf_reply_to = NULL;
765   imf_to = NULL;
766   imf_cc = NULL;
767   imf_bcc = NULL;
768   imf_msg_id = NULL;
769   imf_references = NULL;
770   imf_in_reply_to = NULL;
771   imf_subject =NULL;
772   field = NULL;
773
774   if (date != NULL) {
775     imf_date = mailimf_orig_date_new(date);
776     if (imf_date == NULL)
777       goto free;
778     field = mailimf_field_new(MAILIMF_FIELD_ORIG_DATE,
779         NULL /* return-path */,
780         NULL /* resent date */,
781         NULL /* resent from */,
782         NULL /* resent sender */,
783         NULL /* resent to */,
784         NULL /* resent cc */,
785         NULL /* resent bcc */,
786         NULL /* resent msg id */,
787         imf_date /* date */,
788         NULL /* from */,
789         NULL /* sender */,
790         NULL /* reply-to */,
791         NULL /* to */,
792         NULL /* cc */,
793         NULL /* bcc */,
794         NULL /* message id */,
795         NULL /* in reply to */,
796         NULL /* references */,
797         NULL /* subject */,
798         NULL /* comments */,
799         NULL /* keywords */,
800         NULL /* optional field */);
801     if (field == NULL)
802       goto free;
803     r =  mailimf_fields_add(fields, field);
804     if (r != MAILIMF_NO_ERROR)
805       goto free_field;
806   }
807
808   if (from != NULL) {
809     imf_from = mailimf_from_new(from);
810     if (imf_from == NULL)
811       goto free_field;
812     field = mailimf_field_new(MAILIMF_FIELD_FROM,
813         NULL /* return-path */,
814         NULL /* resent date */,
815         NULL /* resent from */,
816         NULL /* resent sender */,
817         NULL /* resent to */,
818         NULL /* resent cc */,
819         NULL /* resent bcc */,
820         NULL /* resent msg id */,
821         NULL /* date */,
822         imf_from /* from */,
823         NULL /* sender */,
824         NULL /* reply-to */,
825         NULL /* to */,
826         NULL /* cc */,
827         NULL /* bcc */,
828         NULL /* message id */,
829         NULL /* in reply to */,
830         NULL /* references */,
831         NULL /* subject */,
832         NULL /* comments */,
833         NULL /* keywords */,
834         NULL /* optional field */);
835     if (field == NULL)
836       goto free;
837     r =  mailimf_fields_add(fields, field);
838     if (r != MAILIMF_NO_ERROR)
839       goto free_field;
840   }
841
842   if (sender != NULL) {
843     imf_sender = mailimf_sender_new(sender);
844     if (imf_sender == NULL)
845       goto free;
846     field = mailimf_field_new(MAILIMF_FIELD_SENDER,
847         NULL /* return-path */,
848         NULL /* resent date */,
849         NULL /* resent from */,
850         NULL /* resent sender */,
851         NULL /* resent to */,
852         NULL /* resent cc */,
853         NULL /* resent bcc */,
854         NULL /* resent msg id */,
855         NULL /* date */,
856         NULL /* from */,
857         imf_sender /* sender */,
858         NULL /* reply-to */,
859         NULL /* to */,
860         NULL /* cc */,
861         NULL /* bcc */,
862         NULL /* message id */,
863         NULL /* in reply to */,
864         NULL /* references */,
865         NULL /* subject */,
866         NULL /* comments */,
867         NULL /* keywords */,
868         NULL /* optional field */);
869     if (field == NULL)
870       goto free;
871     r =  mailimf_fields_add(fields, field);
872     if (r != MAILIMF_NO_ERROR)
873       goto free_field;
874   }
875
876   if (reply_to != NULL) {
877     imf_reply_to = mailimf_reply_to_new(reply_to);
878     if (imf_reply_to == NULL)
879       goto free;
880     field = mailimf_field_new(MAILIMF_FIELD_REPLY_TO,
881         NULL /* return-path */,
882         NULL /* resent date */,
883         NULL /* resent from */,
884         NULL /* resent sender */,
885         NULL /* resent to */,
886         NULL /* resent cc */,
887         NULL /* resent bcc */,
888         NULL /* resent msg id */,
889         NULL /* date */,
890         NULL /* from */,
891         NULL /* sender */,
892         imf_reply_to /* reply-to */,
893         NULL /* to */,
894         NULL /* cc */,
895         NULL /* bcc */,
896         NULL /* message id */,
897         NULL /* in reply to */,
898         NULL /* references */,
899         NULL /* subject */,
900         NULL /* comments */,
901         NULL /* keywords */,
902         NULL /* optional field */);
903     if (field == NULL)
904       goto free;
905     r =  mailimf_fields_add(fields, field);
906     if (r != MAILIMF_NO_ERROR)
907       goto free_field;
908   }
909
910   if (to != NULL) {
911     imf_to = mailimf_to_new(to);
912     if (imf_to == NULL)
913       goto free;
914     field = mailimf_field_new(MAILIMF_FIELD_TO,
915         NULL /* return-path */,
916         NULL /* resent date */,
917         NULL /* resent from */,
918         NULL /* resent sender */,
919         NULL /* resent to */,
920         NULL /* resent cc */,
921         NULL /* resent bcc */,
922         NULL /* resent msg id */,
923         NULL /* date */,
924         NULL /* from */,
925         NULL /* sender */,
926         NULL /* reply-to */,
927         imf_to /* to */,
928         NULL /* cc */,
929         NULL /* bcc */,
930         NULL /* message id */,
931         NULL /* in reply to */,
932         NULL /* references */,
933         NULL /* subject */,
934         NULL /* comments */,
935         NULL /* keywords */,
936         NULL /* optional field */);
937     if (field == NULL)
938       goto free;
939     r =  mailimf_fields_add(fields, field);
940     if (r != MAILIMF_NO_ERROR)
941       goto free_field;
942   }
943
944   if (cc != NULL) {
945     imf_cc = mailimf_cc_new(cc);
946     if (imf_cc == NULL)
947       goto free;
948     field = mailimf_field_new(MAILIMF_FIELD_CC,
949         NULL /* return-path */,
950         NULL /* resent date */,
951         NULL /* resent from */,
952         NULL /* resent sender */,
953         NULL /* resent to */,
954         NULL /* resent cc */,
955         NULL /* resent bcc */,
956         NULL /* resent msg id */,
957         NULL /* date */,
958         NULL /* from */,
959         NULL /* sender */,
960         NULL /* reply-to */,
961         NULL /* to */,
962         imf_cc /* cc */,
963         NULL /* bcc */,
964         NULL /* message id */,
965         NULL /* in reply to */,
966         NULL /* references */,
967         NULL /* subject */,
968         NULL /* comments */,
969         NULL /* keywords */,
970         NULL /* optional field */);
971     if (field == NULL)
972       goto free;
973     r =  mailimf_fields_add(fields, field);
974     if (r != MAILIMF_NO_ERROR)
975       goto free_field;
976   }
977
978   if (bcc != NULL) {
979     imf_bcc = mailimf_bcc_new(bcc);
980     if (imf_bcc == NULL)
981       goto free;
982     field = mailimf_field_new(MAILIMF_FIELD_BCC,
983         NULL /* return-path */,
984         NULL /* resent date */,
985         NULL /* resent from */,
986         NULL /* resent sender */,
987         NULL /* resent to */,
988         NULL /* resent cc */,
989         NULL /* resent bcc */,
990         NULL /* resent msg id */,
991         NULL /* date */,
992         NULL /* from */,
993         NULL /* sender */,
994         NULL /* reply-to */,
995         NULL /* to */,
996         NULL /* cc */,
997         imf_bcc /* bcc */,
998         NULL /* message id */,
999         NULL /* in reply to */,
1000         NULL /* references */,
1001         NULL /* subject */,
1002         NULL /* comments */,
1003         NULL /* keywords */,
1004         NULL /* optional field */);
1005     if (field == NULL)
1006       goto free;
1007     r =  mailimf_fields_add(fields, field);
1008     if (r != MAILIMF_NO_ERROR)
1009       goto free_field;
1010   }
1011
1012   if (msg_id != NULL) {
1013     imf_msg_id = mailimf_message_id_new(msg_id);
1014     if (imf_msg_id == NULL)
1015       goto free;
1016     field = mailimf_field_new(MAILIMF_FIELD_MESSAGE_ID,
1017         NULL /* return-path */,
1018         NULL /* resent date */,
1019         NULL /* resent from */,
1020         NULL /* resent sender */,
1021         NULL /* resent to */,
1022         NULL /* resent cc */,
1023         NULL /* resent bcc */,
1024         NULL /* resent msg id */,
1025         NULL /* date */,
1026         NULL /* from */,
1027         NULL /* sender */,
1028         NULL /* reply-to */,
1029         NULL /* to */,
1030         NULL /* cc */,
1031         NULL /* bcc */,
1032         imf_msg_id /* message id */,
1033         NULL /* in reply to */,
1034         NULL /* references */,
1035         NULL /* subject */,
1036         NULL /* comments */,
1037         NULL /* keywords */,
1038         NULL /* optional field */);
1039     if (field == NULL)
1040       goto free;
1041     r =  mailimf_fields_add(fields, field);
1042     if (r != MAILIMF_NO_ERROR)
1043       goto free_field;
1044   }
1045
1046   if (in_reply_to != NULL) {
1047     imf_in_reply_to = mailimf_in_reply_to_new(in_reply_to);
1048     if (imf_in_reply_to == NULL)
1049       goto free;
1050     field = mailimf_field_new(MAILIMF_FIELD_IN_REPLY_TO,
1051         NULL /* return-path */,
1052         NULL /* resent date */,
1053         NULL /* resent from */,
1054         NULL /* resent sender */,
1055         NULL /* resent to */,
1056         NULL /* resent cc */,
1057         NULL /* resent bcc */,
1058         NULL /* resent msg id */,
1059         NULL /* date */,
1060         NULL /* from */,
1061         NULL /* sender */,
1062         NULL /* reply-to */,
1063         NULL /* to */,
1064         NULL /* cc */,
1065         NULL /* bcc */,
1066         NULL /* message id */,
1067         imf_in_reply_to /* in reply to */,
1068         NULL /* references */,
1069         NULL /* subject */,
1070         NULL /* comments */,
1071         NULL /* keywords */,
1072         NULL /* optional field */);
1073     if (field == NULL)
1074       goto free;
1075     r =  mailimf_fields_add(fields, field);
1076     if (r != MAILIMF_NO_ERROR)
1077       goto free_field;
1078   }
1079
1080   if (references != NULL) {
1081     imf_references = mailimf_references_new(references);
1082     if (imf_references == NULL)
1083       goto free;
1084     field = mailimf_field_new(MAILIMF_FIELD_REFERENCES,
1085         NULL /* return-path */,
1086         NULL /* resent date */,
1087         NULL /* resent from */,
1088         NULL /* resent sender */,
1089         NULL /* resent to */,
1090         NULL /* resent cc */,
1091         NULL /* resent bcc */,
1092         NULL /* resent msg id */,
1093         NULL /* date */,
1094         NULL /* from */,
1095         NULL /* sender */,
1096         NULL /* reply-to */,
1097         NULL /* to */,
1098         NULL /* cc */,
1099         NULL /* bcc */,
1100         NULL /* message id */,
1101         NULL /* in reply to */,
1102         imf_references /* references */,
1103         NULL /* subject */,
1104         NULL /* comments */,
1105         NULL /* keywords */,
1106         NULL /* optional field */);
1107     if (field == NULL)
1108       goto free;
1109     r =  mailimf_fields_add(fields, field);
1110     if (r != MAILIMF_NO_ERROR)
1111       goto free_field;
1112   }
1113
1114   if (subject != NULL) {
1115     imf_subject = mailimf_subject_new(subject);
1116     if (imf_subject == NULL)
1117       goto free;
1118     field = mailimf_field_new(MAILIMF_FIELD_SUBJECT,
1119         NULL /* return-path */,
1120         NULL /* resent date */,
1121         NULL /* resent from */,
1122         NULL /* resent sender */,
1123         NULL /* resent to */,
1124         NULL /* resent cc */,
1125         NULL /* resent bcc */,
1126         NULL /* resent msg id */,
1127         NULL /* date */,
1128         NULL /* from */,
1129         NULL /* sender */,
1130         NULL /* reply-to */,
1131         NULL /* to */,
1132         NULL /* cc */,
1133         NULL /* bcc */,
1134         NULL /* message id */,
1135         NULL /* in reply to */,
1136         NULL /* references */,
1137         imf_subject /* subject */,
1138         NULL /* comments */,
1139         NULL /* keywords */,
1140         NULL /* optional field */);
1141     if (field == NULL)
1142       goto free;
1143     r =  mailimf_fields_add(fields, field);
1144     if (r != MAILIMF_NO_ERROR)
1145       goto free_field;
1146   }
1147
1148   return MAILIMF_NO_ERROR;
1149
1150  free_field:
1151   if (field != NULL) {
1152     detach_field(field);
1153   }
1154  free:
1155   detach_free_fields(imf_date,
1156                      imf_from,
1157                      imf_sender,
1158                      imf_reply_to,
1159                      imf_to,
1160                      imf_cc,
1161                      imf_bcc,
1162                      imf_msg_id,
1163                      imf_in_reply_to,
1164                      imf_references,
1165                      imf_subject);
1166
1167   return MAILIMF_ERROR_MEMORY;
1168 }
1169
1170 struct mailimf_fields *
1171 mailimf_fields_new_with_data_all(struct mailimf_date_time * date,
1172                                  struct mailimf_mailbox_list * from,
1173                                  struct mailimf_mailbox * sender,
1174                                  struct mailimf_address_list * reply_to,
1175                                  struct mailimf_address_list * to,
1176                                  struct mailimf_address_list * cc,
1177                                  struct mailimf_address_list * bcc,
1178                                  char * message_id,
1179                                  clist * in_reply_to,
1180                                  clist * references,
1181                                  char * subject)
1182 {
1183   struct mailimf_fields * fields;
1184   int r;
1185
1186   fields = mailimf_fields_new_empty();
1187   if (fields == NULL)
1188     goto err;
1189
1190   r = mailimf_fields_add_data(fields,
1191                               date,
1192                               from,
1193                               sender,
1194                               reply_to,
1195                               to,
1196                               cc,
1197                               bcc,
1198                               message_id,
1199                               in_reply_to,
1200                               references,
1201                               subject);
1202   if (r != MAILIMF_NO_ERROR)
1203     goto free;
1204
1205   return fields;
1206
1207  free:
1208   mailimf_fields_free(fields);
1209  err:
1210   return NULL;
1211 }
1212
1213 struct mailimf_fields *
1214 mailimf_fields_new_with_data(struct mailimf_mailbox_list * from,
1215                              struct mailimf_mailbox * sender,
1216                              struct mailimf_address_list * reply_to,
1217                              struct mailimf_address_list * to,
1218                              struct mailimf_address_list * cc,
1219                              struct mailimf_address_list * bcc,
1220                              clist * in_reply_to,
1221                              clist * references,
1222                              char * subject)
1223 {
1224   struct mailimf_date_time * date;
1225   char * msg_id;
1226   struct mailimf_fields * fields;
1227
1228   date = mailimf_get_current_date();
1229   if (date == NULL)
1230     goto err;
1231
1232   msg_id = mailimf_get_message_id();
1233   if (msg_id == NULL)
1234     goto free_date;
1235
1236   fields = mailimf_fields_new_with_data_all(date,
1237                                             from, sender, reply_to,
1238                                             to, cc, bcc,
1239                                             msg_id,
1240                                             in_reply_to, references,
1241                                             subject);
1242   if (fields == NULL)
1243     goto free_msg_id;
1244
1245   return fields;
1246
1247  free_msg_id:
1248   free(msg_id);
1249  free_date:
1250   mailimf_date_time_free(date);
1251  err:
1252   return NULL;
1253 }
1254
1255
1256
1257 #define MAX_MESSAGE_ID 512
1258
1259 char * mailimf_get_message_id(void)
1260 {
1261   char id[MAX_MESSAGE_ID];
1262   time_t now;
1263   char name[MAX_MESSAGE_ID];
1264   long value;
1265
1266   now = time(NULL);
1267   value = random();
1268
1269   gethostname(name, MAX_MESSAGE_ID);
1270   snprintf(id, MAX_MESSAGE_ID, "etPan.%lx.%lx.%x@%s",
1271            now, value, getpid(), name);
1272
1273   return strdup(id);
1274 }
1275
1276
1277
1278 static time_t mkgmtime(struct tm * tmp);
1279
1280
1281 struct mailimf_date_time * mailimf_get_current_date(void)
1282 {
1283   struct tm gmt;
1284   struct tm lt;
1285   int off;
1286   time_t now;
1287   struct mailimf_date_time * date_time;
1288
1289   now = time(NULL);
1290
1291   if (gmtime_r(&now, &gmt) == NULL)
1292     return NULL;
1293
1294   if (localtime_r(&now, &lt) == NULL)
1295     return NULL;
1296
1297   off = (mkgmtime(&lt) - mkgmtime(&gmt)) / (60 * 60) * 100;
1298
1299   date_time = mailimf_date_time_new(lt.tm_mday, lt.tm_mon + 1, lt.tm_year + 1900,
1300                                     lt.tm_hour, lt.tm_min, lt.tm_sec,
1301                                     off);
1302
1303   return date_time;
1304 }
1305
1306
1307
1308 /* mkgmtime.c - make time corresponding to a GMT timeval struct
1309  $Id$
1310  
1311  * Copyright (c) 1998-2000 Carnegie Mellon University.  All rights reserved.
1312  *
1313  * Redistribution and use in source and binary forms, with or without
1314  * modification, are permitted provided that the following conditions
1315  * are met:
1316  *
1317  * 1. Redistributions of source code must retain the above copyright
1318  *    notice, this list of conditions and the following disclaimer. 
1319  *
1320  * 2. Redistributions in binary form must reproduce the above copyright
1321  *    notice, this list of conditions and the following disclaimer in
1322  *    the documentation and/or other materials provided with the
1323  *    distribution.
1324  *
1325  * 3. The name "Carnegie Mellon University" must not be used to
1326  *    endorse or promote products derived from this software without
1327  *    prior written permission. For permission or any other legal
1328  *    details, please contact  
1329  *      Office of Technology Transfer
1330  *      Carnegie Mellon University
1331  *      5000 Forbes Avenue
1332  *      Pittsburgh, PA  15213-3890
1333  *      (412) 268-4387, fax: (412) 268-7395
1334  *      tech-transfer@andrew.cmu.edu
1335  *
1336  * 4. Redistributions of any form whatsoever must retain the following
1337  *    acknowledgment:
1338  *    "This product includes software developed by Computing Services
1339  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
1340  *
1341  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
1342  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1343  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
1344  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1345  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
1346  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
1347  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1348  *
1349  *
1350  */
1351 /*
1352  * Copyright (c) 1987, 1989, 1993
1353  *      The Regents of the University of California.  All rights reserved.
1354  *
1355  * This code is derived from software contributed to Berkeley by
1356  * Arthur David Olson of the National Cancer Institute.
1357  *
1358  * Redistribution and use in source and binary forms, with or without
1359  * modification, are permitted provided that the following conditions
1360  * are met:
1361  * 1. Redistributions of source code must retain the above copyright
1362  *    notice, this list of conditions and the following disclaimer.
1363  * 2. Redistributions in binary form must reproduce the above copyright
1364  *    notice, this list of conditions and the following disclaimer in the
1365  *    documentation and/or other materials provided with the distribution.
1366  * 3. All advertising materials mentioning features or use of this software
1367  *    must display the following acknowledgement:
1368  *      This product includes software developed by the University of
1369  *      California, Berkeley and its contributors.
1370  * 4. Neither the name of the University nor the names of its contributors
1371  *    may be used to endorse or promote products derived from this software
1372  *    without specific prior written permission.
1373  *
1374  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1375  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1376  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1377  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1378  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1379  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1380  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1381  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1382  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1383  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1384  * SUCH DAMAGE.
1385  */
1386
1387 /*
1388 ** Adapted from code provided by Robert Elz, who writes:
1389 **      The "best" way to do mktime I think is based on an idea of Bob
1390 **      Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1391 **      It does a binary search of the time_t space.  Since time_t's are
1392 **      just 32 bits, its a max of 32 iterations (even at 64 bits it
1393 **      would still be very reasonable).
1394 */
1395
1396 /*
1397   adapted for libEtPan! by DINH V. Hoa
1398 */
1399
1400 #ifndef WRONG
1401 #define WRONG   (-1)
1402 #endif /* !defined WRONG */
1403
1404 static int tmcomp(struct tm * atmp, struct tm * btmp)
1405 {
1406   register int  result;
1407   
1408   if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1409       (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1410       (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1411       (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1412       (result = (atmp->tm_min - btmp->tm_min)) == 0)
1413     result = atmp->tm_sec - btmp->tm_sec;
1414   return result;
1415 }
1416
1417 static time_t mkgmtime(struct tm * tmp)
1418 {
1419   register int                  dir;
1420   register int                  bits;
1421   register int                  saved_seconds;
1422   time_t                                t;
1423   struct tm                     yourtm, *mytm, buft;
1424   
1425   yourtm = *tmp;
1426   saved_seconds = yourtm.tm_sec;
1427   yourtm.tm_sec = 0;
1428   /*
1429   ** Calculate the number of magnitude bits in a time_t
1430   ** (this works regardless of whether time_t is
1431   ** signed or unsigned, though lint complains if unsigned).
1432   */
1433   for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
1434     ;
1435   /*
1436   ** If time_t is signed, then 0 is the median value,
1437   ** if time_t is unsigned, then 1 << bits is median.
1438   */
1439   t = (t < 0) ? 0 : ((time_t) 1 << bits);
1440   for ( ; ; ) {
1441     mytm = gmtime_r(&t, &buft);
1442     dir = tmcomp(mytm, &yourtm);
1443     if (dir != 0) {
1444       if (bits-- < 0)
1445         return WRONG;
1446       if (bits < 0)
1447         --t;
1448       else if (dir > 0)
1449         t -= (time_t) 1 << bits;
1450       else      t += (time_t) 1 << bits;
1451       continue;
1452     }
1453     break;
1454   }
1455   t += saved_seconds;
1456   return t;
1457 }
1458
1459
1460
1461
1462
1463
1464
1465 void mailimf_single_fields_init(struct mailimf_single_fields * single_fields,
1466                                 struct mailimf_fields * fields)
1467 {
1468   clistiter * cur;
1469
1470   memset(single_fields, 0, sizeof(struct mailimf_single_fields));
1471
1472   cur = clist_begin(fields->fld_list);
1473   while (cur != NULL) {
1474     struct mailimf_field * field;
1475
1476     field = clist_content(cur);
1477
1478     switch (field->fld_type) {
1479     case MAILIMF_FIELD_ORIG_DATE:
1480       if (single_fields->fld_orig_date == NULL)
1481         single_fields->fld_orig_date = field->fld_data.fld_orig_date;
1482       cur = clist_next(cur);
1483       break;
1484     case MAILIMF_FIELD_FROM:
1485       if (single_fields->fld_from == NULL) {
1486         single_fields->fld_from = field->fld_data.fld_from;
1487         cur = clist_next(cur);
1488       }
1489       else {
1490         clist_concat(single_fields->fld_from->frm_mb_list->mb_list,
1491                      field->fld_data.fld_from->frm_mb_list->mb_list);
1492         mailimf_field_free(field);
1493         cur = clist_delete(fields->fld_list, cur);
1494       }
1495       break;
1496     case MAILIMF_FIELD_SENDER:
1497       if (single_fields->fld_sender == NULL)
1498         single_fields->fld_sender = field->fld_data.fld_sender;
1499       cur = clist_next(cur);
1500       break;
1501     case MAILIMF_FIELD_REPLY_TO:
1502       if (single_fields->fld_reply_to == NULL) {
1503         single_fields->fld_reply_to = field->fld_data.fld_reply_to;
1504         cur = clist_next(cur);
1505       }
1506       else {
1507         clist_concat(single_fields->fld_reply_to->rt_addr_list->ad_list,
1508                      field->fld_data.fld_reply_to->rt_addr_list->ad_list);
1509         mailimf_field_free(field);
1510         cur = clist_delete(fields->fld_list, cur);
1511       }
1512       break;
1513     case MAILIMF_FIELD_TO:
1514       if (single_fields->fld_to == NULL) {
1515         single_fields->fld_to = field->fld_data.fld_to;
1516         cur = clist_next(cur);
1517       }
1518       else {
1519         clist_concat(single_fields->fld_to->to_addr_list->ad_list,
1520                      field->fld_data.fld_to->to_addr_list->ad_list);
1521         mailimf_field_free(field);
1522         cur = clist_delete(fields->fld_list, cur);
1523       }
1524       break;
1525     case MAILIMF_FIELD_CC:
1526       if (single_fields->fld_cc == NULL) {
1527         single_fields->fld_cc = field->fld_data.fld_cc;
1528         cur = clist_next(cur);
1529       }
1530       else {
1531         clist_concat(single_fields->fld_cc->cc_addr_list->ad_list, 
1532                      field->fld_data.fld_cc->cc_addr_list->ad_list);
1533         mailimf_field_free(field);
1534         cur = clist_delete(fields->fld_list, cur);
1535       }
1536       break;
1537     case MAILIMF_FIELD_BCC:
1538       if (single_fields->fld_bcc == NULL) {
1539         single_fields->fld_bcc = field->fld_data.fld_bcc;
1540         cur = clist_next(cur);
1541       }
1542       else {
1543         clist_concat(single_fields->fld_bcc->bcc_addr_list->ad_list,
1544                      field->fld_data.fld_bcc->bcc_addr_list->ad_list);
1545         mailimf_field_free(field);
1546         cur = clist_delete(fields->fld_list, cur);
1547       }
1548       break;
1549     case MAILIMF_FIELD_MESSAGE_ID:
1550       if (single_fields->fld_message_id == NULL)
1551         single_fields->fld_message_id = field->fld_data.fld_message_id;
1552       cur = clist_next(cur);
1553       break;
1554     case MAILIMF_FIELD_IN_REPLY_TO:
1555       if (single_fields->fld_in_reply_to == NULL)
1556         single_fields->fld_in_reply_to = field->fld_data.fld_in_reply_to;
1557       cur = clist_next(cur);
1558       break;
1559     case MAILIMF_FIELD_REFERENCES:
1560       if (single_fields->fld_references == NULL)
1561         single_fields->fld_references = field->fld_data.fld_references;
1562       cur = clist_next(cur);
1563       break;
1564     case MAILIMF_FIELD_SUBJECT:
1565       if (single_fields->fld_subject == NULL)
1566         single_fields->fld_subject = field->fld_data.fld_subject;
1567       cur = clist_next(cur);
1568       break;
1569     case MAILIMF_FIELD_COMMENTS:
1570       if (single_fields->fld_comments == NULL)
1571         single_fields->fld_comments = field->fld_data.fld_comments;
1572       cur = clist_next(cur);
1573       break;
1574     case MAILIMF_FIELD_KEYWORDS:
1575       if (single_fields->fld_keywords == NULL)
1576         single_fields->fld_keywords = field->fld_data.fld_keywords;
1577       cur = clist_next(cur);
1578       break;
1579     default:
1580       cur = clist_next(cur);
1581       break;
1582     }
1583   }
1584 }
1585
1586
1587 struct mailimf_single_fields *
1588 mailimf_single_fields_new(struct mailimf_fields * fields)
1589 {
1590   struct mailimf_single_fields * single_fields;
1591
1592   single_fields = malloc(sizeof(struct mailimf_single_fields));
1593   if (single_fields == NULL)
1594     goto err;
1595
1596   mailimf_single_fields_init(single_fields, fields);
1597
1598   return single_fields;
1599
1600  err:
1601   return NULL;
1602 }
1603
1604 void mailimf_single_fields_free(struct mailimf_single_fields *
1605                                 single_fields)
1606 {
1607   free(single_fields);
1608 }
1609
1610 struct mailimf_field * mailimf_field_new_custom(char * name, char * value)
1611 {
1612   struct mailimf_optional_field * opt_field;
1613   struct mailimf_field * field;
1614
1615   opt_field = mailimf_optional_field_new(name, value);
1616   if (opt_field == NULL)
1617     goto err;
1618
1619   field = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD,
1620       NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1621       NULL, NULL, NULL, NULL,
1622       NULL, NULL, NULL, NULL,
1623       NULL, NULL, NULL, NULL,
1624       NULL, NULL, opt_field);
1625   if (field == NULL)
1626     goto free_opt_field;
1627
1628   return field;
1629   
1630  free_opt_field:
1631   mailimf_optional_field_free(opt_field);
1632  err:
1633   return NULL;
1634 }