Diffstat (limited to 'libetpan/src/engine/mailprivacy_tools.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | libetpan/src/engine/mailprivacy_tools.c | 1283 |
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 | |||
52 | void 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 | |||
97 | static 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 | |||
118 | FILE * 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 | |||
126 | static 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 | |||
188 | static 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 | |||
274 | static 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 | |||
366 | int 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 | ||
455 | static 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 | |||
477 | struct mailmime * | ||
478 | mailprivacy_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 | |||
593 | int 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 | |||
620 | int 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 | |||
683 | int 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 | |||
748 | int 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 | |||
796 | static 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 | |||
859 | void 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 | |||
890 | char * 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 | |||
948 | struct mailmime_fields * | ||
949 | mailprivacy_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 | |||
1014 | struct mailmime_parameter * | ||
1015 | mailmime_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 | |||
1043 | struct mailmime_composite_type * | ||
1044 | mailmime_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 | |||
1069 | struct mailmime_discrete_type * | ||
1070 | mailmime_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 | |||
1095 | struct 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 | |||
1133 | struct mailmime_content * | ||
1134 | mailmime_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 | |||
1190 | struct mailmime_parameter * | ||
1191 | mailmime_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 | |||
1220 | int 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 | |||