1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999-2021 Free Software Foundation, Inc.
3
4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Mailutils is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18 #include <stdlib.h>
19 #include <mailutils/mailutils.h>
20 #include <mailutils/sys/envelope.h>
21 #include <muaux.h>
22 #include <sysexits.h>
23 #include <sys/time.h>
24 #include <sys/resource.h>
25
26 int truncate_opt;
27 int from_filter;
28 int recode_charset;
29 char *charset;
30 int fd_err;
31
32 static struct mu_option decodemail_options[] =
33 {
34 { "truncate", 't', NULL, MU_OPTION_DEFAULT,
35 N_("truncate the output mailbox, if it exists"),
36 mu_c_bool, &truncate_opt },
37 { "charset", 'c', N_("CHARSET"), MU_OPTION_DEFAULT,
38 N_("recode output to this charset"),
39 mu_c_string, &charset },
40 { "recode", 'R', NULL, MU_OPTION_DEFAULT,
41 N_("recode text parts to the current charset"),
42 mu_c_bool, &recode_charset },
43 MU_OPTION_END
44 }, *options[] = { decodemail_options, NULL };
45
46 struct mu_cli_setup cli = {
47 .optv = options,
48 .prog_doc = N_("GNU decodemail -- decode messages."),
49 .prog_args = N_("[INBOX] [OUTBOX]")
50 };
51
52 static char *decodemail_capa[] = {
53 "debug",
54 "mailbox",
55 "locking",
56 "mime",
57 NULL
58 };
59
60 char *charset;
61
62 static void
define_charset(void)63 define_charset (void)
64 {
65 struct mu_lc_all lc_all = { .flags = 0 };
66 char *ep = getenv ("LC_ALL");
67 if (!ep)
68 ep = getenv ("LANG");
69
70 if (ep && mu_parse_lc_all (ep, &lc_all, MU_LC_CSET) == 0)
71 {
72 charset = mu_strdup (lc_all.charset);
73 mu_lc_all_free (&lc_all);
74 }
75 else
76 charset = mu_strdup ("us-ascii");
77 }
78
79 static mu_message_t message_decode (mu_message_t, mu_coord_t *, size_t);
80
81 static void message_store_mbox (mu_message_t, mu_mailbox_t);
82 static void message_store_stdout (mu_message_t, mu_mailbox_t);
83
84 static void
enable_log_prefix(int on)85 enable_log_prefix (int on)
86 {
87 int mode;
88
89 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
90 MU_IOCTL_LOGSTREAM_GET_MODE, &mode);
91 if (on)
92 mode |= MU_LOGMODE_PREFIX;
93 else
94 mode &= ~MU_LOGMODE_PREFIX;
95
96 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
97 MU_IOCTL_LOGSTREAM_SET_MODE, &mode);
98 }
99
100 static void
set_log_prefix(mu_coord_t crd,size_t dim)101 set_log_prefix (mu_coord_t crd, size_t dim)
102 {
103 char *prefix = mu_coord_part_string (crd, dim);
104 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
105 MU_IOCTL_LOGSTREAM_SET_PREFIX, prefix);
106 free (prefix);
107 }
108
109 void
abend(int code)110 abend (int code)
111 {
112 if (fd_err)
113 {
114 struct rlimit rlim;
115
116 getrlimit (RLIMIT_NOFILE, &rlim);
117 rlim.rlim_cur += fd_err;
118 mu_error (_("at least %lu file descriptors are needed to process this message"),
119 (unsigned long) rlim.rlim_cur);
120 }
121 exit (code);
122 }
123
124 static void
mailbox_truncate(mu_mailbox_t mbox)125 mailbox_truncate (mu_mailbox_t mbox)
126 {
127 int rc;
128 mu_iterator_t itr;
129
130 mu_mailbox_get_iterator (mbox, &itr);
131 for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
132 mu_iterator_next (itr))
133 {
134 mu_message_t m;
135 mu_attribute_t a;
136
137 if ((rc = mu_iterator_current (itr, (void **)&m)) != 0)
138 {
139 mu_error (_("can't get current message while truncating the mailbox: %s"),
140 mu_strerror (rc));
141 exit (EX_OSERR);
142 }
143 mu_message_get_attribute (m, &a);
144 mu_attribute_set_deleted (a);
145 }
146 mu_iterator_destroy (&itr);
147 if ((rc = mu_mailbox_expunge (mbox)) != 0)
148 {
149 mu_error (_("error expunging destination mailbox: %s"),
150 mu_strerror (rc));
151 exit (EX_OSERR);
152 }
153 }
154
155 static void
output_mbox_cleanup(void * arg)156 output_mbox_cleanup (void *arg)
157 {
158 if (arg)
159 {
160 mu_mailbox_t mbox = arg;
161 mu_mailbox_unlock (mbox);
162 }
163 }
164
165 int
main(int argc,char ** argv)166 main (int argc, char **argv)
167 {
168 int rc;
169 mu_mailbox_t imbox, ombox = NULL;
170 char *imbox_name = NULL, *ombox_name = NULL;
171 void (*message_store) (mu_message_t, mu_mailbox_t);
172 mu_iterator_t itr;
173 unsigned long i;
174 int err = 0;
175 mu_coord_t crd;
176
177 /* Native Language Support */
178 MU_APP_INIT_NLS ();
179
180 /* register the formats. */
181 mu_register_all_mbox_formats ();
182 mu_register_extra_formats ();
183 mu_auth_register_module (&mu_auth_tls_module);
184 mu_cli_capa_register (&mu_cli_capa_mime);
185
186 mu_cli (argc, argv, &cli, decodemail_capa, NULL, &argc, &argv);
187
188 switch (argc)
189 {
190 case 2:
191 ombox_name = argv[1];
192 case 1:
193 imbox_name = argv[0];
194 break;
195 case 0:
196 break;
197 default:
198 mu_error (_("too many arguments; try %s --help for help"),
199 mu_program_name);
200 exit (EX_USAGE);
201 }
202
203 if (!charset && recode_charset)
204 define_charset ();
205
206 /* Open input mailbox */
207 rc = mu_mailbox_create_default (&imbox, imbox_name);
208 if (rc != 0)
209 {
210 if (imbox_name)
211 mu_error (_("could not create mailbox `%s': %s"),
212 imbox_name,
213 mu_strerror (rc));
214 else
215 mu_error (_("could not create default mailbox: %s"),
216 mu_strerror (rc));
217 abend (EX_OSERR);
218 }
219
220 rc = mu_mailbox_open (imbox, MU_STREAM_READ);
221 if (rc)
222 {
223 mu_url_t url = NULL;
224
225 mu_mailbox_get_url (imbox, &url);
226 mu_error (_("could not open input mailbox `%s': %s"),
227 mu_url_to_string (url), mu_strerror (rc));
228 abend (EX_NOINPUT);
229 }
230
231 /* Create output mailbox */
232 if (ombox_name)
233 {
234 mu_property_t prop;
235 const char *type;
236
237 rc = mu_mailbox_create_default (&ombox, ombox_name);
238 if (rc != 0)
239 {
240 mu_error (_("could not create output mailbox `%s': %s"),
241 ombox_name,
242 mu_strerror (rc));
243 abend (EX_OSERR);
244 }
245
246 mu_onexit (output_mbox_cleanup, ombox);
247
248 if (truncate_opt)
249 {
250 rc = mu_mailbox_open (ombox, MU_STREAM_RDWR);
251 switch (rc)
252 {
253 case 0:
254 mailbox_truncate (ombox);
255 mu_mailbox_close (ombox);
256 break;
257
258 case ENOENT:
259 case MU_ERR_NOENT:
260 break;
261
262 default:
263 mu_error (_("could not open mailbox `%s': %s"),
264 ombox_name, mu_strerror (rc));
265 abend (EX_OSERR);
266 }
267 }
268
269 rc = mu_mailbox_open (ombox, MU_STREAM_APPEND|MU_STREAM_CREAT);
270 if (rc)
271 {
272 mu_error (_("could not open mailbox `%s': %s"),
273 ombox_name, mu_strerror (rc));
274 abend (EX_CANTCREAT);
275 }
276
277 if (mu_mailbox_get_property (ombox, &prop) == 0 &&
278 mu_property_sget_value (prop, "TYPE", &type) == 0 &&
279 strcmp (type, "MBOX") == 0)
280 from_filter = 1;
281
282 message_store = message_store_mbox;
283 }
284 else
285 {
286 message_store = message_store_stdout;
287 from_filter = 1;
288 }
289
290 rc = mu_mailbox_get_iterator (imbox, &itr);
291 if (rc)
292 {
293 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_iterator", NULL, rc);
294 abend (EX_SOFTWARE);
295 }
296
297 rc = mu_coord_alloc (&crd, 1);
298 if (rc)
299 mu_alloc_die ();
300
301 enable_log_prefix (1);
302 for (mu_iterator_first (itr), i = 1; !mu_iterator_is_done (itr);
303 mu_iterator_next (itr), i++)
304 {
305 mu_message_t msg, newmsg;
306
307 rc = mu_iterator_current (itr, (void **)&msg);
308 if (rc)
309 {
310 mu_error (_("cannot read message %lu: %s"),
311 i, mu_strerror (rc));
312 err = 1;
313 continue;
314 }
315 crd[1] = i;
316 fd_err = 0;
317 newmsg = message_decode (msg, &crd, 1);
318 message_store (newmsg, ombox);
319 mu_message_unref (newmsg);
320 mu_message_unref (msg);
321 }
322 enable_log_prefix (0);
323
324 mu_mailbox_destroy (&imbox);
325 mu_mailbox_sync (ombox);
326 mu_mailbox_destroy (&ombox);
327
328 if (err)
329 abend (EX_UNAVAILABLE);
330 exit (EX_OK);
331 }
332
333 static void
message_store_mbox(mu_message_t msg,mu_mailbox_t mbx)334 message_store_mbox (mu_message_t msg, mu_mailbox_t mbx)
335 {
336 int rc = mu_mailbox_append_message (mbx, msg);
337 if (rc)
338 {
339 mu_error (_("cannot store message: %s"), mu_strerror (rc));
340 switch (rc)
341 {
342 case MU_ERR_INVALID_EMAIL:
343 case MU_ERR_EMPTY_ADDRESS:
344 break;
345
346 case EMFILE:
347 fd_err++;
348 /* FALLTHROUGH */
349
350 default:
351 abend (EX_IOERR);
352 }
353 }
354 }
355
356 static void
env_print(mu_message_t msg)357 env_print (mu_message_t msg)
358 {
359 mu_envelope_t env;
360 char const *buf;
361 size_t len;
362
363 mu_message_get_envelope (msg, &env);
364 if (mu_envelope_sget_sender (env, &buf))
365 buf = "UNKNOWN";
366 mu_printf ("From %s ", buf);
367
368 if (mu_envelope_sget_date (env, &buf))
369 {
370 char datebuf[MU_DATETIME_FROM_LENGTH+1];
371 time_t t;
372 struct tm *tm;
373
374 t = time (NULL);
375 tm = gmtime (&t);
376 mu_strftime (datebuf, sizeof datebuf, MU_DATETIME_FROM, tm);
377 buf = datebuf;
378 }
379
380 mu_printf ("%s", buf);
381 len = strlen (buf);
382 if (len > 1 && buf[len-1] != '\n')
383 mu_printf ("\n");
384 }
385
386 static void
message_store_stdout(mu_message_t msg,mu_mailbox_t mbx)387 message_store_stdout (mu_message_t msg, mu_mailbox_t mbx)
388 {
389 mu_stream_t str;
390
391 env_print (msg);
392 mu_message_get_streamref (msg, &str);
393 mu_stream_copy_nl (mu_strout, str, 0, NULL);
394 mu_stream_destroy (&str);
395 mu_printf ("\n");
396 }
397
398 static inline int
is_address_header(char const * name)399 is_address_header (char const *name)
400 {
401 return !mu_c_strcasecmp (name, MU_HEADER_FROM) ||
402 !mu_c_strcasecmp (name, MU_HEADER_TO) ||
403 !mu_c_strcasecmp (name, MU_HEADER_CC) ||
404 !mu_c_strcasecmp (name, MU_HEADER_BCC);
405 }
406
407 static int
qstring_needed(char const * s)408 qstring_needed (char const *s)
409 {
410 for (; *s; s++)
411 {
412 if (mu_isascii (*s) && !mu_istspec (*s))
413 continue;
414 return 1;
415 }
416 return 0;
417 }
418
419 static void
qstring_format(mu_stream_t stream,char const * s)420 qstring_format (mu_stream_t stream, char const *s)
421 {
422 if (!s)
423 return;
424 if (qstring_needed (s))
425 {
426 char const *cp;
427
428 mu_stream_write (stream, "\"", 1, NULL);
429 while (*(cp = mu_str_skip_cset_comp (s, "\\\"")))
430 {
431 mu_stream_write (stream, s, cp - s, NULL);
432 mu_stream_write (stream, "\\", 1, NULL);
433 mu_stream_write (stream, cp, 1, NULL);
434 s = cp + 1;
435 }
436 if (*s)
437 mu_stream_write (stream, s, strlen (s), NULL);
438 mu_stream_write (stream, "\"", 1, NULL);
439 }
440 else
441 mu_stream_write (stream, s, strlen (s), NULL);
442 }
443
444 static int
address_decode(char const * name,char const * value,char const * charset,mu_header_t newhdr)445 address_decode (char const *name, char const *value, char const *charset,
446 mu_header_t newhdr)
447 {
448 int rc;
449 mu_address_t addr;
450 mu_stream_t mstr;
451 mu_transport_t trans[2];
452
453 rc = mu_memory_stream_create (&mstr, MU_STREAM_RDWR);
454 if (rc)
455 return rc;
456
457 rc = mu_address_create (&addr, value);
458 if (rc == 0)
459 {
460 mu_address_t cur;
461 for (cur = addr; cur; cur = cur->next)
462 {
463 char *s;
464
465 rc = mu_rfc2047_decode (charset, cur->personal, &s);
466 if (rc == 0)
467 {
468 qstring_format (mstr, s);
469 free (s);
470 }
471 else
472 qstring_format (mstr, cur->personal);
473 mu_stream_printf (mstr, " <%s>", cur->email);
474 if (cur->next)
475 mu_stream_write (mstr, ", ", 2, NULL);
476 }
477 mu_stream_write (mstr, "", 1, NULL);
478 rc = mu_stream_err (mstr);
479 if (rc == 0)
480 {
481 mu_stream_ioctl (mstr, MU_IOCTL_TRANSPORT,
482 MU_IOCTL_OP_GET,
483 trans);
484 mu_header_append (newhdr, name, (char*)trans[0]);
485 }
486 mu_stream_destroy (&mstr);
487 mu_address_destroy (&addr);
488 }
489 return rc;
490 }
491
492 /*
493 * Decode a single message or message part.
494 *
495 * Arguments:
496 * msg - Message or message part.
497 * crd - Pointer to mu_coord_t object that keeps its location.
498 * dim - Number of significant positions in crd. If it is 1,
499 * msg is the message. If it is greater than 1, msg is
500 * part of a MIME message.
501 *
502 * The function can reallocate crd to increase its actual dimension.
503 * It can modify the coordinate positions starting from dim+1 (inclusive).
504 */
505 static mu_message_t
message_decode_nomime(mu_message_t msg)506 message_decode_nomime (mu_message_t msg)
507 {
508 mu_message_t newmsg;
509 int rc;
510 mu_stream_t str;
511 mu_body_t body;
512 mu_stream_t bstr;
513 mu_header_t hdr, newhdr;
514 mu_iterator_t itr;
515 size_t i;
516 char *content_type = NULL;
517 mu_stream_stat_buffer stat;
518
519 rc = message_body_stream (msg, from_filter, charset, &str);
520 if (rc)
521 return NULL;
522
523 rc = mu_message_create (&newmsg, NULL);
524 if (rc)
525 {
526 mu_diag_funcall (MU_DIAG_ERROR, "mu_message_create", NULL, rc);
527 abend (EX_OSERR);
528 }
529
530 rc = mu_message_get_body (newmsg, &body);
531 if (rc)
532 {
533 mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_body", NULL, rc);
534 goto end;
535 }
536
537 rc = mu_body_get_streamref (body, &bstr);
538 if (rc)
539 {
540 if (rc == EMFILE)
541 fd_err++;
542 mu_diag_funcall (MU_DIAG_ERROR, "mu_body_get_streamref", NULL, rc);
543 goto end;
544 }
545
546 mu_stream_set_stat (bstr,
547 MU_STREAM_STAT_MASK (MU_STREAM_STAT_IN8BIT),
548 stat);
549 rc = mu_stream_copy (bstr, str, 0, NULL);
550 if (rc)
551 {
552 mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_copy", NULL, rc);
553 if (mu_stream_err (bstr))
554 {
555 abend (EX_IOERR);
556 }
557 else
558 {
559 mu_stream_printf (bstr,
560 "\n[decodemail: content decoding failed: %s]\n",
561 mu_strerror (rc));
562 }
563 }
564 mu_stream_unref (bstr);
565 mu_stream_unref (str);
566
567 rc = mu_message_get_header (msg, &hdr);
568 if (rc)
569 {
570 mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_header", "msg", rc);
571 goto end;
572 }
573
574 rc = mu_message_get_header (newmsg, &newhdr);
575 if (rc)
576 {
577 mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_header", "newmsg", rc);
578 goto end;
579 }
580
581 rc = mu_header_get_iterator (hdr, &itr);
582 if (rc)
583 {
584 mu_diag_funcall (MU_DIAG_ERROR, "mu_header_get_iterator", NULL, rc);
585 goto end;
586 }
587
588 for (mu_iterator_first (itr), i = 1; !mu_iterator_is_done (itr);
589 mu_iterator_next (itr), i++)
590 {
591 const char *name;
592 const char *value;
593 char *s;
594
595 rc = mu_iterator_current_kv (itr, (void const **) &name,
596 (void**)&value);
597 if (rc)
598 {
599 mu_diag_funcall (MU_DIAG_ERROR, "mu_iterator_current_kv", NULL, rc);
600 continue;
601 }
602
603 if (!mu_c_strcasecmp (name, MU_HEADER_CONTENT_TYPE))
604 {
605 if (charset)
606 {
607 mu_content_type_t ct;
608 struct mu_mime_param **pparam;
609 char *vc = mu_strdup (value);
610 size_t len;
611 mu_string_unfold (vc, &len);
612 rc = mu_content_type_parse_ext (vc, NULL,
613 MU_CONTENT_TYPE_RELAXED |
614 MU_CONTENT_TYPE_PARAM,
615 &ct);
616 if (rc)
617 {
618 mu_diag_funcall (MU_DIAG_ERROR,
619 "mu_content_type_parse_ext",
620 vc, rc);
621 free (vc);
622 continue;
623 }
624 free (vc);
625 rc = mu_assoc_install_ref (ct->param, "charset", &pparam);
626 switch (rc)
627 {
628 case 0:
629 *pparam = mu_zalloc (sizeof **pparam);
630 break;
631
632 case MU_ERR_EXISTS:
633 free ((*pparam)->value);
634 break;
635
636 default:
637 mu_diag_funcall (MU_DIAG_ERROR,
638 "mu_assoc_install_ref",
639 NULL, rc);
640 abend (EX_IOERR);
641 }
642 (*pparam)->value = mu_strdup (charset);
643 mu_content_type_format (ct, &content_type);
644 mu_content_type_destroy (&ct);
645 continue;
646 }
647 }
648 else if (!mu_c_strcasecmp (name, MU_HEADER_CONTENT_TRANSFER_ENCODING))
649 continue;
650 else if (is_address_header (name))
651 {
652 if (address_decode (name, value, charset, newhdr))
653 mu_header_append (newhdr, name, value);
654 continue;
655 }
656
657 rc = mu_rfc2047_decode (charset, value, &s);
658 if (rc == 0)
659 {
660 mu_header_append (newhdr, name, s);
661 free (s);
662 }
663 else
664 mu_header_append (newhdr, name, value);
665 }
666 mu_iterator_destroy (&itr);
667 rc = 0;
668
669 mu_header_set_value (newhdr,
670 MU_HEADER_CONTENT_TRANSFER_ENCODING,
671 stat[MU_STREAM_STAT_IN8BIT] ? "8bit" : "7bit",
672 1);
673 if (charset)
674 {
675 if (!content_type)
676 mu_asprintf (&content_type, "text/plain; charset=%s", charset);
677 mu_header_set_value (newhdr,
678 MU_HEADER_CONTENT_TYPE,
679 content_type,
680 1);
681 free (content_type);
682 }
683 end:
684 if (rc)
685 {
686 mu_message_unref (newmsg);
687 newmsg = NULL;
688 }
689 return newmsg;
690 }
691
692 static mu_message_t
message_decode_mime(mu_message_t msg,mu_coord_t * crd,size_t dim)693 message_decode_mime (mu_message_t msg, mu_coord_t *crd, size_t dim)
694 {
695 int rc;
696 mu_message_t newmsg;
697 size_t nparts, i;
698 mu_mime_t mime;
699 mu_header_t hdr, newhdr;
700 mu_iterator_t itr;
701 char *s;
702 mu_content_type_t ct;
703
704 /* FIXME: The following could be simplified if we could obtain
705 a mime object from the message */
706 rc = mu_message_get_header (msg, &hdr);
707 if (rc)
708 {
709 mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_header", "msg", rc);
710 return NULL;
711 }
712
713 rc = mu_header_aget_value_unfold (hdr, MU_HEADER_CONTENT_TYPE, &s);
714 if (rc)
715 {
716 mu_diag_funcall (MU_DIAG_ERROR, "mu_header_aget_value_unfold",
717 MU_HEADER_CONTENT_TYPE, rc);
718 return NULL;
719 }
720
721 rc = mu_content_type_parse_ext (s, NULL,
722 MU_CONTENT_TYPE_RELAXED |
723 MU_CONTENT_TYPE_PARAM, &ct);
724 if (rc)
725 {
726 mu_diag_funcall (MU_DIAG_ERROR, "mu_content_type_parse_ext", s, rc);
727 free (s);
728 return NULL;
729 }
730 free (s);
731
732 if (!ct->subtype)
733 {
734 mu_content_type_destroy (&ct);
735 return NULL;
736 }
737
738 rc = mu_mime_create_multipart (&mime, ct->subtype, ct->param);
739 mu_content_type_destroy (&ct);
740 if (rc)
741 {
742 mu_diag_funcall (MU_DIAG_ERROR, "mu_mime_create_multipart", NULL, rc);
743 return NULL;
744 }
745
746 rc = mu_message_get_num_parts (msg, &nparts);
747 if (rc)
748 {
749 mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_num_parts",
750 NULL, rc);
751 return NULL;
752 }
753
754 ++dim;
755 if (dim > mu_coord_length (*crd))
756 {
757 rc = mu_coord_realloc (crd, dim);
758 if (rc)
759 mu_alloc_die ();
760 }
761
762 for (i = 1; i <= nparts; i++)
763 {
764 mu_message_t msgpart, msgdec;
765
766 (*crd)[dim] = i;
767 rc = mu_message_get_part (msg, i, &msgpart);
768 if (rc)
769 {
770 mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_part",
771 NULL, rc);
772 mu_mime_unref (mime);
773 return NULL;
774 }
775 msgdec = message_decode (msgpart, crd, dim);
776 rc = mu_mime_add_part (mime, msgdec);
777 mu_message_unref (msgdec);
778 if (rc)
779 {
780 mu_diag_funcall (MU_DIAG_ERROR, "mu_mime_add_part", NULL, rc);
781 mu_mime_unref (mime);
782 return NULL;
783 }
784 }
785
786 --dim;
787
788 rc = mu_mime_to_message (mime, &newmsg);
789 mu_mime_unref (mime);
790 if (rc)
791 {
792 mu_diag_funcall (MU_DIAG_ERROR, "mu_mime_to_message", NULL, rc);
793 return NULL;
794 }
795
796 /* Copy headers */
797 rc = mu_message_get_header (newmsg, &newhdr);
798 if (rc)
799 {
800 mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_header", "newmsg", rc);
801 goto end;
802 }
803
804 rc = mu_header_get_iterator (hdr, &itr);
805 if (rc)
806 {
807 mu_diag_funcall (MU_DIAG_ERROR, "mu_header_get_iterator", NULL, rc);
808 goto end;
809 }
810
811 for (mu_iterator_first (itr), i = 1; !mu_iterator_is_done (itr);
812 mu_iterator_next (itr), i++)
813 {
814 const char *name;
815 const char *value;
816 char *s;
817
818 rc = mu_iterator_current_kv (itr, (void const **) &name,
819 (void**)&value);
820 if (rc)
821 {
822 mu_diag_funcall (MU_DIAG_ERROR, "mu_iterator_current_kv", NULL, rc);
823 continue;
824 }
825
826 if (mu_c_strcasecmp (name, MU_HEADER_MIME_VERSION) == 0 ||
827 mu_c_strcasecmp (name, MU_HEADER_CONTENT_TYPE) == 0)
828 continue;
829 else if (is_address_header (name))
830 {
831 if (address_decode (name, value, charset, newhdr))
832 mu_header_append (newhdr, name, value);
833 continue;
834 }
835 rc = mu_rfc2047_decode (charset, value, &s);
836 if (rc == 0)
837 {
838 mu_header_append (newhdr, name, s);
839 free (s);
840 }
841 else
842 mu_header_append (newhdr, name, value);
843 }
844 mu_iterator_destroy (&itr);
845 rc = 0;
846
847 end:
848 if (rc)
849 {
850 mu_message_unref (newmsg);
851 newmsg = NULL;
852 }
853 return newmsg;
854 }
855
856 static mu_message_t
message_decode(mu_message_t msg,mu_coord_t * crd,size_t dim)857 message_decode (mu_message_t msg, mu_coord_t *crd, size_t dim)
858 {
859 mu_message_t newmsg;
860 int ismime = 0;
861 int rc;
862
863 set_log_prefix (*crd, dim);
864
865 rc = mu_message_is_multipart (msg, &ismime);
866 if (rc)
867 {
868 mu_diag_funcall (MU_DIAG_ERROR, "mu_message_is_multipart", NULL, rc);
869 newmsg = NULL;
870 }
871 else if (!ismime)
872 {
873 newmsg = message_decode_nomime (msg);
874 }
875 else
876 {
877 newmsg = message_decode_mime (msg, crd, dim);
878 }
879
880 if (!newmsg)
881 {
882 mu_message_ref (msg);
883 return msg;
884 }
885
886 set_log_prefix (*crd, dim);
887
888 if (dim == 1)
889 {
890 /* Copy envelope */
891 mu_envelope_t env, newenv;
892
893 rc = mu_message_get_envelope (msg, &env);
894 if (rc == 0)
895 {
896 char *sender = NULL, *date = NULL;
897 if ((rc = mu_envelope_aget_sender (env, &sender)) != 0)
898 {
899 mu_diag_funcall (MU_DIAG_ERROR, "mu_envelope_aget_sender",
900 NULL, rc);
901 }
902 else if ((rc = mu_envelope_aget_date (env, &date)) != 0)
903 {
904 free (sender);
905 sender = NULL;
906 mu_diag_funcall (MU_DIAG_ERROR, "mu_envelope_aget_date",
907 NULL, rc);
908 }
909
910 if (sender)
911 {
912 if ((rc = mu_envelope_create (&newenv, newmsg)) == 0)
913 {
914 newenv->sender = sender;
915 newenv->date = date;
916 mu_message_set_envelope (newmsg, newenv,
917 mu_message_get_owner (newmsg));
918 }
919 else
920 {
921 free (sender);
922 free (date);
923 mu_diag_funcall (MU_DIAG_ERROR, "mu_envelope_create",
924 NULL, rc);
925 }
926 }
927 }
928 else
929 mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_envelope",
930 NULL, rc);
931 }
932
933 return newmsg;
934 }
935
936