summaryrefslogtreecommitdiffabout
path: root/libetpan/src/engine/mailprivacy_tools.c
Unidiff
Diffstat (limited to 'libetpan/src/engine/mailprivacy_tools.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/engine/mailprivacy_tools.c1283
1 files changed, 1283 insertions, 0 deletions
diff --git a/libetpan/src/engine/mailprivacy_tools.c b/libetpan/src/engine/mailprivacy_tools.c
new file mode 100644
index 0000000..cae2ef8
--- a/dev/null
+++ b/libetpan/src/engine/mailprivacy_tools.c
@@ -0,0 +1,1283 @@
1/*
2 * libEtPan! -- a mail 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 "mailprivacy_tools.h"
37
38#include <stdlib.h>
39#include <string.h>
40#include <libgen.h>
41#include <unistd.h>
42#include <sys/mman.h>
43#include <sys/types.h>
44#include <sys/stat.h>
45#include <fcntl.h>
46#include <libetpan/mailmessage.h>
47#include <ctype.h>
48#include "mailprivacy.h"
49#include <libetpan/libetpan-config.h>
50#include <libetpan/data_message_driver.h>
51
52void mailprivacy_mime_clear(struct mailmime * mime)
53{
54 struct mailmime_data * data;
55 clistiter * cur;
56
57 switch (mime->mm_type) {
58 case MAILMIME_SINGLE:
59 data = mime->mm_data.mm_single;
60 if (data != NULL) {
61 if (data->dt_type == MAILMIME_DATA_FILE)
62 unlink(data->dt_data.dt_filename);
63 }
64 break;
65
66 case MAILMIME_MULTIPLE:
67 data = mime->mm_data.mm_multipart.mm_preamble;
68 if (data != NULL) {
69 if (data->dt_type == MAILMIME_DATA_FILE)
70 unlink(data->dt_data.dt_filename);
71 }
72 data = mime->mm_data.mm_multipart.mm_epilogue;
73 if (data != NULL) {
74 if (data->dt_type == MAILMIME_DATA_FILE)
75 unlink(data->dt_data.dt_filename);
76 }
77
78 for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ;
79 cur != NULL ; cur = clist_next(cur)) {
80 struct mailmime * submime;
81
82 submime = clist_content(cur);
83
84 mailprivacy_mime_clear(submime);
85 }
86 break;
87
88 case MAILMIME_MESSAGE:
89 if (mime->mm_data.mm_message.mm_msg_mime != NULL) {
90 mailprivacy_mime_clear(mime->mm_data.mm_message.mm_msg_mime);
91 }
92 break;
93 }
94}
95
96
97static FILE * get_tmp_file(char * filename)
98{
99 int fd;
100 mode_t old_mask;
101 FILE * f;
102
103 old_mask = umask(0077);
104 fd = mkstemp(filename);
105 umask(old_mask);
106 if (fd == -1)
107 return NULL;
108
109 f = fdopen(fd, "r+");
110 if (f == NULL) {
111 close(fd);
112 unlink(filename);
113 }
114
115 return f;
116}
117
118FILE * mailprivacy_get_tmp_file(struct mailprivacy * privacy,
119 char * filename, size_t size)
120{
121 snprintf(filename, size, "%s/libetpan-privacy-XXXXXX", privacy->tmp_dir);
122 return get_tmp_file(filename);
123}
124
125
126static char * dup_file(struct mailprivacy * privacy,
127 char * source_filename)
128{
129 char filename[PATH_MAX];
130 FILE * dest_f;
131 int r;
132 struct stat stat_info;
133 char * dest_filename;
134 char * mapping;
135 size_t written;
136 int fd;
137
138 dest_f = mailprivacy_get_tmp_file(privacy, filename, sizeof(filename));
139 if (dest_f == NULL)
140 goto err;
141
142 dest_filename = strdup(filename);
143 if (dest_filename == NULL)
144 goto close_dest;
145
146 fd = open(source_filename, O_RDONLY);
147 if (fd < 0)
148 goto free_dest;
149
150 r = fstat(fd, &stat_info);
151 if (r < 0)
152 goto close_src;
153
154 mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
155 if (mapping == MAP_FAILED)
156 goto close_src;
157
158 written = fwrite(mapping, 1, stat_info.st_size, dest_f);
159 if (written != (size_t) stat_info.st_size)
160 goto unmap;
161
162 munmap(mapping, stat_info.st_size);
163 close(fd);
164 fclose(dest_f);
165
166 return dest_filename;
167
168 unmap:
169 munmap(mapping, stat_info.st_size);
170 close_src:
171 close(fd);
172 free_dest:
173 free(dest_filename);
174 close_dest:
175 fclose(dest_f);
176 err:
177 return NULL;
178}
179
180
181/*
182 mime_data_replace()
183
184 write a mime part to a file and change the reference of mailmime_data
185 to the file.
186*/
187
188static int mime_data_replace(struct mailprivacy * privacy,
189 int encoding_type,
190 struct mailmime_data * data)
191{
192 char filename[PATH_MAX];
193 FILE * f;
194 size_t written;
195 char * dup_filename;
196 int res;
197 int r;
198 int decoded;
199
200 if (data->dt_type != MAILMIME_DATA_TEXT) {
201 res = MAIL_NO_ERROR;
202 goto err;
203 }
204
205 f = mailprivacy_get_tmp_file(privacy, filename, sizeof(filename));
206 if (f == NULL) {
207 res = MAIL_ERROR_FILE;
208 goto err;
209 }
210
211 decoded = 0;
212 if (encoding_type != -1) {
213 char * content;
214 size_t content_len;
215 size_t cur_token;
216
217 cur_token = 0;
218 r = mailmime_part_parse(data->dt_data.dt_text.dt_data,
219 data->dt_data.dt_text.dt_length,
220 &cur_token, encoding_type, &content, &content_len);
221
222 if (r == MAILIMF_NO_ERROR) {
223 /* write decoded */
224 written = fwrite(content, 1, content_len, f);
225 if (written != content_len) {
226 fclose(f);
227 unlink(filename);
228 res = MAIL_ERROR_FILE;
229 goto err;
230 }
231 mmap_string_unref(content);
232
233 decoded = 1;
234 data->dt_encoded = 0;
235 }
236 }
237
238 if (!decoded) {
239 written = fwrite(data->dt_data.dt_text.dt_data, 1,
240 data->dt_data.dt_text.dt_length, f);
241 if (written != data->dt_data.dt_text.dt_length) {
242 fclose(f);
243 unlink(filename);
244 res = MAIL_ERROR_FILE;
245 goto err;
246 }
247 }
248
249 fclose(f);
250
251 dup_filename = strdup(filename);
252 if (dup_filename == NULL) {
253 unlink(filename);
254 res = MAIL_ERROR_MEMORY;
255 goto err;
256 }
257
258 data->dt_type = MAILMIME_DATA_FILE;
259 data->dt_data.dt_filename = dup_filename;
260
261 return MAIL_NO_ERROR;
262
263 err:
264 return res;
265}
266
267
268/*
269 recursive_replace_single_parts()
270
271 write all parts of the given mime part to file.
272*/
273
274static int recursive_replace_single_parts(struct mailprivacy * privacy,
275 struct mailmime * mime)
276{
277 int r;
278 int res;
279 clistiter * cur;
280
281 mime->mm_mime_start = NULL;
282
283 switch(mime->mm_type) {
284 case MAILMIME_SINGLE:
285 if (mime->mm_data.mm_single != NULL) {
286 int encoding_type;
287 struct mailmime_single_fields single_fields;
288
289 mailmime_single_fields_init(&single_fields, mime->mm_mime_fields,
290 mime->mm_content_type);
291
292 if (single_fields.fld_encoding != NULL)
293 encoding_type = single_fields.fld_encoding->enc_type;
294 else
295 encoding_type = -1;
296
297 r = mime_data_replace(privacy, encoding_type, mime->mm_data.mm_single);
298 if (r != MAIL_NO_ERROR) {
299 res = r;
300 goto err;
301 }
302 }
303 break;
304
305 case MAILMIME_MULTIPLE:
306 if (mime->mm_data.mm_multipart.mm_preamble != NULL) {
307 r = mime_data_replace(privacy, -1,
308 mime->mm_data.mm_multipart.mm_preamble);
309 if (r != MAIL_NO_ERROR) {
310 res = r;
311 goto err;
312 }
313 }
314
315 if (mime->mm_data.mm_multipart.mm_epilogue != NULL) {
316 r = mime_data_replace(privacy, -1,
317 mime->mm_data.mm_multipart.mm_epilogue);
318 if (r != MAIL_NO_ERROR) {
319 res = r;
320 goto err;
321 }
322 }
323
324 for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ;
325 cur != NULL ; cur = clist_next(cur)) {
326 struct mailmime * child;
327
328 child = clist_content(cur);
329
330 r = recursive_replace_single_parts(privacy, child);
331 if (r != MAIL_NO_ERROR) {
332 res = r;
333 goto err;
334 }
335 }
336
337 break;
338
339 case MAILMIME_MESSAGE:
340 if (mime->mm_data.mm_message.mm_msg_mime != NULL) {
341 r = recursive_replace_single_parts(privacy,
342 mime->mm_data.mm_message.mm_msg_mime);
343 if (r != MAIL_NO_ERROR) {
344 res = r;
345 goto err;
346 }
347 }
348 break;
349 }
350
351 return MAIL_NO_ERROR;
352
353 err:
354 return res;
355}
356
357/*
358 mailprivacy_get_mime()
359
360 parse the message in MIME structure,
361 all single MIME parts are stored in files.
362
363 privacy can be set to NULL to disable privacy check.
364*/
365
366int mailprivacy_get_mime(struct mailprivacy * privacy,
367 int check_privacy,
368 char * content, size_t content_len,
369 struct mailmime ** result_mime)
370{
371 struct mailmime * mime;
372 mailmessage * msg;
373 int r;
374 int res;
375
376#if 0
377 int check_privacy;
378
379 check_privacy = (privacy != NULL);
380#endif
381
382 /*
383 use message data driver, get bodystructure and
384 convert all the data part in MAILMIME_SINGLE to files.
385 */
386
387 msg = data_message_init(content, content_len);
388 if (msg == NULL) {
389 res = MAIL_ERROR_MEMORY;
390 goto err;
391 }
392
393#if 0
394 if (msg->mime == NULL) {
395 if (check_privacy) {
396 r = mailprivacy_msg_get_bodystructure(privacy, msg, &mime);
397 }
398 else {
399 /*
400 don't use etpan_msg_get_bodystructure because it is not useful
401 and to avoid loops due to security part
402 */
403 r = mailmessage_get_bodystructure(msg, &mime);
404 }
405 }
406 else {
407 mime = msg->mime;
408 }
409#endif
410
411 if (check_privacy)
412 r = mailprivacy_msg_get_bodystructure(privacy, msg, &mime);
413 else
414 r = mailmessage_get_bodystructure(msg, &mime);
415 if (r != MAIL_NO_ERROR) {
416 res = r;
417 goto free_msg;
418 }
419
420 /*
421 should be done so that the MIME structure need not to be unregistered.
422 */
423 mailprivacy_recursive_unregister_mime(privacy, mime);
424
425 r = recursive_replace_single_parts(privacy, mime);
426 if (r != MAIL_NO_ERROR) {
427 res = r;
428 goto clear_mime;
429 }
430
431 data_message_detach_mime(msg);
432#if 0
433 if (check_privacy)
434 mailprivacy_msg_flush(privacy, msg);
435 else
436 mailmessage_flush(msg);
437#endif
438 mailprivacy_msg_flush(privacy, msg);
439 mailmessage_free(msg);
440
441 * result_mime = mime;
442
443 return MAIL_NO_ERROR;
444
445 clear_mime:
446 mailprivacy_mime_clear(mime);
447 mailprivacy_msg_flush(privacy, msg);
448 free_msg:
449 mailmessage_free(msg);
450 err:
451 return res;
452}
453
454#ifndef LIBETPAN_SYSTEM_BASENAME
455static char * libetpan_basename(char * filename)
456{
457 char * next;
458 char * p;
459
460 p = filename;
461 next = strchr(p, '/');
462
463 while (next != NULL) {
464 p = next;
465 next = strchr(p + 1, '/');
466 }
467
468 if (p == filename)
469 return filename;
470 else
471 return p + 1;
472}
473#else
474#define libetpan_basename(a) basename(a)
475#endif
476
477struct mailmime *
478mailprivacy_new_file_part(struct mailprivacy * privacy,
479 char * filename,
480 char * default_content_type, int default_encoding)
481{
482 char basename_buf[PATH_MAX];
483 char * name;
484 struct mailmime_mechanism * encoding;
485 struct mailmime_content * content;
486 struct mailmime * mime;
487 int r;
488 char * dup_filename;
489 struct mailmime_fields * mime_fields;
490 int encoding_type;
491 char * content_type_str;
492 int do_encoding;
493
494 if (filename != NULL) {
495 strncpy(basename_buf, filename, PATH_MAX);
496 name = libetpan_basename(basename_buf);
497 }
498 else {
499 name = NULL;
500 }
501
502 encoding = NULL;
503
504 /* default content-type */
505 if (default_content_type == NULL)
506 content_type_str = "application/octet-stream";
507 else
508 content_type_str = default_content_type;
509
510 content = mailmime_content_new_with_str(content_type_str);
511 if (content == NULL) {
512 goto free_content;
513 }
514
515 do_encoding = 1;
516 if (content->ct_type->tp_type == MAILMIME_TYPE_COMPOSITE_TYPE) {
517 struct mailmime_composite_type * composite;
518
519 composite = content->ct_type->tp_data.tp_composite_type;
520
521 switch (composite->ct_type) {
522 case MAILMIME_COMPOSITE_TYPE_MESSAGE:
523 if (strcasecmp(content->ct_subtype, "rfc822") == 0)
524 do_encoding = 0;
525 break;
526
527 case MAILMIME_COMPOSITE_TYPE_MULTIPART:
528 do_encoding = 0;
529 break;
530 }
531 }
532
533 if (do_encoding) {
534 if (default_encoding == -1)
535 encoding_type = MAILMIME_MECHANISM_BASE64;
536 else
537 encoding_type = default_encoding;
538
539 /* default Content-Transfer-Encoding */
540 encoding = mailmime_mechanism_new(encoding_type, NULL);
541 if (encoding == NULL) {
542 goto free_content;
543 }
544 }
545
546 mime_fields = mailmime_fields_new_with_data(encoding,
547 NULL, NULL, NULL, NULL);
548 if (mime_fields == NULL) {
549 goto free_content;
550 }
551
552 mime = mailmime_new_empty(content, mime_fields);
553 if (mime == NULL) {
554 goto free_mime_fields;
555 }
556
557 if ((filename != NULL) && (mime->mm_type == MAILMIME_SINGLE)) {
558 /*
559 duplicates the file so that the file can be deleted when
560 the MIME part is done
561 */
562 dup_filename = dup_file(privacy, filename);
563 if (dup_filename == NULL) {
564 goto free_mime;
565 }
566
567 r = mailmime_set_body_file(mime, dup_filename);
568 if (r != MAILIMF_NO_ERROR) {
569 free(dup_filename);
570 goto free_mime;
571 }
572 }
573
574 return mime;
575
576 free_mime:
577 mailmime_free(mime);
578 goto err;
579 free_mime_fields:
580 mailmime_fields_free(mime_fields);
581 mailmime_content_free(content);
582 goto err;
583 free_content:
584 if (encoding != NULL)
585 mailmime_mechanism_free(encoding);
586 if (content != NULL)
587 mailmime_content_free(content);
588 err:
589 return NULL;
590}
591
592
593int mailmime_substitute(struct mailmime * old_mime,
594 struct mailmime * new_mime)
595{
596 struct mailmime * parent;
597
598 parent = old_mime->mm_parent;
599 if (parent == NULL)
600 return MAIL_ERROR_INVAL;
601
602 if (old_mime->mm_parent_type == MAILMIME_MESSAGE)
603 parent->mm_data.mm_message.mm_msg_mime = new_mime;
604 else /* MAILMIME_MULTIPLE */
605 old_mime->mm_multipart_pos->data = new_mime;
606 new_mime->mm_parent = parent;
607 new_mime->mm_parent_type = old_mime->mm_parent_type;
608
609 /* detach old_mime */
610 old_mime->mm_parent = NULL;
611 old_mime->mm_parent_type = MAILMIME_NONE;
612
613 return MAIL_NO_ERROR;
614}
615
616
617
618/* write mime headers and body to a file, CR LF fixed */
619
620int mailprivacy_fetch_mime_body_to_file(struct mailprivacy * privacy,
621 char * filename, size_t size,
622 mailmessage * msg, struct mailmime * mime)
623{
624 int r;
625 int res;
626 FILE * f;
627 char * content;
628 size_t content_len;
629 int col;
630
631 if (mime->mm_parent_type == MAILMIME_NONE) {
632 res = MAIL_ERROR_INVAL;
633 goto err;
634 }
635
636 f = mailprivacy_get_tmp_file(privacy, filename, size);
637 if (f == NULL) {
638 res = MAIL_ERROR_FETCH;
639 goto err;
640 }
641
642 r = mailprivacy_msg_fetch_section_mime(privacy, msg, mime,
643 &content, &content_len);
644 if (r != MAIL_NO_ERROR) {
645 res = MAIL_ERROR_FETCH;
646 goto close;
647 }
648
649 col = 0;
650 r = mailimf_string_write(f, &col, content, content_len);
651 mailprivacy_msg_fetch_result_free(privacy, msg, content);
652 if (r != MAILIMF_NO_ERROR) {
653 res = r;
654 goto close;
655 }
656
657 r = mailprivacy_msg_fetch_section(privacy, msg, mime,
658 &content, &content_len);
659 if (r != MAIL_NO_ERROR) {
660 res = MAIL_ERROR_FETCH;
661 goto close;
662 }
663
664 r = mailimf_string_write(f, &col, content, content_len);
665 mailprivacy_msg_fetch_result_free(privacy, msg, content);
666 if (r != MAILIMF_NO_ERROR) {
667 res = r;
668 goto close;
669 }
670
671 fclose(f);
672
673 return MAIL_NO_ERROR;
674
675 close:
676 fclose(f);
677 unlink(filename);
678 err:
679 return res;
680}
681
682
683int mailprivacy_get_part_from_file(struct mailprivacy * privacy,
684 int check_security, char * filename,
685 struct mailmime ** result_mime)
686{
687 int fd;
688 struct mailmime * mime;
689 int r;
690 struct stat stat_info;
691 int res;
692 char * mapping;
693
694 fd = open(filename, O_RDONLY);
695 if (fd < 0) {
696 res = MAIL_ERROR_FILE;
697 goto err;
698 }
699
700 r = fstat(fd, &stat_info);
701 if (r < 0) {
702 res = MAIL_ERROR_FILE;
703 goto close;
704 }
705
706 mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
707 if (mapping == MAP_FAILED) {
708 res = MAIL_ERROR_FILE;
709 goto close;
710 }
711
712 /* check recursive parts if privacy is set */
713 r = mailprivacy_get_mime(privacy, check_security,
714 mapping, stat_info.st_size, &mime);
715 if (r != MAIL_NO_ERROR) {
716 res = r;
717 goto unmap;
718 }
719
720 if (mime->mm_type == MAILMIME_MESSAGE) {
721 struct mailmime * submime;
722
723 submime = mime->mm_data.mm_message.mm_msg_mime;
724 if (mime->mm_data.mm_message.mm_msg_mime != NULL) {
725 mailmime_remove_part(submime);
726 mailmime_free(mime);
727
728 mime = submime;
729 }
730 }
731
732 munmap(mapping, stat_info.st_size);
733
734 close(fd);
735
736 * result_mime = mime;
737
738 return MAIL_NO_ERROR;
739
740 unmap:
741 munmap(mapping, stat_info.st_size);
742 close:
743 close(fd);
744 err:
745 return res;
746}
747
748int mail_quote_filename(char * result, size_t size, char * path)
749{
750 char * p;
751 char * result_p;
752 size_t remaining;
753
754 result_p = result;
755 remaining = size;
756
757 for(p = path ; * p != '\0' ; p ++) {
758
759 if (isalpha(* p) || isdigit(* p) || (* p == '/')) {
760 if (remaining > 0) {
761 * result_p = * p;
762 result_p ++;
763 remaining --;
764 }
765 else {
766 result[size - 1] = '\0';
767 return -1;
768 }
769 }
770 else {
771 if (remaining >= 2) {
772 * result_p = '\\';
773 result_p ++;
774 * result_p = * p;
775 result_p ++;
776 remaining -= 2;
777 }
778 else {
779 result[size - 1] = '\0';
780 return -1;
781 }
782 }
783 }
784 if (remaining > 0) {
785 * result_p = '\0';
786 }
787 else {
788 result[size - 1] = '\0';
789 return -1;
790 }
791
792 return 0;
793}
794
795
796static void prepare_mime_single(struct mailmime * mime)
797{
798 struct mailmime_single_fields single_fields;
799 int encoding;
800 int r;
801
802 if (mime->mm_mime_fields != NULL) {
803 mailmime_single_fields_init(&single_fields, mime->mm_mime_fields,
804 mime->mm_content_type);
805 if (single_fields.fld_encoding != NULL) {
806 encoding = single_fields.fld_encoding->enc_type;
807 switch (encoding) {
808 case MAILMIME_MECHANISM_8BIT:
809 case MAILMIME_MECHANISM_7BIT:
810 case MAILMIME_MECHANISM_BINARY:
811 single_fields.fld_encoding->enc_type =
812 MAILMIME_MECHANISM_QUOTED_PRINTABLE;
813 break;
814 }
815 }
816 else {
817 struct mailmime_mechanism * mechanism;
818 struct mailmime_field * field;
819
820 mechanism =
821 mailmime_mechanism_new(MAILMIME_MECHANISM_QUOTED_PRINTABLE, NULL);
822 if (mechanism == NULL)
823 return;
824
825 field = mailmime_field_new(MAILMIME_FIELD_TRANSFER_ENCODING,
826 NULL, mechanism, NULL, NULL, 0, NULL, NULL);
827 if (field == NULL) {
828 mailmime_mechanism_free(mechanism);
829 return;
830 }
831
832 r = clist_append(mime->mm_mime_fields->fld_list, field);
833 if (r < 0) {
834 mailmime_field_free(field);
835 return;
836 }
837 }
838 }
839
840 if (mime->mm_type == MAILMIME_SINGLE) {
841 switch (mime->mm_data.mm_single->dt_encoding) {
842 case MAILMIME_MECHANISM_8BIT:
843 case MAILMIME_MECHANISM_7BIT:
844 case MAILMIME_MECHANISM_BINARY:
845 mime->mm_data.mm_single->dt_encoding =
846 MAILMIME_MECHANISM_QUOTED_PRINTABLE;
847 mime->mm_data.mm_single->dt_encoded = 0;
848 break;
849 }
850 }
851}
852
853/*
854 mailprivacy_prepare_mime()
855
856 we assume we built ourself the message.
857*/
858
859void mailprivacy_prepare_mime(struct mailmime * mime)
860{
861 clistiter * cur;
862
863 switch (mime->mm_type) {
864 case MAILMIME_SINGLE:
865 if (mime->mm_data.mm_single != NULL) {
866 prepare_mime_single(mime);
867 }
868 break;
869
870 case MAILMIME_MULTIPLE:
871 for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ;
872 cur != NULL ; cur = clist_next(cur)) {
873 struct mailmime * child;
874
875 child = clist_content(cur);
876
877 mailprivacy_prepare_mime(child);
878 }
879 break;
880
881 case MAILMIME_MESSAGE:
882 if (mime->mm_data.mm_message.mm_msg_mime) {
883 mailprivacy_prepare_mime(mime->mm_data.mm_message.mm_msg_mime);
884 }
885 break;
886 }
887}
888
889
890char * mailprivacy_dup_imf_file(struct mailprivacy * privacy,
891 char * source_filename)
892{
893 char filename[PATH_MAX];
894 FILE * dest_f;
895 int r;
896 struct stat stat_info;
897 char * dest_filename;
898 char * mapping;
899 int fd;
900 int col;
901
902 dest_f = mailprivacy_get_tmp_file(privacy,
903 filename, sizeof(filename));
904 if (dest_f == NULL)
905 goto err;
906
907 dest_filename = strdup(filename);
908 if (dest_filename == NULL)
909 goto close_dest;
910
911 fd = open(source_filename, O_RDONLY);
912 if (fd < 0)
913 goto free_dest;
914
915 r = fstat(fd, &stat_info);
916 if (r < 0)
917 goto close_src;
918
919 mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
920 if (mapping == MAP_FAILED)
921 goto close_src;
922
923 col = 0;
924 r = mailimf_string_write(dest_f, &col, mapping, stat_info.st_size);
925 if (r != MAILIMF_NO_ERROR)
926 goto unmap;
927
928 munmap(mapping, stat_info.st_size);
929 close(fd);
930 fclose(dest_f);
931
932 return dest_filename;
933
934 unmap:
935 munmap(mapping, stat_info.st_size);
936 close_src:
937 close(fd);
938 free_dest:
939 free(dest_filename);
940 close_dest:
941 fclose(dest_f);
942 err:
943 return NULL;
944}
945
946/* TODO : better function to duplicate mime fields, currenly such inelegant */
947
948struct mailmime_fields *
949mailprivacy_mime_fields_dup(struct mailprivacy * privacy,
950 struct mailmime_fields * mime_fields)
951{
952 FILE * f;
953 char tmp_file[PATH_MAX];
954 int col;
955 int r;
956 struct mailmime_fields * dup_mime_fields;
957 int fd;
958 char * mapping;
959 struct stat stat_info;
960 struct mailimf_fields * fields;
961 size_t cur_token;
962
963 f = mailprivacy_get_tmp_file(privacy, tmp_file, sizeof(tmp_file));
964 if (f == NULL)
965 goto err;
966
967 col = 0;
968 r = mailmime_fields_write(f, &col, mime_fields);
969 if (r != MAILIMF_NO_ERROR)
970 goto unlink;
971
972 fflush(f);
973
974 fd = fileno(f);
975 if (fd == -1)
976 goto unlink;
977
978 r = fstat(fd, &stat_info);
979 if (r < 0)
980 goto unlink;
981
982 mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
983 if (mapping == MAP_FAILED)
984 goto unlink;
985
986 cur_token = 0;
987 r = mailimf_optional_fields_parse(mapping, stat_info.st_size,
988 &cur_token, &fields);
989 if (r != MAILIMF_NO_ERROR)
990 goto unmap;
991
992 r = mailmime_fields_parse(fields, &dup_mime_fields);
993 mailimf_fields_free(fields);
994 if (r != MAILIMF_NO_ERROR)
995 goto unmap;
996
997 munmap(mapping, stat_info.st_size);
998 fclose(f);
999 unlink(tmp_file);
1000
1001 return dup_mime_fields;
1002
1003 unmap:
1004 munmap(mapping, stat_info.st_size);
1005 unlink:
1006 fclose(f);
1007 unlink(tmp_file);
1008 err:
1009 return NULL;
1010}
1011
1012
1013
1014struct mailmime_parameter *
1015mailmime_parameter_dup(struct mailmime_parameter * param)
1016{
1017 char * name;
1018 char * value;
1019 struct mailmime_parameter * dup_param;
1020
1021 name = strdup(param->pa_name);
1022 if (name == NULL)
1023 goto err;
1024
1025 value = strdup(param->pa_value);
1026 if (value == NULL)
1027 goto free_name;
1028
1029 dup_param = mailmime_parameter_new(name, value);
1030 if (dup_param == NULL)
1031 goto free_value;
1032
1033 return dup_param;
1034
1035 free_value:
1036 free(value);
1037 free_name:
1038 free(name);
1039 err:
1040 return NULL;
1041}
1042
1043struct mailmime_composite_type *
1044mailmime_composite_type_dup(struct mailmime_composite_type * composite_type)
1045{
1046 struct mailmime_composite_type * dup_composite;
1047 char * token;
1048
1049 token = NULL;
1050 if (composite_type->ct_token != NULL) {
1051 token = strdup(composite_type->ct_token);
1052 if (token == NULL)
1053 goto err;
1054 }
1055
1056 dup_composite = mailmime_composite_type_new(composite_type->ct_type, token);
1057 if (dup_composite == NULL)
1058 goto free_token;
1059
1060 return dup_composite;
1061
1062 free_token:
1063 if (token != NULL)
1064 free(token);
1065 err:
1066 return NULL;
1067}
1068
1069struct mailmime_discrete_type *
1070mailmime_discrete_type_dup(struct mailmime_discrete_type * discrete_type)
1071{
1072 struct mailmime_discrete_type * dup_discrete;
1073 char * extension;
1074
1075 extension = NULL;
1076 if (discrete_type->dt_extension != NULL) {
1077 extension = strdup(discrete_type->dt_extension);
1078 if (extension == NULL)
1079 goto err;
1080 }
1081
1082 dup_discrete = mailmime_discrete_type_new(discrete_type->dt_type, extension);
1083 if (dup_discrete == NULL)
1084 goto free_extension;
1085
1086 return dup_discrete;
1087
1088 free_extension:
1089 if (extension != NULL)
1090 free(extension);
1091 err:
1092 return NULL;
1093}
1094
1095struct mailmime_type * mailmime_type_dup(struct mailmime_type * type)
1096{
1097 struct mailmime_type * dup_type;
1098 struct mailmime_discrete_type * discrete_type;
1099 struct mailmime_composite_type * composite_type;
1100
1101 discrete_type = NULL;
1102 composite_type = NULL;
1103 switch (type->tp_type) {
1104 case MAILMIME_TYPE_DISCRETE_TYPE:
1105 discrete_type =
1106 mailmime_discrete_type_dup(type->tp_data.tp_discrete_type);
1107 if (discrete_type == NULL)
1108 goto err;
1109 break;
1110
1111 composite_type =
1112 mailmime_composite_type_dup(type->tp_data.tp_composite_type);
1113 if (composite_type == NULL)
1114 goto free_discrete;
1115 }
1116
1117 dup_type = mailmime_type_new(type->tp_type, discrete_type, composite_type);
1118 if (dup_type == NULL)
1119 goto free_composite;
1120
1121 return dup_type;
1122
1123 free_composite:
1124 if (composite_type != NULL)
1125 mailmime_composite_type_free(composite_type);
1126 free_discrete:
1127 if (discrete_type != NULL)
1128 mailmime_discrete_type_free(discrete_type);
1129 err:
1130 return NULL;
1131}
1132
1133struct mailmime_content *
1134mailmime_content_dup(struct mailmime_content * content)
1135{
1136 clist * list;
1137 struct mailmime_type * type;
1138 int r;
1139 struct mailmime_content * dup_content;
1140 char * subtype;
1141
1142 type = mailmime_type_dup(content->ct_type);
1143 if (type == NULL)
1144 goto err;
1145
1146 subtype = strdup(content->ct_subtype);
1147 if (subtype == NULL)
1148 goto free_type;
1149
1150 list = clist_new();
1151 if (list == NULL)
1152 goto free_subtype;
1153
1154 if (content->ct_parameters != NULL) {
1155 clistiter * cur;
1156
1157 for(cur = clist_begin(content->ct_parameters) ;
1158 cur != NULL ; cur = clist_next(cur)) {
1159 struct mailmime_parameter * param;
1160
1161 param = mailmime_parameter_dup(clist_content(cur));
1162 if (param == NULL)
1163 goto free_list;
1164
1165 r = clist_append(list, param);
1166 if (r < 0) {
1167 mailmime_parameter_free(param);
1168 goto free_list;
1169 }
1170 }
1171 }
1172
1173 dup_content = mailmime_content_new(type, subtype, list);
1174 if (dup_content == NULL)
1175 goto free_list;
1176
1177 return dup_content;
1178
1179 free_list:
1180 clist_foreach(list, (clist_func) mailmime_parameter_free, NULL);
1181 free_subtype:
1182 free(subtype);
1183 free_type:
1184 mailmime_type_free(type);
1185 err:
1186 return NULL;
1187}
1188
1189
1190struct mailmime_parameter *
1191mailmime_param_new_with_data(char * name, char * value)
1192{
1193 char * param_name;
1194 char * param_value;
1195 struct mailmime_parameter * param;
1196
1197 param_name = strdup(name);
1198 if (param_name == NULL)
1199 goto err;
1200
1201 param_value = strdup(value);
1202 if (param_value == NULL)
1203 goto free_name;
1204
1205 param = mailmime_parameter_new(param_name, param_value);
1206 if (param == NULL)
1207 goto free_value;
1208
1209 return param;
1210
1211 free_value:
1212 free(param_value);
1213 free_name:
1214 free(param_name);
1215 err:
1216 return NULL;
1217}
1218
1219
1220int mailprivacy_fetch_decoded_to_file(struct mailprivacy * privacy,
1221 char * filename, size_t size,
1222 mailmessage * msg, struct mailmime * mime)
1223{
1224 int r;
1225 int res;
1226 FILE * f;
1227 char * content;
1228 size_t content_len;
1229 size_t written;
1230 struct mailmime_single_fields single_fields;
1231 int encoding;
1232 size_t cur_token;
1233 char * parsed_content;
1234 size_t parsed_content_len;
1235
1236 mailmime_single_fields_init(&single_fields, mime->mm_mime_fields,
1237 mime->mm_content_type);
1238 if (single_fields.fld_encoding != NULL)
1239 encoding = single_fields.fld_encoding->enc_type;
1240 else
1241 encoding = MAILMIME_MECHANISM_8BIT;
1242
1243 r = mailprivacy_msg_fetch_section(privacy, msg, mime,
1244 &content, &content_len);
1245 if (r != MAIL_NO_ERROR) {
1246 res = MAIL_ERROR_FETCH;
1247 goto err;
1248 }
1249
1250 cur_token = 0;
1251 r = mailmime_part_parse(content, content_len, &cur_token,
1252 encoding, &parsed_content, &parsed_content_len);
1253 mailprivacy_msg_fetch_result_free(privacy, msg, content);
1254 if (r != MAILIMF_NO_ERROR) {
1255 res = MAIL_ERROR_PARSE;
1256 goto err;
1257 }
1258
1259 f = mailprivacy_get_tmp_file(privacy, filename, size);
1260 if (f == NULL) {
1261 res = MAIL_ERROR_FETCH;
1262 goto free_fetch;
1263 }
1264 written = fwrite(parsed_content, 1, parsed_content_len, f);
1265 if (written != parsed_content_len) {
1266 res = MAIL_ERROR_FILE;
1267 goto close;
1268 }
1269 fclose(f);
1270
1271 mmap_string_unref(parsed_content);
1272
1273 return MAIL_NO_ERROR;
1274
1275 close:
1276 fclose(f);
1277 unlink(filename);
1278 free_fetch:
1279 mmap_string_unref(parsed_content);
1280 err:
1281 return res;
1282}
1283