diff options
Diffstat (limited to 'mail/decode.c')
-rw-r--r-- | mail/decode.c | 182 |
1 files changed, 153 insertions, 29 deletions
diff --git a/mail/decode.c b/mail/decode.c index 6f20ae2cd..76d9f4e00 100644 --- a/mail/decode.c +++ b/mail/decode.c @@ -1,5 +1,5 @@ /* GNU Mailutils -- a suite of utilities for electronic mail - Copyright (C) 1999-2019 Free Software Foundation, Inc. + Copyright (C) 1999-2024 Free Software Foundation, Inc. GNU Mailutils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ /* FIXME: decode, this is temporary, until the API on how to present - mime/attachements etc is less confusing. + mime/attachments etc is less confusing. */ struct decode_closure @@ -41,7 +41,8 @@ mail_decode (int argc, char **argv) msgset_t *msgset; struct decode_closure decode_closure; - if (msgset_parse (argc, argv, MSG_NODELETED|MSG_SILENT, &msgset)) + if (msgset_parse (argc, argv, MSG_NODELETED|MSG_SILENT|MSG_ALLOWPART, + &msgset)) return 1; decode_closure.select_hdr = mu_islower (argv[0][0]); @@ -73,7 +74,7 @@ display_message (mu_message_t mesg, msgset_t *msgset, void *arg) mime_descend (&mclos, display_submessage, NULL); /* Mark enclosing message as read */ - if (mu_mailbox_get_message (mbox, msgset->msg_part[0], &mesg) == 0) + if (mu_mailbox_get_message (mbox, msgset_msgno (msgset), &mesg) == 0) util_mark_read (mesg); return 0; @@ -121,41 +122,22 @@ display_headers (mu_stream_t out, mu_message_t mesg, } } -void -format_msgset (mu_stream_t str, const msgset_t *msgset, size_t *count) -{ - int i; - mu_stream_stat_buffer stat; - - if (count) - mu_stream_set_stat (str, MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUT), - stat); - mu_stream_printf (str, "%lu", (unsigned long) msgset->msg_part[0]); - for (i = 1; i < msgset->npart; i++) - mu_stream_printf (str, "[%lu", (unsigned long) msgset->msg_part[i]); - for (i = 1; i < msgset->npart; i++) - mu_stream_printf (str, "]"); - if (count) - { - *count = stat[MU_STREAM_STAT_OUT]; - mu_stream_set_stat (str, 0, NULL); - } -} - static void display_part_header (mu_stream_t str, const msgset_t *msgset, const char *type, const char *encoding) { int size = util_screen_columns () - 3; unsigned int i; - + char *msp; + mu_stream_printf (str, "+"); for (i = 0; (int)i <= size; i++) mu_stream_printf (str, "-"); mu_stream_printf (str, "+"); mu_stream_printf (str, "\n"); - mu_stream_printf (str, "%s", _("| Message=")); - format_msgset (str, msgset, NULL); + msp = msgset_str (msgset); + mu_stream_printf (str, _("| Message=%s"), msp); + free (msp); mu_stream_printf (str, "\n"); mu_stream_printf (str, _("| Type=%s\n"), type); @@ -226,12 +208,69 @@ mime_descend (struct mime_descend_closure *closure, { mu_message_t submsg = NULL; - if (mu_message_unencapsulate (closure->message, &submsg, NULL) == 0) + switch (mu_message_unencapsulate (closure->message, &submsg, NULL)) { + case 0: subclosure.hints = MDHINT_SELECTED_HEADERS; subclosure.msgset = closure->msgset; subclosure.message = submsg; status = mime_descend (&subclosure, fun, data); + break; + + case MU_ERR_INVALID_EMAIL: + /* + * The mu_message_unencapsulate function returns this code + * if it was unable to parse the message body as a RFC822 + * message (this code is propagated from mu_stream_to_message, + * which does the actual work). + * + * If the enclosing message(part) is of message/digest type, it + * is possible that messages are packed into it without MIME + * headers. That violates RFC 1341, but such digests are + * reported to exist (re. email conversation with Karl on + * 2020-08-07, <202008070138.0771cfHn003390@freefriends.org>). + * + * Try to see whether the part has one of the normal RFC822 headers + * and if so treat it as the message. Otherwise, treat it as + * text/plain. + * + * FIXME: Do all this only if the upper-level message is of + * message/digest type. + */ + { + char *names[] = { "From", "To", "Subject" }; + mu_header_t hdr; + + if (mu_message_get_header (closure->message, &hdr) == 0 && + mu_header_sget_firstof (hdr, names, NULL, NULL) == 0) + { + mu_stream_t str; + if (mu_message_get_streamref (closure->message, &str) == 0) + { + status = mu_stream_to_message (str, &submsg); + mu_stream_unref (str); + if (status == 0) + { + mu_header_t subhdr; + if (mu_message_get_header (submsg, &subhdr) == 0) + { + mu_header_remove (subhdr, + MU_HEADER_CONTENT_TYPE, 1); + subclosure.hints = MDHINT_SELECTED_HEADERS; + subclosure.msgset = closure->msgset; + subclosure.message = submsg; + status = mime_descend (&subclosure, fun, data); + break; + } + } + } + } + } + /* FALLTHROUGH */ + + default: + /* Treat as text/plain */ + status = fun (closure, data); } } else @@ -449,3 +488,88 @@ run_metamail (const char *mailcap_cmd, mu_message_t mesg) sigaction (SIGQUIT, &savequit, NULL); sigprocmask (SIG_SETMASK, &savemask, NULL); } + +/* print_message_body(msg, out, stat) + * + * Prints the body of the message MSG to the output stream OUT. If + * the Content-Transfer-Encoding header is set, the body is decoded. + * If stat is not NULL, it must point to an array of two size_t. + * Upon return stat[0] will contain the number of bytes and stat[1] + * the number of newline characters written to the output. + */ +int +print_message_body (mu_message_t msg, mu_stream_t out, size_t *stat) +{ + int rc; + mu_header_t hdr; + mu_body_t body; + mu_stream_t d_stream; + mu_stream_t stream; + char *encoding = NULL; + mu_stream_stat_buffer sb; + + rc = mu_message_get_header (msg, &hdr); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_header", + NULL, rc); + return rc; + } + + rc = mu_message_get_body (msg, &body); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_body", + NULL, rc); + return rc; + } + + rc = mu_body_get_streamref (body, &stream); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_body_get_streamref", + NULL, rc); + return rc; + } + + util_get_hdr_value (hdr, MU_HEADER_CONTENT_TRANSFER_ENCODING, &encoding); + if (encoding == NULL || *encoding == '\0') + /* No need to filter */; + else if ((rc = mu_filter_create (&d_stream, stream, encoding, + MU_FILTER_DECODE, MU_STREAM_READ)) == 0) + { + mu_stream_unref (stream); + stream = d_stream; + } + else + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_body", + encoding, rc); + /* FIXME: continue anyway? */ + } + + if (stat) + { + mu_stream_set_stat (stream, + MU_STREAM_STAT_MASK (MU_STREAM_STAT_IN) | + MU_STREAM_STAT_MASK (MU_STREAM_STAT_INLN), + sb); + } + rc = mu_stream_copy (out, stream, 0, NULL); + + mu_stream_destroy (&stream); + free (encoding); + + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_copy", + encoding, rc); + } + else if (stat) + { + stat[0] = sb[MU_STREAM_STAT_IN]; + stat[1] = sb[MU_STREAM_STAT_INLN]; + } + + return rc; +} |