From a41a550eab83ccd5922b08823e95e8959cee1859 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Thu, 2 Nov 2017 12:04:07 +0100 Subject: [PATCH] Bug 789648 - Problem viewing .eml attachment --- src/em-format/e-mail-parser-application-mbox.c | 94 ++++++++++++++++---------- src/em-format/e-mail-parser-multipart-mixed.c | 64 ++++++++++++++++-- src/em-format/e-mail-parser.c | 76 ++++++++++++++++----- src/em-format/e-mail-parser.h | 5 ++ 4 files changed, 182 insertions(+), 57 deletions(-) diff --git a/src/em-format/e-mail-parser-application-mbox.c b/src/em-format/e-mail-parser-application-mbox.c index c4e9ecd53e..38dc1ee781 100644 --- a/src/em-format/e-mail-parser-application-mbox.c +++ b/src/em-format/e-mail-parser-application-mbox.c @@ -40,6 +40,47 @@ static const gchar *parser_mime_types[] = { NULL }; +static void +empe_app_mbox_add_message (EMailParser *parser, + CamelMimeMessage *message, + gint nth_message, + GString *part_id, + GCancellable *cancellable, + GQueue *out_mail_parts) +{ + GQueue work_queue = G_QUEUE_INIT; + CamelMimePart *opart; + gint old_len; + + old_len = part_id->len; + + g_string_append_printf (part_id, ".mbox.%d", nth_message); + + opart = camel_mime_part_new (); + camel_medium_set_content (CAMEL_MEDIUM (opart), CAMEL_DATA_WRAPPER (message)); + camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (opart), "message/rfc822"); + + e_mail_parser_parse_part_as ( + parser, opart, part_id, "message/rfc822", + cancellable, &work_queue); + + /* Wrap every message as attachment */ + e_mail_parser_wrap_as_attachment (parser, opart, part_id, &work_queue); + + /* Inline all messages in mbox */ + if (!g_queue_is_empty (&work_queue)) { + EMailPart *pp = g_queue_peek_head (&work_queue); + + pp->force_inline = TRUE; + } + + e_queue_transfer (&work_queue, out_mail_parts); + + g_string_truncate (part_id, old_len); + + g_object_unref (opart); +} + static gboolean empe_app_mbox_parse (EMailParserExtension *extension, EMailParser *parser, @@ -51,7 +92,6 @@ empe_app_mbox_parse (EMailParserExtension *extension, CamelMimeParser *mime_parser; CamelStream *mem_stream; CamelMimeParserState state; - gint old_len; gint messages; GError *error = NULL; @@ -90,67 +130,51 @@ empe_app_mbox_parse (EMailParserExtension *extension, return TRUE; } - g_object_unref (mem_stream); - - old_len = part_id->len; - /* Extract messages from the mbox. */ messages = 0; state = camel_mime_parser_step (mime_parser, NULL, NULL); while (state == CAMEL_MIME_PARSER_STATE_FROM) { - GQueue work_queue = G_QUEUE_INIT; CamelMimeMessage *message; - CamelMimePart *opart; message = camel_mime_message_new (); - opart = CAMEL_MIME_PART (message); if (!camel_mime_part_construct_from_parser_sync ( - opart, mime_parser, NULL, NULL)) { + CAMEL_MIME_PART (message), mime_parser, NULL, NULL)) { g_object_unref (message); break; } - g_string_append_printf (part_id, ".mbox.%d", messages); + empe_app_mbox_add_message (parser, message, messages, part_id, cancellable, out_mail_parts); + messages++; - opart = camel_mime_part_new (); - camel_medium_set_content (CAMEL_MEDIUM (opart), CAMEL_DATA_WRAPPER (message)); - camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (opart), "message/rfc822"); + g_object_unref (message); - e_mail_parser_parse_part_as ( - parser, opart, part_id, "message/rfc822", - cancellable, &work_queue); + /* Skip past CAMEL_MIME_PARSER_STATE_FROM_END. */ + camel_mime_parser_step (mime_parser, NULL, NULL); - /* Wrap every message as attachment */ - e_mail_parser_wrap_as_attachment ( - parser, opart, part_id, &work_queue); + state = camel_mime_parser_step (mime_parser, NULL, NULL); + } - /* Inline all messages in mbox */ - if (!g_queue_is_empty (&work_queue)) { - EMailPart *p = g_queue_peek_head (&work_queue); + if (!messages) { + CamelMimeMessage *message; - p->force_inline = TRUE; - } + g_seekable_seek (G_SEEKABLE (mem_stream), 0, G_SEEK_SET, cancellable, NULL); - e_queue_transfer (&work_queue, out_mail_parts); + message = camel_mime_message_new (); - g_string_truncate (part_id, old_len); + if (camel_data_wrapper_construct_from_stream_sync (CAMEL_DATA_WRAPPER (message), mem_stream, NULL, NULL)) { + empe_app_mbox_add_message (parser, message, messages, part_id, cancellable, out_mail_parts); + messages++; + } g_object_unref (message); - g_object_unref (opart); - - /* Skip past CAMEL_MIME_PARSER_STATE_FROM_END. */ - camel_mime_parser_step (mime_parser, NULL, NULL); - - state = camel_mime_parser_step (mime_parser, NULL, NULL); - - messages++; } g_object_unref (mime_parser); + g_object_unref (mem_stream); - return TRUE; + return messages > 0; } static void diff --git a/src/em-format/e-mail-parser-multipart-mixed.c b/src/em-format/e-mail-parser-multipart-mixed.c index cc6a02306e..6d3aefea17 100644 --- a/src/em-format/e-mail-parser-multipart-mixed.c +++ b/src/em-format/e-mail-parser-multipart-mixed.c @@ -140,12 +140,65 @@ empe_mp_mixed_parse (EMailParserExtension *extension, g_string_append_printf (part_id, ".mixed.%d", i); - handled = e_mail_parser_parse_part ( - parser, subpart, part_id, cancellable, &work_queue); + handled = FALSE; + ct = camel_mime_part_get_content_type (subpart); + if (ct) + ct = camel_content_type_ref (ct); + + if (!e_mail_parser_get_parsers_for_part (parser, subpart)) { + const gchar *snoop_type; + CamelContentType *snoop_ct = NULL; + + snoop_type = e_mail_part_snoop_type (subpart); + if (snoop_type) + snoop_ct = camel_content_type_decode (snoop_type); + + if (snoop_ct && snoop_ct->type && snoop_ct->subtype && ( + !ct || g_ascii_strcasecmp (snoop_ct->type, ct->type) != 0 || + g_ascii_strcasecmp (snoop_ct->subtype, ct->subtype) != 0)) { + CamelStream *mem_stream; + + mem_stream = camel_stream_mem_new (); + if (camel_data_wrapper_decode_to_stream_sync ( + camel_medium_get_content (CAMEL_MEDIUM (subpart)), + mem_stream, cancellable, NULL)) { + CamelMimePart *opart; + CamelDataWrapper *dw; + + g_seekable_seek (G_SEEKABLE (mem_stream), 0, G_SEEK_SET, cancellable, NULL); + + opart = camel_mime_part_new (); + + dw = camel_data_wrapper_new (); + camel_data_wrapper_set_mime_type (dw, snoop_type); + if (camel_data_wrapper_construct_from_stream_sync (dw, mem_stream, cancellable, NULL)) { + camel_medium_set_content (CAMEL_MEDIUM (opart), dw); + camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (opart), snoop_type); + + handled = e_mail_parser_parse_part (parser, opart, part_id, cancellable, &work_queue); + if (handled) { + camel_content_type_unref (ct); + ct = camel_content_type_ref (snoop_ct); + } + } - mail_part = g_queue_peek_head (&work_queue); + g_object_unref (opart); + g_object_unref (dw); + } - ct = camel_mime_part_get_content_type (subpart); + g_object_unref (mem_stream); + } + + if (snoop_ct) + camel_content_type_unref (snoop_ct); + } + + if (!handled) { + handled = e_mail_parser_parse_part ( + parser, subpart, part_id, cancellable, &work_queue); + } + + mail_part = g_queue_peek_head (&work_queue); /* Display parts with CID as attachments * (unless they already are attachments). @@ -178,6 +231,9 @@ empe_mp_mixed_parse (EMailParserExtension *extension, e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); + + if (ct) + camel_content_type_unref (ct); } return TRUE; diff --git a/src/em-format/e-mail-parser.c b/src/em-format/e-mail-parser.c index 1cbbe3243f..a9a08498b7 100644 --- a/src/em-format/e-mail-parser.c +++ b/src/em-format/e-mail-parser.c @@ -494,6 +494,63 @@ e_mail_parser_parse_finish (EMailParser *parser, return g_object_ref (part_list); } +GQueue * +e_mail_parser_get_parsers_for_part (EMailParser *parser, + CamelMimePart *part) +{ + CamelContentType *ct; + gchar *mime_type; + GQueue *parsers; + + g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL); + g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL); + + ct = camel_mime_part_get_content_type (part); + if (!ct) { + mime_type = (gchar *) "application/vnd.evolution.error"; + } else { + gchar *tmp; + tmp = camel_content_type_simple (ct); + mime_type = g_ascii_strdown (tmp, -1); + g_free (tmp); + } + + parsers = e_mail_parser_get_parsers (parser, mime_type); + + if (ct) + g_free (mime_type); + + return parsers; +} + +GQueue * +e_mail_parser_get_parsers (EMailParser *parser, + const gchar *mime_type) +{ + EMailExtensionRegistry *reg; + EMailParserClass *parser_class; + gchar *as_mime_type; + GQueue *parsers; + + g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL); + + if (mime_type) + as_mime_type = g_ascii_strdown (mime_type, -1); + else + as_mime_type = NULL; + + parser_class = E_MAIL_PARSER_GET_CLASS (parser); + reg = E_MAIL_EXTENSION_REGISTRY (parser_class->extension_registry); + + parsers = e_mail_extension_registry_get_for_mime_type (reg, as_mime_type); + if (!parsers) + parsers = e_mail_extension_registry_get_fallback (reg, as_mime_type); + + g_free (as_mime_type); + + return parsers; +} + gboolean e_mail_parser_parse_part (EMailParser *parser, CamelMimePart *part, @@ -536,26 +593,9 @@ e_mail_parser_parse_part_as (EMailParser *parser, { GQueue *parsers; GList *iter; - EMailExtensionRegistry *reg; - EMailParserClass *parser_class; - gchar *as_mime_type; gboolean mime_part_handled = FALSE; - if (mime_type) - as_mime_type = g_ascii_strdown (mime_type, -1); - else - as_mime_type = NULL; - - parser_class = E_MAIL_PARSER_GET_CLASS (parser); - reg = E_MAIL_EXTENSION_REGISTRY (parser_class->extension_registry); - - parsers = e_mail_extension_registry_get_for_mime_type (reg, as_mime_type); - if (!parsers) { - parsers = e_mail_extension_registry_get_fallback (reg, as_mime_type); - } - - if (as_mime_type) - g_free (as_mime_type); + parsers = e_mail_parser_get_parsers (parser, mime_type); if (parsers == NULL) { e_mail_parser_wrap_as_attachment ( diff --git a/src/em-format/e-mail-parser.h b/src/em-format/e-mail-parser.h index 1d0c44795e..9a6ccd309e 100644 --- a/src/em-format/e-mail-parser.h +++ b/src/em-format/e-mail-parser.h @@ -79,6 +79,11 @@ EMailPartList * e_mail_parser_parse_finish (EMailParser *parser, GAsyncResult *result, GError **error); +GQueue * e_mail_parser_get_parsers_for_part + (EMailParser *parser, + CamelMimePart *part); +GQueue * e_mail_parser_get_parsers (EMailParser *parser, + const gchar *mime_type); gboolean e_mail_parser_parse_part (EMailParser *parser, CamelMimePart *part, GString *part_id, -- 2.11.4.GIT