summaryrefslogtreecommitdiffabout
path: root/libetpan/src/low-level/mime/mailmime_write.c
Unidiff
Diffstat (limited to 'libetpan/src/low-level/mime/mailmime_write.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/low-level/mime/mailmime_write.c1416
1 files changed, 1416 insertions, 0 deletions
diff --git a/libetpan/src/low-level/mime/mailmime_write.c b/libetpan/src/low-level/mime/mailmime_write.c
new file mode 100644
index 0000000..4bce0d5
--- a/dev/null
+++ b/libetpan/src/low-level/mime/mailmime_write.c
@@ -0,0 +1,1416 @@
1/*
2 * libEtPan! -- a mail stuff library
3 *
4 * Copyright (C) 2001, 2005 - 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 AUTHORS 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 AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#include "mailmime_write.h"
37
38#include <stdlib.h>
39#include <string.h>
40#include <time.h>
41#include <unistd.h>
42#include <sys/types.h>
43#include <sys/stat.h>
44#include <fcntl.h>
45#include <sys/mman.h>
46
47#include "mailimf_write.h"
48#include "mailmime_content.h"
49#include "mailmime_types_helper.h"
50
51#define MAX_MAIL_COL 78
52
53#ifndef TRUE
54#define TRUE 1
55#endif
56
57#ifndef FALSE
58#define FALSE 0
59#endif
60
61static int mailmime_field_write(FILE * f, int * col,
62 struct mailmime_field * field);
63
64static int mailmime_id_write(FILE * f, int * col, char * id);
65
66static int mailmime_description_write(FILE * f, int * col, char * descr);
67
68static int mailmime_version_write(FILE * f, int * col, uint32_t version);
69
70static int mailmime_encoding_write(FILE * f, int * col,
71 struct mailmime_mechanism * encoding);
72
73static int mailmime_language_write(FILE * f, int * col,
74 struct mailmime_language * language);
75
76static int mailmime_disposition_write(FILE * f, int * col,
77 struct mailmime_disposition *
78 disposition);
79
80static int
81mailmime_disposition_param_write(FILE * f, int * col,
82 struct mailmime_disposition_parm * param);
83
84static int mailmime_parameter_write(FILE * f, int * col,
85 struct mailmime_parameter * param);
86
87/*
88static int mailmime_content_write(FILE * f, int * col,
89 struct mailmime_content * content);
90*/
91
92static int mailmime_type_write(FILE * f, int * col,
93 struct mailmime_type * type);
94
95static int
96mailmime_discrete_type_write(FILE * f, int * col,
97 struct mailmime_discrete_type * discrete_type);
98
99static int
100mailmime_composite_type_write(FILE * f, int * col,
101 struct mailmime_composite_type * composite_type);
102
103static int mailmime_sub_write(FILE * f, int * col,
104 struct mailmime * build_info);
105
106
107/* ***** */
108
109int mailmime_fields_write(FILE * f, int * col, struct mailmime_fields * fields)
110{
111 int r;
112 clistiter * cur;
113
114 for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
115 cur = clist_next(cur)) {
116 struct mailmime_field * field;
117
118 field = cur->data;
119 r = mailmime_field_write(f, col, field);
120 if (r != MAILIMF_NO_ERROR)
121 return r;
122 }
123
124 return MAILIMF_NO_ERROR;
125}
126
127static int mailmime_field_write(FILE * f, int * col,
128 struct mailmime_field * field)
129{
130 int r;
131
132 switch (field->fld_type) {
133 case MAILMIME_FIELD_TYPE:
134 r = mailmime_content_write(f, col, field->fld_data.fld_content);
135 break;
136
137 case MAILMIME_FIELD_TRANSFER_ENCODING:
138 r = mailmime_encoding_write(f, col, field->fld_data.fld_encoding);
139 break;
140
141 case MAILMIME_FIELD_ID:
142 r = mailmime_id_write(f, col, field->fld_data.fld_id);
143 break;
144
145 case MAILMIME_FIELD_DESCRIPTION:
146 r = mailmime_description_write(f, col, field->fld_data.fld_description);
147 break;
148
149 case MAILMIME_FIELD_VERSION:
150 r = mailmime_version_write(f, col, field->fld_data.fld_version);
151 break;
152
153 case MAILMIME_FIELD_DISPOSITION:
154 r = mailmime_disposition_write(f, col, field->fld_data.fld_disposition);
155 break;
156
157 case MAILMIME_FIELD_LANGUAGE:
158 r = mailmime_language_write(f, col, field->fld_data.fld_language);
159 break;
160
161 default:
162 r = MAILIMF_ERROR_INVAL;
163 break;
164 }
165
166 if (r != MAILIMF_NO_ERROR)
167 return r;
168
169 return MAILIMF_NO_ERROR;
170}
171
172static int mailmime_id_write(FILE * f, int * col, char * id)
173{
174 int r;
175
176 r = mailimf_string_write(f, col, "Content-ID: ", 12);
177 if (r != MAILIMF_NO_ERROR)
178 return r;
179
180 r = mailimf_string_write(f, col, "<", 1);
181 if (r != MAILIMF_NO_ERROR)
182 return r;
183
184 r = mailimf_string_write(f, col, id, strlen(id));
185 if (r != MAILIMF_NO_ERROR)
186 return r;
187
188 r = mailimf_string_write(f, col, ">", 1);
189 if (r != MAILIMF_NO_ERROR)
190 return r;
191
192 r = mailimf_string_write(f, col, "\r\n", 2);
193 if (r != MAILIMF_NO_ERROR)
194 return r;
195#if 0
196 * col = 0;
197#endif
198
199 return MAILIMF_NO_ERROR;
200}
201
202static int mailmime_description_write(FILE * f, int * col, char * descr)
203{
204 int r;
205
206 r = mailimf_string_write(f, col, "Content-Description: ", 21);
207 if (r != MAILIMF_NO_ERROR)
208 return r;
209
210 r = mailimf_string_write(f, col, descr, strlen(descr));
211 if (r != MAILIMF_NO_ERROR)
212 return r;
213
214 r = mailimf_string_write(f, col, "\r\n", 2);
215 if (r != MAILIMF_NO_ERROR)
216 return r;
217#if 0
218 * col = 0;
219#endif
220
221 return MAILIMF_NO_ERROR;
222}
223
224static int mailmime_version_write(FILE * f, int * col, uint32_t version)
225{
226 int r;
227 char versionstr[40];
228
229 r = mailimf_string_write(f, col, "MIME-Version: ", 14);
230 if (r != MAILIMF_NO_ERROR)
231 return r;
232
233 snprintf(versionstr, 40, "%i.%i", version >> 16, version & 0xFFFF);
234
235 r = mailimf_string_write(f, col, versionstr, strlen(versionstr));
236 if (r != MAILIMF_NO_ERROR)
237 return r;
238
239 r = mailimf_string_write(f, col, "\r\n", 2);
240 if (r != MAILIMF_NO_ERROR)
241 return r;
242#if 0
243 * col = 0;
244#endif
245
246 return MAILIMF_NO_ERROR;
247}
248
249static int mailmime_encoding_write(FILE * f, int * col,
250 struct mailmime_mechanism * encoding)
251{
252 int r;
253
254 r = mailimf_string_write(f, col, "Content-Transfer-Encoding: ", 27);
255 if (r != MAILIMF_NO_ERROR)
256 return r;
257
258 switch (encoding->enc_type) {
259 case MAILMIME_MECHANISM_7BIT:
260 r = mailimf_string_write(f, col, "7bit", 4);
261 break;
262
263 case MAILMIME_MECHANISM_8BIT:
264 r = mailimf_string_write(f, col, "8bit", 4);
265 break;
266
267 case MAILMIME_MECHANISM_BINARY:
268 r = mailimf_string_write(f, col, "binary", 6);
269 break;
270
271 case MAILMIME_MECHANISM_QUOTED_PRINTABLE:
272 r = mailimf_string_write(f, col, "quoted-printable", 16);
273 break;
274
275 case MAILMIME_MECHANISM_BASE64:
276 r = mailimf_string_write(f, col, "base64", 6);
277 break;
278
279 case MAILMIME_MECHANISM_TOKEN:
280 r = mailimf_string_write(f, col, encoding->enc_token,
281 strlen(encoding->enc_token));
282 break;
283
284 default:
285 r = MAILIMF_ERROR_INVAL;
286 break;
287 }
288
289 if (r != MAILIMF_NO_ERROR)
290 return r;
291
292 r = mailimf_string_write(f, col, "\r\n", 2);
293 if (r != MAILIMF_NO_ERROR)
294 return r;
295#if 0
296 * col = 0;
297#endif
298
299 return MAILIMF_NO_ERROR;
300}
301
302static int mailmime_language_write(FILE * f, int * col,
303 struct mailmime_language * language)
304{
305 int r;
306 clistiter * cur;
307 int first;
308
309 r = mailimf_string_write(f, col, "Content-Language: ", 18);
310 if (r != MAILIMF_NO_ERROR)
311 return r;
312
313 first = TRUE;
314
315 for(cur = clist_begin(language->lg_list) ; cur != NULL ;
316 cur = clist_next(cur)) {
317 char * lang;
318 size_t len;
319
320 lang = clist_content(cur);
321 len = strlen(lang);
322
323 if (!first) {
324 r = mailimf_string_write(f, col, ", ", 2);
325 if (r != MAILIMF_NO_ERROR)
326 return r;
327 }
328 else {
329 first = FALSE;
330 }
331
332 if (* col > 1) {
333
334 if (* col + len > MAX_MAIL_COL) {
335 r = mailimf_string_write(f, col, "\r\n ", 3);
336 if (r != MAILIMF_NO_ERROR)
337 return r;
338#if 0
339 * col = 1;
340#endif
341 }
342 }
343
344 r = mailimf_string_write(f, col, lang, len);
345 if (r != MAILIMF_NO_ERROR)
346 return r;
347 }
348
349 r = mailimf_string_write(f, col, "\r\n", 2);
350 if (r != MAILIMF_NO_ERROR)
351 return r;
352#if 0
353 * col = 0;
354#endif
355
356 return MAILIMF_NO_ERROR;
357}
358
359static int mailmime_disposition_write(FILE * f, int * col,
360 struct mailmime_disposition *
361 disposition)
362{
363 struct mailmime_disposition_type * dsp_type;
364 int r;
365 clistiter * cur;
366
367 dsp_type = disposition->dsp_type;
368
369 r = mailimf_string_write(f, col, "Content-Disposition: ", 21);
370 if (r != MAILIMF_NO_ERROR)
371 return r;
372
373 switch (dsp_type->dsp_type) {
374 case MAILMIME_DISPOSITION_TYPE_INLINE:
375 r = mailimf_string_write(f, col, "inline", 6);
376 break;
377
378 case MAILMIME_DISPOSITION_TYPE_ATTACHMENT:
379 r = mailimf_string_write(f, col, "attachment", 10);
380 break;
381
382 case MAILMIME_DISPOSITION_TYPE_EXTENSION:
383 r = mailimf_string_write(f, col, dsp_type->dsp_extension,
384 strlen(dsp_type->dsp_extension));
385 break;
386
387 default:
388 r = MAILIMF_ERROR_INVAL;
389 break;
390 }
391
392 if (r != MAILIMF_NO_ERROR)
393 return r;
394
395 for(cur = clist_begin(disposition->dsp_parms) ;
396 cur != NULL ; cur = clist_next(cur)) {
397 struct mailmime_disposition_parm * param;
398
399 param = cur->data;
400
401 r = mailimf_string_write(f, col, "; ", 2);
402 if (r != MAILIMF_NO_ERROR)
403 return r;
404
405 r = mailmime_disposition_param_write(f, col, param);
406 if (r != MAILIMF_NO_ERROR)
407 return r;
408 }
409
410 r = mailimf_string_write(f, col, "\r\n", 2);
411 if (r != MAILIMF_NO_ERROR)
412 return r;
413
414 return MAILIMF_NO_ERROR;
415}
416
417static int
418mailmime_disposition_param_write(FILE * f, int * col,
419 struct mailmime_disposition_parm * param)
420{
421 size_t len;
422 char sizestr[20];
423 int r;
424
425 switch (param->pa_type) {
426 case MAILMIME_DISPOSITION_PARM_FILENAME:
427 len = strlen("filename=") + strlen(param->pa_data.pa_filename);
428 break;
429
430 case MAILMIME_DISPOSITION_PARM_CREATION_DATE:
431 len = strlen("creation-date=") + strlen(param->pa_data.pa_creation_date);
432 break;
433
434 case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE:
435 len = strlen("modification-date=") +
436 strlen(param->pa_data.pa_modification_date);
437 break;
438
439 case MAILMIME_DISPOSITION_PARM_READ_DATE:
440 len = strlen("read-date=") + strlen(param->pa_data.pa_read_date);
441 break;
442
443 case MAILMIME_DISPOSITION_PARM_SIZE:
444 snprintf(sizestr, 20, "%lu", (unsigned long) param->pa_data.pa_size);
445 len = strlen("size=") + strlen(sizestr);
446 break;
447
448 case MAILMIME_DISPOSITION_PARM_PARAMETER:
449 len = strlen(param->pa_data.pa_parameter->pa_name) + 1 +
450 strlen(param->pa_data.pa_parameter->pa_value);
451 break;
452
453 default:
454 return MAILIMF_ERROR_INVAL;
455 }
456
457 if (* col > 1) {
458
459 if (* col + len > MAX_MAIL_COL) {
460 r = mailimf_string_write(f, col, "\r\n ", 3);
461 if (r != MAILIMF_NO_ERROR)
462 return r;
463#if 0
464 * col = 1;
465#endif
466 }
467 }
468
469 switch (param->pa_type) {
470 case MAILMIME_DISPOSITION_PARM_FILENAME:
471 r = mailimf_string_write(f, col, "filename=", 9);
472 if (r != MAILIMF_NO_ERROR)
473 return r;
474
475 r = mailimf_quoted_string_write(f, col,
476 param->pa_data.pa_filename, strlen(param->pa_data.pa_filename));
477 if (r != MAILIMF_NO_ERROR)
478 return r;
479 break;
480
481 case MAILMIME_DISPOSITION_PARM_CREATION_DATE:
482 r = mailimf_string_write(f, col, "creation-date=", 14);
483 if (r != MAILIMF_NO_ERROR)
484 return r;
485
486 r = mailimf_quoted_string_write(f, col, param->pa_data.pa_creation_date,
487 strlen(param->pa_data.pa_creation_date));
488 if (r != MAILIMF_NO_ERROR)
489 return r;
490 break;
491
492 case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE:
493 r = mailimf_string_write(f, col, "modification-date=", 18);
494 if (r != MAILIMF_NO_ERROR)
495 return r;
496
497 r = mailimf_quoted_string_write(f, col,
498 param->pa_data.pa_modification_date,
499 strlen(param->pa_data.pa_modification_date));
500 if (r != MAILIMF_NO_ERROR)
501 return r;
502 break;
503
504 case MAILMIME_DISPOSITION_PARM_READ_DATE:
505 r = mailimf_string_write(f, col, "read-date=", 10);
506 if (r != MAILIMF_NO_ERROR)
507 return r;
508
509 r = mailimf_quoted_string_write(f, col, param->pa_data.pa_read_date,
510 strlen(param->pa_data.pa_read_date));
511 if (r != MAILIMF_NO_ERROR)
512 return r;
513 break;
514
515 case MAILMIME_DISPOSITION_PARM_SIZE:
516 r = mailimf_string_write(f, col, "size=", 5);
517 if (r != MAILIMF_NO_ERROR)
518 return r;
519
520 r = mailimf_string_write(f, col, sizestr, strlen(sizestr));
521 if (r != MAILIMF_NO_ERROR)
522 return r;
523 break;
524
525 case MAILMIME_DISPOSITION_PARM_PARAMETER:
526 r = mailmime_parameter_write(f, col, param->pa_data.pa_parameter);
527 if (r != MAILIMF_NO_ERROR)
528 return r;
529 break;
530 }
531
532 return MAILIMF_NO_ERROR;
533}
534
535static int mailmime_parameter_write(FILE * f, int * col,
536 struct mailmime_parameter * param)
537{
538 int r;
539
540 r = mailimf_string_write(f, col, param->pa_name,
541 strlen(param->pa_name));
542 if (r != MAILIMF_NO_ERROR)
543 return r;
544
545 r = mailimf_string_write(f, col, "=", 1);
546 if (r != MAILIMF_NO_ERROR)
547 return r;
548
549 r = mailimf_quoted_string_write(f, col, param->pa_value,
550 strlen(param->pa_value));
551 if (r != MAILIMF_NO_ERROR)
552 return r;
553
554 return MAILIMF_NO_ERROR;
555}
556
557int mailmime_content_type_write(FILE * f, int * col,
558 struct mailmime_content * content)
559{
560 clistiter * cur;
561 size_t len;
562 int r;
563
564 r = mailmime_type_write(f, col, content->ct_type);
565 if (r != MAILIMF_NO_ERROR)
566 return r;
567
568 r = mailimf_string_write(f, col, "/", 1);
569 if (r != MAILIMF_NO_ERROR)
570 return r;
571
572 r = mailimf_string_write(f, col, content->ct_subtype,
573 strlen(content->ct_subtype));
574 if (r != MAILIMF_NO_ERROR)
575 return r;
576
577 if (content->ct_parameters != NULL) {
578 for(cur = clist_begin(content->ct_parameters) ;
579 cur != NULL ; cur = clist_next(cur)) {
580 struct mailmime_parameter * param;
581
582 param = cur->data;
583
584 r = mailimf_string_write(f, col, "; ", 2);
585 if (r != MAILIMF_NO_ERROR)
586 return r;
587
588 len = strlen(param->pa_name) + 1 + strlen(param->pa_value);
589
590 if (* col > 1) {
591
592 if (* col + len > MAX_MAIL_COL) {
593 r = mailimf_string_write(f, col, "\r\n ", 3);
594 if (r != MAILIMF_NO_ERROR)
595 return r;
596#if 0
597 * col = 1;
598#endif
599 }
600 }
601
602 r = mailmime_parameter_write(f, col, param);
603 if (r != MAILIMF_NO_ERROR)
604 return r;
605 }
606 }
607
608 return MAILIMF_NO_ERROR;
609}
610
611int mailmime_content_write(FILE * f, int * col,
612 struct mailmime_content * content)
613{
614 int r;
615
616 r = mailimf_string_write(f, col, "Content-Type: ", 14);
617 if (r != MAILIMF_NO_ERROR)
618 return r;
619
620 r = mailmime_content_type_write(f, col, content);
621 if (r != MAILIMF_NO_ERROR)
622 return r;
623
624 r = mailimf_string_write(f, col, "\r\n", 2);
625 if (r != MAILIMF_NO_ERROR)
626 return r;
627
628 return MAILIMF_NO_ERROR;
629}
630
631static int mailmime_type_write(FILE * f, int * col,
632 struct mailmime_type * type)
633{
634 int r;
635
636 switch (type->tp_type) {
637 case MAILMIME_TYPE_DISCRETE_TYPE:
638 r = mailmime_discrete_type_write(f, col, type->tp_data.tp_discrete_type);
639 break;
640
641 case MAILMIME_TYPE_COMPOSITE_TYPE:
642 r = mailmime_composite_type_write(f, col, type->tp_data.tp_composite_type);
643 break;
644
645 default:
646 r = MAILIMF_ERROR_INVAL;
647 break;
648 }
649
650 if (r != MAILIMF_NO_ERROR)
651 return r;
652
653 return MAILIMF_NO_ERROR;
654}
655
656static int
657mailmime_discrete_type_write(FILE * f, int * col,
658 struct mailmime_discrete_type * discrete_type)
659{
660 int r;
661
662 switch (discrete_type->dt_type) {
663 case MAILMIME_DISCRETE_TYPE_TEXT:
664 r = mailimf_string_write(f, col, "text", 4);
665 break;
666
667 case MAILMIME_DISCRETE_TYPE_IMAGE:
668 r = mailimf_string_write(f, col, "image", 5);
669 break;
670
671 case MAILMIME_DISCRETE_TYPE_AUDIO:
672 r = mailimf_string_write(f, col, "audio", 5);
673 break;
674
675 case MAILMIME_DISCRETE_TYPE_VIDEO:
676 r = mailimf_string_write(f, col, "video", 5);
677 break;
678
679 case MAILMIME_DISCRETE_TYPE_APPLICATION:
680 r = mailimf_string_write(f, col, "application", 11);
681 break;
682
683 case MAILMIME_DISCRETE_TYPE_EXTENSION:
684 r = mailimf_string_write(f, col, discrete_type->dt_extension,
685 strlen(discrete_type->dt_extension));
686 break;
687
688 default:
689 r = MAILIMF_ERROR_INVAL;
690 break;
691 }
692
693 if (r != MAILIMF_NO_ERROR)
694 return r;
695
696 return MAILIMF_NO_ERROR;
697}
698
699static int
700mailmime_composite_type_write(FILE * f, int * col,
701 struct mailmime_composite_type * composite_type)
702{
703 int r;
704
705 switch (composite_type->ct_type) {
706 case MAILMIME_COMPOSITE_TYPE_MESSAGE:
707 r = mailimf_string_write(f, col, "message", 7);
708 break;
709
710 case MAILMIME_COMPOSITE_TYPE_MULTIPART:
711 r = mailimf_string_write(f, col, "multipart", 9);
712 break;
713
714 case MAILMIME_COMPOSITE_TYPE_EXTENSION:
715 r = mailimf_string_write(f, col, composite_type->ct_token,
716 strlen(composite_type->ct_token));
717 break;
718
719 default:
720 r = MAILIMF_ERROR_INVAL;
721 break;
722 }
723
724 if (r != MAILIMF_NO_ERROR)
725 return r;
726
727 return MAILIMF_NO_ERROR;
728}
729
730
731
732
733/* ****************************************************************** */
734/* message */
735
736/*
737static int mailmime_data_write(FILE * f, int * col,
738 struct mailmime_data * data,
739 int is_text);
740*/
741
742static int mailmime_text_content_write(FILE * f, int * col, int encoding,
743 int istext,
744 const char * text, size_t size);
745
746/*
747static int mailmime_base64_write(FILE * f, int * col,
748 char * text, size_t size);
749
750static int mailmime_quoted_printable_write(FILE * f, int * col, int istext,
751 char * text, size_t size);
752*/
753
754static int mailmime_part_write(FILE * f, int * col,
755 struct mailmime * build_info)
756{
757 clistiter * cur;
758 int first;
759 int r;
760 char * boundary;
761 int istext;
762
763 istext = TRUE;
764 boundary = NULL;
765
766 if (build_info->mm_content_type != NULL) {
767 if (build_info->mm_type == MAILMIME_MULTIPLE) {
768 boundary = mailmime_extract_boundary(build_info->mm_content_type);
769 if (boundary == NULL)
770 return MAILIMF_ERROR_INVAL;
771 }
772
773 if (build_info->mm_content_type->ct_type->tp_type ==
774 MAILMIME_TYPE_DISCRETE_TYPE) {
775 if (build_info->mm_content_type->ct_type->tp_data.tp_discrete_type->dt_type !=
776 MAILMIME_DISCRETE_TYPE_TEXT)
777 istext = FALSE;
778 }
779 }
780
781 switch (build_info->mm_type) {
782 case MAILMIME_SINGLE:
783
784 /* 1-part body */
785
786 if (build_info->mm_data.mm_single != NULL) {
787 r = mailmime_data_write(f, col, build_info->mm_data.mm_single, istext);
788 if (r != MAILIMF_NO_ERROR)
789 return r;
790 }
791
792 break;
793
794 case MAILMIME_MULTIPLE:
795
796 /* multi-part */
797
798
799 /* preamble */
800
801 if (build_info->mm_data.mm_multipart.mm_preamble != NULL) {
802 r = mailmime_data_write(f, col,
803 build_info->mm_data.mm_multipart.mm_preamble, TRUE);
804 if (r != MAILIMF_NO_ERROR)
805 return r;
806
807 r = mailimf_string_write(f, col, "\r\n", 2);
808 if (r != MAILIMF_NO_ERROR)
809 return r;
810#if 0
811 * col = 0;
812#endif
813 }
814
815 /* sub-parts */
816
817 first = TRUE;
818
819 for(cur = clist_begin(build_info->mm_data.mm_multipart.mm_mp_list) ;
820 cur != NULL ; cur = clist_next(cur)) {
821 struct mailmime * subpart;
822
823 subpart = cur->data;
824
825 if (!first) {
826 r = mailimf_string_write(f, col, "\r\n", 2);
827 if (r != MAILIMF_NO_ERROR)
828 return r;
829#if 0
830 * col = 0;
831#endif
832 }
833 else {
834 first = FALSE;
835 }
836
837 r = mailimf_string_write(f, col, "--", 2);
838 if (r != MAILIMF_NO_ERROR)
839 return r;
840
841 r = mailimf_string_write(f, col, boundary, strlen(boundary));
842 if (r != MAILIMF_NO_ERROR)
843 return r;
844
845 r = mailimf_string_write(f, col, "\r\n", 2);
846 if (r != MAILIMF_NO_ERROR)
847 return r;
848#if 0
849 * col = 0;
850#endif
851
852 r = mailmime_sub_write(f, col, subpart);
853 if (r != MAILIMF_NO_ERROR)
854 return r;
855 }
856
857 r = mailimf_string_write(f, col, "\r\n", 2);
858 if (r != MAILIMF_NO_ERROR)
859 return r;
860#if 0
861 * col = 0;
862#endif
863
864 r = mailimf_string_write(f, col, "--", 2);
865 if (r != MAILIMF_NO_ERROR)
866 return r;
867
868 r = mailimf_string_write(f, col, boundary, strlen(boundary));
869 if (r != MAILIMF_NO_ERROR)
870 return r;
871
872 r = mailimf_string_write(f, col, "--", 2);
873 if (r != MAILIMF_NO_ERROR)
874 return r;
875
876
877 /* epilogue */
878
879 r = mailimf_string_write(f, col, "\r\n", 2);
880 if (r != MAILIMF_NO_ERROR)
881 return r;
882#if 0
883 * col = 0;
884#endif
885
886 if (build_info->mm_data.mm_multipart.mm_epilogue != NULL) {
887 r = mailmime_data_write(f, col,
888 build_info->mm_data.mm_multipart.mm_epilogue, TRUE);
889 if (r != MAILIMF_NO_ERROR)
890 return r;
891 }
892
893 break;
894
895 case MAILMIME_MESSAGE:
896
897 if (build_info->mm_data.mm_message.mm_fields != NULL) {
898 r = mailimf_fields_write(f, col,
899 build_info->mm_data.mm_message.mm_fields);
900 if (r != MAILIMF_NO_ERROR)
901 return r;
902 }
903
904 if (build_info->mm_mime_fields != NULL) {
905 r = mailmime_fields_write(f, col, build_info->mm_mime_fields);
906 if (r != MAILIMF_NO_ERROR)
907 return r;
908 }
909
910 /* encapsuled message */
911
912 if (build_info->mm_data.mm_message.mm_msg_mime != NULL) {
913 r = mailmime_sub_write(f, col,
914 build_info->mm_data.mm_message.mm_msg_mime);
915 if (r != MAILIMF_NO_ERROR)
916 return r;
917 }
918 break;
919
920 }
921
922 return MAILIMF_NO_ERROR;
923}
924
925
926static int mailmime_sub_write(FILE * f, int * col,
927 struct mailmime * build_info)
928{
929 int r;
930
931#if 0
932 * col = 0;
933#endif
934 /* MIME field - Content-Type */
935
936 if (build_info->mm_content_type != NULL) {
937 r = mailmime_content_write(f, col, build_info->mm_content_type);
938 if (r != MAILIMF_NO_ERROR)
939 return r;
940 }
941
942 /* other MIME fields */
943
944 if (build_info->mm_type != MAILMIME_MESSAGE) {
945 if (build_info->mm_mime_fields != NULL) {
946 r = mailmime_fields_write(f, col, build_info->mm_mime_fields);
947 if (r != MAILIMF_NO_ERROR)
948 return r;
949 }
950 }
951
952 r = mailimf_string_write(f, col, "\r\n", 2);
953 if (r != MAILIMF_NO_ERROR)
954 return r;
955#if 0
956 * col = 0;
957#endif
958
959 return mailmime_part_write(f, col, build_info);
960}
961
962int mailmime_write(FILE * f, int * col,
963 struct mailmime * build_info)
964{
965 if (build_info->mm_parent != NULL)
966 return mailmime_sub_write(f, col, build_info);
967 else
968 return mailmime_part_write(f, col, build_info);
969}
970
971
972int mailmime_data_write(FILE * f, int * col,
973 struct mailmime_data * data,
974 int istext)
975{
976 int fd;
977 int r;
978 char * text;
979 struct stat buf;
980 int res;
981
982 switch (data->dt_type) {
983 case MAILMIME_DATA_TEXT:
984
985 if (data->dt_encoded) {
986 r = mailimf_string_write(f, col,
987 data->dt_data.dt_text.dt_data,
988 data->dt_data.dt_text.dt_length);
989 if (r != MAILIMF_NO_ERROR)
990 return r;
991 }
992 else {
993 r = mailmime_text_content_write(f, col, data->dt_encoding, istext,
994 data->dt_data.dt_text.dt_data,
995 data->dt_data.dt_text.dt_length);
996 if (r != MAILIMF_NO_ERROR)
997 return r;
998 }
999
1000 break;
1001
1002 case MAILMIME_DATA_FILE:
1003 fd = open(data->dt_data.dt_filename, O_RDONLY);
1004 if (fd < 0) {
1005 res = MAILIMF_ERROR_FILE;
1006 goto err;
1007 }
1008
1009 r = fstat(fd, &buf);
1010 if (r < 0) {
1011 res = MAILIMF_ERROR_FILE;
1012 goto close;
1013 }
1014
1015 if (buf.st_size != 0) {
1016 text = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1017 if (text == MAP_FAILED) {
1018 res = MAILIMF_ERROR_FILE;
1019 goto close;
1020 }
1021
1022 if (data->dt_encoded) {
1023 r = mailimf_string_write(f, col, text, buf.st_size);
1024 if (r != MAILIMF_NO_ERROR) {
1025 res = r;
1026 goto unmap;
1027 }
1028 }
1029 else {
1030 r = mailmime_text_content_write(f, col, data->dt_encoding, istext,
1031 text, buf.st_size);
1032 if (r != MAILIMF_NO_ERROR) {
1033 res = r;
1034 goto unmap;
1035 }
1036 }
1037
1038 munmap(text, buf.st_size);
1039 }
1040 close(fd);
1041
1042 if (r != MAILIMF_NO_ERROR)
1043 return r;
1044
1045 break;
1046
1047 unmap:
1048 munmap(text, buf.st_size);
1049 close:
1050 close(fd);
1051 err:
1052 return res;
1053 }
1054
1055 return MAILIMF_NO_ERROR;
1056}
1057
1058static int mailmime_text_content_write(FILE * f, int * col, int encoding,
1059 int istext,
1060 const char * text, size_t size)
1061{
1062 switch (encoding) {
1063 case MAILMIME_MECHANISM_QUOTED_PRINTABLE:
1064 return mailmime_quoted_printable_write(f, col, istext, text, size);
1065 break;
1066
1067 case MAILMIME_MECHANISM_BASE64:
1068 return mailmime_base64_write(f, col, text, size);
1069 break;
1070
1071 case MAILMIME_MECHANISM_7BIT:
1072 case MAILMIME_MECHANISM_8BIT:
1073 case MAILMIME_MECHANISM_BINARY:
1074 default:
1075 return mailimf_string_write(f, col, text, size);
1076 }
1077}
1078
1079
1080static const char base64_encoding[] =
1081"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1082
1083#define BASE64_MAX_COL 76
1084
1085int mailmime_base64_write(FILE * f, int * col,
1086 const char * text, size_t size)
1087{
1088 int a;
1089 int b;
1090 int c;
1091 size_t remains;
1092 const char * p;
1093 size_t count;
1094 char ogroup[4];
1095 int r;
1096
1097 remains = size;
1098 p = text;
1099
1100 while (remains > 0) {
1101 switch (remains) {
1102 case 1:
1103 a = (unsigned char) p[0];
1104 b = 0;
1105 c = 0;
1106 count = 1;
1107 break;
1108 case 2:
1109 a = (unsigned char) p[0];
1110 b = (unsigned char) p[1];
1111 c = 0;
1112 count = 2;
1113 break;
1114 default:
1115 a = (unsigned char) p[0];
1116 b = (unsigned char) p[1];
1117 c = (unsigned char) p[2];
1118 count = 3;
1119 break;
1120 }
1121
1122 ogroup[0]= base64_encoding[a >> 2];
1123 ogroup[1]= base64_encoding[((a & 3) << 4) | (b >> 4)];
1124 ogroup[2]= base64_encoding[((b & 0xF) << 2) | (c >> 6)];
1125 ogroup[3]= base64_encoding[c & 0x3F];
1126
1127 switch (count) {
1128 case 1:
1129 ogroup[2]= '=';
1130 ogroup[3]= '=';
1131 break;
1132 case 2:
1133 ogroup[3]= '=';
1134 break;
1135 }
1136
1137 if (* col + 4 > BASE64_MAX_COL) {
1138 r = mailimf_string_write(f, col, "\r\n", 2);
1139 if (r != MAILIMF_NO_ERROR)
1140 return r;
1141#if 0
1142 * col = 0;
1143#endif
1144 }
1145
1146 r = mailimf_string_write(f, col, ogroup, 4);
1147 if (r != MAILIMF_NO_ERROR)
1148 return r;
1149
1150 remains -= count;
1151 p += count;
1152 }
1153
1154 r = mailimf_string_write(f, col, "\r\n", 2);
1155
1156 return MAILIMF_NO_ERROR;
1157}
1158
1159#if 0
1160#define MAX_WRITE_SIZE 512
1161#endif
1162
1163enum {
1164 STATE_INIT,
1165 STATE_CR,
1166 STATE_SPACE,
1167 STATE_SPACE_CR,
1168};
1169
1170#if 0
1171static inline int write_try_buf(FILE * f, int * col,
1172 char ** pstart, size_t * plen)
1173{
1174 int r;
1175
1176 if (* plen >= MAX_WRITE_SIZE) {
1177 r = mailimf_string_write(f, col, * pstart, * plen);
1178 if (r != MAILIMF_NO_ERROR)
1179 return r;
1180 * plen = 0;
1181 }
1182
1183 return MAILIMF_NO_ERROR;
1184}
1185#endif
1186
1187static inline int write_remaining(FILE * f, int * col,
1188 const char ** pstart, size_t * plen)
1189{
1190 int r;
1191
1192 if (* plen > 0) {
1193 r = mailimf_string_write(f, col, * pstart, * plen);
1194 if (r != MAILIMF_NO_ERROR)
1195 return r;
1196 * plen = 0;
1197 }
1198
1199 return MAILIMF_NO_ERROR;
1200}
1201
1202
1203
1204#define QP_MAX_COL 72
1205
1206int mailmime_quoted_printable_write(FILE * f, int * col, int istext,
1207 const char * text, size_t size)
1208{
1209 size_t i;
1210 const char * start;
1211 size_t len;
1212 char hexstr[6];
1213 int r;
1214 int state;
1215
1216 start = text;
1217 len = 0;
1218 state = STATE_INIT;
1219
1220 i = 0;
1221 while (i < size) {
1222 unsigned char ch;
1223
1224 if (* col + len > QP_MAX_COL) {
1225 r = write_remaining(f, col, &start, &len);
1226 if (r != MAILIMF_NO_ERROR)
1227 return r;
1228 start = text + i;
1229
1230 r = mailimf_string_write(f, col, "=\r\n", 3);
1231 if (r != MAILIMF_NO_ERROR)
1232 return r;
1233 }
1234
1235 ch = text[i];
1236
1237 switch (state) {
1238
1239 case STATE_INIT:
1240 switch (ch) {
1241 case ' ':
1242 case '\t':
1243 state = STATE_SPACE;
1244 break;
1245
1246 case '\r':
1247 state = STATE_CR;
1248 break;
1249
1250 case '!':
1251 case '"':
1252 case '#':
1253 case '$':
1254 case '@':
1255 case '[':
1256 case '\\':
1257 case ']':
1258 case '^':
1259 case '`':
1260 case '{':
1261 case '|':
1262 case '}':
1263 case '~':
1264 case '=':
1265 case '?':
1266 case '_':
1267 case 'F': /* there is no more 'From' at the beginning of a line */
1268 r = write_remaining(f, col, &start, &len);
1269 if (r != MAILIMF_NO_ERROR)
1270 return r;
1271 start = text + i + 1;
1272
1273 snprintf(hexstr, 6, "=%02X", ch);
1274
1275 r = mailimf_string_write(f, col, hexstr, 3);
1276 if (r != MAILIMF_NO_ERROR)
1277 return r;
1278 break;
1279
1280 default:
1281 if (istext && (ch == '\n')) {
1282 r = write_remaining(f, col, &start, &len);
1283 if (r != MAILIMF_NO_ERROR)
1284 return r;
1285 start = text + i + 1;
1286
1287 r = mailimf_string_write(f, col, "\r\n", 2);
1288 if (r != MAILIMF_NO_ERROR)
1289 return r;
1290 break;
1291 }
1292 else {
1293 if (((ch >= 33) && (ch <= 60)) || ((ch >= 62) && (ch <= 126))) {
1294 len ++;
1295 }
1296 else {
1297 r = write_remaining(f, col, &start, &len);
1298 if (r != MAILIMF_NO_ERROR)
1299 return r;
1300 start = text + i + 1;
1301
1302 snprintf(hexstr, 6, "=%02X", ch);
1303
1304 r = mailimf_string_write(f, col, hexstr, 3);
1305 if (r != MAILIMF_NO_ERROR)
1306 return r;
1307 }
1308 }
1309
1310 break;
1311 }
1312
1313 i ++;
1314 break;
1315
1316 case STATE_CR:
1317 switch (ch) {
1318 case '\n':
1319 r = write_remaining(f, col, &start, &len);
1320 if (r != MAILIMF_NO_ERROR)
1321 return r;
1322 start = text + i + 1;
1323 r = mailimf_string_write(f, col, "\r\n", 2);
1324 if (r != MAILIMF_NO_ERROR)
1325 return r;
1326 i ++;
1327 state = STATE_INIT;
1328 break;
1329
1330 default:
1331 r = write_remaining(f, col, &start, &len);
1332 if (r != MAILIMF_NO_ERROR)
1333 return r;
1334 start = text + i;
1335 snprintf(hexstr, 6, "=%02X", '\r');
1336 r = mailimf_string_write(f, col, hexstr, 3);
1337 if (r != MAILIMF_NO_ERROR)
1338 return r;
1339 state = STATE_INIT;
1340 break;
1341 }
1342 break;
1343
1344 case STATE_SPACE:
1345 switch (ch) {
1346 case '\r':
1347 state = STATE_SPACE_CR;
1348 i ++;
1349 break;
1350
1351 case '\n':
1352 r = write_remaining(f, col, &start, &len);
1353 if (r != MAILIMF_NO_ERROR)
1354 return r;
1355 start = text + i + 1;
1356 snprintf(hexstr, 6, "=%02X\r\n", text[i - 1]);
1357 r = mailimf_string_write(f, col, hexstr, strlen(hexstr));
1358 if (r != MAILIMF_NO_ERROR)
1359 return r;
1360 state = STATE_INIT;
1361 i ++;
1362 break;
1363
1364 case ' ':
1365 case '\t':
1366 len ++;
1367 i ++;
1368 break;
1369
1370 default:
1371#if 0
1372 len += 2;
1373 state = STATE_INIT;
1374 i ++;
1375#endif
1376 len ++;
1377 state = STATE_INIT;
1378 break;
1379 }
1380
1381 break;
1382
1383 case STATE_SPACE_CR:
1384 switch (ch) {
1385 case '\n':
1386 r = write_remaining(f, col, &start, &len);
1387 if (r != MAILIMF_NO_ERROR)
1388 return r;
1389 start = text + i + 1;
1390 snprintf(hexstr, 6, "=%02X\r\n", text[i - 2]);
1391 r = mailimf_string_write(f, col, hexstr, strlen(hexstr));
1392 if (r != MAILIMF_NO_ERROR)
1393 return r;
1394 state = STATE_INIT;
1395 i ++;
1396 break;
1397
1398 default:
1399 r = write_remaining(f, col, &start, &len);
1400 if (r != MAILIMF_NO_ERROR)
1401 return r;
1402 start = text + i + 1;
1403 snprintf(hexstr, 6, "%c=%02X", text[i - 2], '\r');
1404 r = mailimf_string_write(f, col, hexstr, strlen(hexstr));
1405 if (r != MAILIMF_NO_ERROR)
1406 return r;
1407 state = STATE_INIT;
1408 break;
1409 }
1410
1411 break;
1412 }
1413 }
1414
1415 return MAILIMF_NO_ERROR;
1416}