66dce6bd80fb0880c8275bb247883db00d468ba5
[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     mailimf_field_free(field);
1154   }
1155  free:
1156   detach_free_fields(imf_date,
1157                      imf_from,
1158                      imf_sender,
1159                      imf_reply_to,
1160                      imf_to,
1161                      imf_cc,
1162                      imf_bcc,
1163                      imf_msg_id,
1164                      imf_in_reply_to,
1165                      imf_references,
1166                      imf_subject);
1167
1168   return MAILIMF_ERROR_MEMORY;
1169 }
1170
1171 struct mailimf_fields *
1172 mailimf_fields_new_with_data_all(struct mailimf_date_time * date,
1173                                  struct mailimf_mailbox_list * from,
1174                                  struct mailimf_mailbox * sender,
1175                                  struct mailimf_address_list * reply_to,
1176                                  struct mailimf_address_list * to,
1177                                  struct mailimf_address_list * cc,
1178                                  struct mailimf_address_list * bcc,
1179                                  char * message_id,
1180                                  clist * in_reply_to,
1181                                  clist * references,
1182                                  char * subject)
1183 {
1184   struct mailimf_fields * fields;
1185   int r;
1186
1187   fields = mailimf_fields_new_empty();
1188   if (fields == NULL)
1189     goto err;
1190
1191   r = mailimf_fields_add_data(fields,
1192                               date,
1193                               from,
1194                               sender,
1195                               reply_to,
1196                               to,
1197                               cc,
1198                               bcc,
1199                               message_id,
1200                               in_reply_to,
1201                               references,
1202                               subject);
1203   if (r != MAILIMF_NO_ERROR)
1204     goto free;
1205
1206   return fields;
1207
1208  free:
1209   mailimf_fields_free(fields);
1210  err:
1211   return NULL;
1212 }
1213
1214 struct mailimf_fields *
1215 mailimf_fields_new_with_data(struct mailimf_mailbox_list * from,
1216                              struct mailimf_mailbox * sender,
1217                              struct mailimf_address_list * reply_to,
1218                              struct mailimf_address_list * to,
1219                              struct mailimf_address_list * cc,
1220                              struct mailimf_address_list * bcc,
1221                              clist * in_reply_to,
1222                              clist * references,
1223                              char * subject)
1224 {
1225   struct mailimf_date_time * date;
1226   char * msg_id;
1227   struct mailimf_fields * fields;
1228
1229   date = mailimf_get_current_date();
1230   if (date == NULL)
1231     goto err;
1232
1233   msg_id = mailimf_get_message_id();
1234   if (msg_id == NULL)
1235     goto free_date;
1236
1237   fields = mailimf_fields_new_with_data_all(date,
1238                                             from, sender, reply_to,
1239                                             to, cc, bcc,
1240                                             msg_id,
1241                                             in_reply_to, references,
1242                                             subject);
1243   if (fields == NULL)
1244     goto free_msg_id;
1245
1246   return fields;
1247
1248  free_msg_id:
1249   free(msg_id);
1250  free_date:
1251   mailimf_date_time_free(date);
1252  err:
1253   return NULL;
1254 }
1255
1256
1257
1258 #define MAX_MESSAGE_ID 512
1259
1260 char * mailimf_get_message_id(void)
1261 {
1262   char id[MAX_MESSAGE_ID];
1263   time_t now;
1264   char name[MAX_MESSAGE_ID];
1265   long value;
1266
1267   now = time(NULL);
1268   value = random();
1269
1270   gethostname(name, MAX_MESSAGE_ID);
1271   snprintf(id, MAX_MESSAGE_ID, "etPan.%lx.%lx.%x@%s",
1272            now, value, getpid(), name);
1273
1274   return strdup(id);
1275 }
1276
1277
1278
1279 static time_t mkgmtime(struct tm * tmp);
1280
1281
1282 struct mailimf_date_time * mailimf_get_current_date(void)
1283 {
1284   struct tm gmt;
1285   struct tm lt;
1286   int off;
1287   time_t now;
1288   struct mailimf_date_time * date_time;
1289
1290   now = time(NULL);
1291
1292   if (gmtime_r(&now, &gmt) == NULL)
1293     return NULL;
1294
1295   if (localtime_r(&now, &lt) == NULL)
1296     return NULL;
1297
1298   off = (mkgmtime(&lt) - mkgmtime(&gmt)) / (60 * 60) * 100;
1299
1300   date_time = mailimf_date_time_new(lt.tm_mday, lt.tm_mon + 1, lt.tm_year + 1900,
1301                                     lt.tm_hour, lt.tm_min, lt.tm_sec,
1302                                     off);
1303
1304   return date_time;
1305 }
1306
1307
1308
1309 /* mkgmtime.c - make time corresponding to a GMT timeval struct
1310  $Id$
1311  
1312  * Copyright (c) 1998-2000 Carnegie Mellon University.  All rights reserved.
1313  *
1314  * Redistribution and use in source and binary forms, with or without
1315  * modification, are permitted provided that the following conditions
1316  * are met:
1317  *
1318  * 1. Redistributions of source code must retain the above copyright
1319  *    notice, this list of conditions and the following disclaimer. 
1320  *
1321  * 2. Redistributions in binary form must reproduce the above copyright
1322  *    notice, this list of conditions and the following disclaimer in
1323  *    the documentation and/or other materials provided with the
1324  *    distribution.
1325  *
1326  * 3. The name "Carnegie Mellon University" must not be used to
1327  *    endorse or promote products derived from this software without
1328  *    prior written permission. For permission or any other legal
1329  *    details, please contact  
1330  *      Office of Technology Transfer
1331  *      Carnegie Mellon University
1332  *      5000 Forbes Avenue
1333  *      Pittsburgh, PA  15213-3890
1334  *      (412) 268-4387, fax: (412) 268-7395
1335  *      tech-transfer@andrew.cmu.edu
1336  *
1337  * 4. Redistributions of any form whatsoever must retain the following
1338  *    acknowledgment:
1339  *    "This product includes software developed by Computing Services
1340  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
1341  *
1342  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
1343  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1344  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
1345  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1346  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
1347  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
1348  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1349  *
1350  *
1351  */
1352 /*
1353  * Copyright (c) 1987, 1989, 1993
1354  *      The Regents of the University of California.  All rights reserved.
1355  *
1356  * This code is derived from software contributed to Berkeley by
1357  * Arthur David Olson of the National Cancer Institute.
1358  *
1359  * Redistribution and use in source and binary forms, with or without
1360  * modification, are permitted provided that the following conditions
1361  * are met:
1362  * 1. Redistributions of source code must retain the above copyright
1363  *    notice, this list of conditions and the following disclaimer.
1364  * 2. Redistributions in binary form must reproduce the above copyright
1365  *    notice, this list of conditions and the following disclaimer in the
1366  *    documentation and/or other materials provided with the distribution.
1367  * 3. All advertising materials mentioning features or use of this software
1368  *    must display the following acknowledgement:
1369  *      This product includes software developed by the University of
1370  *      California, Berkeley and its contributors.
1371  * 4. Neither the name of the University nor the names of its contributors
1372  *    may be used to endorse or promote products derived from this software
1373  *    without specific prior written permission.
1374  *
1375  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1376  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1377  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1378  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1379  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1380  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1381  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1382  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1383  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1384  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1385  * SUCH DAMAGE.
1386  */
1387
1388 /*
1389 ** Adapted from code provided by Robert Elz, who writes:
1390 **      The "best" way to do mktime I think is based on an idea of Bob
1391 **      Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1392 **      It does a binary search of the time_t space.  Since time_t's are
1393 **      just 32 bits, its a max of 32 iterations (even at 64 bits it
1394 **      would still be very reasonable).
1395 */
1396
1397 /*
1398   adapted for libEtPan! by DINH V. Hoa
1399 */
1400
1401 #ifndef WRONG
1402 #define WRONG   (-1)
1403 #endif /* !defined WRONG */
1404
1405 static int tmcomp(struct tm * atmp, struct tm * btmp)
1406 {
1407   register int  result;
1408   
1409   if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1410       (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1411       (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1412       (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1413       (result = (atmp->tm_min - btmp->tm_min)) == 0)
1414     result = atmp->tm_sec - btmp->tm_sec;
1415   return result;
1416 }
1417
1418 static time_t mkgmtime(struct tm * tmp)
1419 {
1420   register int                  dir;
1421   register int                  bits;
1422   register int                  saved_seconds;
1423   time_t                                t;
1424   struct tm                     yourtm, *mytm, buft;
1425   
1426   yourtm = *tmp;
1427   saved_seconds = yourtm.tm_sec;
1428   yourtm.tm_sec = 0;
1429   /*
1430   ** Calculate the number of magnitude bits in a time_t
1431   ** (this works regardless of whether time_t is
1432   ** signed or unsigned, though lint complains if unsigned).
1433   */
1434   for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
1435     ;
1436   /*
1437   ** If time_t is signed, then 0 is the median value,
1438   ** if time_t is unsigned, then 1 << bits is median.
1439   */
1440   t = (t < 0) ? 0 : ((time_t) 1 << bits);
1441   for ( ; ; ) {
1442     mytm = gmtime_r(&t, &buft);
1443     dir = tmcomp(mytm, &yourtm);
1444     if (dir != 0) {
1445       if (bits-- < 0)
1446         return WRONG;
1447       if (bits < 0)
1448         --t;
1449       else if (dir > 0)
1450         t -= (time_t) 1 << bits;
1451       else      t += (time_t) 1 << bits;
1452       continue;
1453     }
1454     break;
1455   }
1456   t += saved_seconds;
1457   return t;
1458 }
1459
1460
1461
1462
1463
1464
1465
1466 void mailimf_single_fields_init(struct mailimf_single_fields * single_fields,
1467                                 struct mailimf_fields * fields)
1468 {
1469   clistiter * cur;
1470
1471   memset(single_fields, 0, sizeof(struct mailimf_single_fields));
1472
1473   cur = clist_begin(fields->fld_list);
1474   while (cur != NULL) {
1475     struct mailimf_field * field;
1476
1477     field = clist_content(cur);
1478
1479     switch (field->fld_type) {
1480     case MAILIMF_FIELD_ORIG_DATE:
1481       if (single_fields->fld_orig_date == NULL)
1482         single_fields->fld_orig_date = field->fld_data.fld_orig_date;
1483       cur = clist_next(cur);
1484       break;
1485     case MAILIMF_FIELD_FROM:
1486       if (single_fields->fld_from == NULL) {
1487         single_fields->fld_from = field->fld_data.fld_from;
1488         cur = clist_next(cur);
1489       }
1490       else {
1491         clist_concat(single_fields->fld_from->frm_mb_list->mb_list,
1492                      field->fld_data.fld_from->frm_mb_list->mb_list);
1493         mailimf_field_free(field);
1494         cur = clist_delete(fields->fld_list, cur);
1495       }
1496       break;
1497     case MAILIMF_FIELD_SENDER:
1498       if (single_fields->fld_sender == NULL)
1499         single_fields->fld_sender = field->fld_data.fld_sender;
1500       cur = clist_next(cur);
1501       break;
1502     case MAILIMF_FIELD_REPLY_TO:
1503       if (single_fields->fld_reply_to == NULL) {
1504         single_fields->fld_reply_to = field->fld_data.fld_reply_to;
1505         cur = clist_next(cur);
1506       }
1507       else {
1508         clist_concat(single_fields->fld_reply_to->rt_addr_list->ad_list,
1509                      field->fld_data.fld_reply_to->rt_addr_list->ad_list);
1510         mailimf_field_free(field);
1511         cur = clist_delete(fields->fld_list, cur);
1512       }
1513       break;
1514     case MAILIMF_FIELD_TO:
1515       if (single_fields->fld_to == NULL) {
1516         single_fields->fld_to = field->fld_data.fld_to;
1517         cur = clist_next(cur);
1518       }
1519       else {
1520         clist_concat(single_fields->fld_to->to_addr_list->ad_list,
1521                      field->fld_data.fld_to->to_addr_list->ad_list);
1522         mailimf_field_free(field);
1523         cur = clist_delete(fields->fld_list, cur);
1524       }
1525       break;
1526     case MAILIMF_FIELD_CC:
1527       if (single_fields->fld_cc == NULL) {
1528         single_fields->fld_cc = field->fld_data.fld_cc;
1529         cur = clist_next(cur);
1530       }
1531       else {
1532         clist_concat(single_fields->fld_cc->cc_addr_list->ad_list, 
1533                      field->fld_data.fld_cc->cc_addr_list->ad_list);
1534         mailimf_field_free(field);
1535         cur = clist_delete(fields->fld_list, cur);
1536       }
1537       break;
1538     case MAILIMF_FIELD_BCC:
1539       if (single_fields->fld_bcc == NULL) {
1540         single_fields->fld_bcc = field->fld_data.fld_bcc;
1541         cur = clist_next(cur);
1542       }
1543       else {
1544         clist_concat(single_fields->fld_bcc->bcc_addr_list->ad_list,
1545                      field->fld_data.fld_bcc->bcc_addr_list->ad_list);
1546         mailimf_field_free(field);
1547         cur = clist_delete(fields->fld_list, cur);
1548       }
1549       break;
1550     case MAILIMF_FIELD_MESSAGE_ID:
1551       if (single_fields->fld_message_id == NULL)
1552         single_fields->fld_message_id = field->fld_data.fld_message_id;
1553       cur = clist_next(cur);
1554       break;
1555     case MAILIMF_FIELD_IN_REPLY_TO:
1556       if (single_fields->fld_in_reply_to == NULL)
1557         single_fields->fld_in_reply_to = field->fld_data.fld_in_reply_to;
1558       cur = clist_next(cur);
1559       break;
1560     case MAILIMF_FIELD_REFERENCES:
1561       if (single_fields->fld_references == NULL)
1562         single_fields->fld_references = field->fld_data.fld_references;
1563       cur = clist_next(cur);
1564       break;
1565     case MAILIMF_FIELD_SUBJECT:
1566       if (single_fields->fld_subject == NULL)
1567         single_fields->fld_subject = field->fld_data.fld_subject;
1568       cur = clist_next(cur);
1569       break;
1570     case MAILIMF_FIELD_COMMENTS:
1571       if (single_fields->fld_comments == NULL)
1572         single_fields->fld_comments = field->fld_data.fld_comments;
1573       cur = clist_next(cur);
1574       break;
1575     case MAILIMF_FIELD_KEYWORDS:
1576       if (single_fields->fld_keywords == NULL)
1577         single_fields->fld_keywords = field->fld_data.fld_keywords;
1578       cur = clist_next(cur);
1579       break;
1580     default:
1581       cur = clist_next(cur);
1582       break;
1583     }
1584   }
1585 }
1586
1587
1588 struct mailimf_single_fields *
1589 mailimf_single_fields_new(struct mailimf_fields * fields)
1590 {
1591   struct mailimf_single_fields * single_fields;
1592
1593   single_fields = malloc(sizeof(struct mailimf_single_fields));
1594   if (single_fields == NULL)
1595     goto err;
1596
1597   mailimf_single_fields_init(single_fields, fields);
1598
1599   return single_fields;
1600
1601  err:
1602   return NULL;
1603 }
1604
1605 void mailimf_single_fields_free(struct mailimf_single_fields *
1606                                 single_fields)
1607 {
1608   free(single_fields);
1609 }
1610
1611 struct mailimf_field * mailimf_field_new_custom(char * name, char * value)
1612 {
1613   struct mailimf_optional_field * opt_field;
1614   struct mailimf_field * field;
1615
1616   opt_field = mailimf_optional_field_new(name, value);
1617   if (opt_field == NULL)
1618     goto err;
1619
1620   field = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD,
1621       NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1622       NULL, NULL, NULL, NULL,
1623       NULL, NULL, NULL, NULL,
1624       NULL, NULL, NULL, NULL,
1625       NULL, NULL, opt_field);
1626   if (field == NULL)
1627     goto free_opt_field;
1628
1629   return field;
1630   
1631  free_opt_field:
1632   mailimf_optional_field_free(opt_field);
1633  err:
1634   return NULL;
1635 }