Merge lp:~purejava/pantheon-mail/improve-mime-handling into lp:~elementary-apps/pantheon-mail/trunk

Proposed by Ralph Plawetzki
Status: Merged
Approved by: Danielle Foré
Approved revision: 1971
Merged at revision: 1979
Proposed branch: lp:~purejava/pantheon-mail/improve-mime-handling
Merge into: lp:~elementary-apps/pantheon-mail/trunk
Diff against target: 111 lines (+17/-14)
2 files modified
src/client/conversation-viewer/conversation-viewer.vala (+11/-4)
src/engine/rfc822/rfc822-message.vala (+6/-10)
To merge this branch: bzr merge lp:~purejava/pantheon-mail/improve-mime-handling
Reviewer Review Type Date Requested Status
elementary Apps team Pending
Review via email: mp+286203@code.launchpad.net

Commit message

Improve mimetype handling in the conversation viewer

Description of the change

Patch to address LP#1545605 and LP#1543629

Mail processes all nested content types of an email recursively.
First, Mail assumes Geary.RFC822.TextFormat.HTML and walks through the email. If there is a least one content type of html or an inlined image, these parts are used.
If none are found, Mail assumes Geary.RFC822.TextFormat.PLAIN and walks through the email a second time. Now, if there is at least one content type of plain text or an inlined image, these parts are used.

LP#1543629
Mail already has a functionality for saving inline images, which has been modified with commit 89ca016 [1] to only allow this for Mime.MultipartSubtype.MIXED.
This patch reverts this restriction. As images that are allowed to be saved have a tag "replaced-id", this tag gets added in ConversationViewer#insert_html_markup(..) for images that have a content-id, but no data prefix yet.

[1] https://github.com/GNOME/geary/commit/89ca0167830dfbc63e4b90e6085764e690fc4fde

LP#1545605
The problem here is, that assuming Geary.RFC822.TextFormat.HTML during the first walk through ignores the plain text parts but finds the inlined images which are returned.
The reason for this is line 539 in rfc822-message.vala. The variable body has a valid content (with an replaced image), so the return statement returns true for the inlined image.

Setting this to always false means that inlined images are never treated as valid content here, but line 487 (found_text_subtype |= construct_body_from_mime_parts...) takes care of this. As, depending on the Geary.RFC822.TextFormat, other valid parts have been found and the body gets contructed correctly.

As line 539 is always false now, it does not reflect returns of null in inline_image_replacer(..) any more which indicates errors, but this is ok (see above).

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/client/conversation-viewer/conversation-viewer.vala'
2--- src/client/conversation-viewer/conversation-viewer.vala 2016-01-18 10:11:06 +0000
3+++ src/client/conversation-viewer/conversation-viewer.vala 2016-02-16 16:41:42 +0000
4@@ -182,6 +182,7 @@
5 private int next_replaced_buffer_number = 0;
6 private Gee.HashMap<string, ReplacedImage> replaced_images = new Gee.HashMap<string, ReplacedImage>();
7 private Gee.HashSet<string> replaced_content_ids = new Gee.HashSet<string>();
8+ private Gee.HashMap<string, string> replaced_images_index = new Gee.HashMap<string, string>();
9 private Gee.HashSet<string> blacklist_ids = new Gee.HashSet<string>();
10
11 public ConversationViewer() {
12@@ -859,7 +860,7 @@
13 //
14 // * Geary.RFC822.Message.get_body() recursively walks the message's MIME structure looking
15 // for text MIME parts and assembles them sequentially. If non-text MIME parts are
16- // discovered within a multipart/mixed container, it calls inline_image_replacer(), which
17+ // discovered, it calls inline_image_replacer(), which
18 // converts them to an IMG tag with a data: URI if they are a supported image type.
19 // Otherwise, the MIME part is dropped.
20 //
21@@ -941,7 +942,7 @@
22 }
23
24 // This delegate is called from within Geary.RFC822.Message.get_body while assembling the plain
25- // or HTML document when a non-text MIME part is encountered within a multipart/mixed container.
26+ // or HTML document when a non-text MIME part is encountered.
27 // If this returns null, the MIME part is dropped from the final returned document; otherwise,
28 // this returns HTML that is placed into the document in the position where the MIME part was
29 // found
30@@ -1012,6 +1013,10 @@
31 buffer);
32 replaced_images.set(replaced_image.id, replaced_image);
33
34+ if (!Geary.String.is_empty(content_id)) {
35+ replaced_images_index.set(content_id, replaced_image.id);
36+ }
37+
38 return "<img alt=\"%s\" class=\"%s %s\" src=\"%s\" replaced-id=\"%s\" %s />".printf(
39 Geary.HTML.escape_markup(filename),
40 DATA_IMAGE_CLASS, REPLACED_IMAGE_CLASS,
41@@ -2005,7 +2010,8 @@
42
43 // if image has a Content-ID and it's already been replaced by the image replacer,
44 // drop this tag, otherwise fix up this one with the Base-64 data URI of the image
45- if (!replaced_content_ids.contains(content_id)) {
46+ // and the replaced id
47+ if (!src.has_prefix("data:")) {
48 string? filename = message.get_content_filename_by_mime_id(content_id);
49 Geary.Memory.Buffer image_content = message.get_content_by_mime_id(content_id);
50 Geary.Memory.UnownedBytesBuffer? unowned_buffer =
51@@ -2021,11 +2027,12 @@
52 string mimetype = ContentType.get_mime_type(guess);
53
54 // Replace the SRC to a data URI, the class to a known label for the popup menu,
55- // and the ALT to its filename, if supplied
56+ // the ALT to its filename, if supplied and add the replaced-id
57 img.set_attribute("src", assemble_data_uri(mimetype, image_content));
58 img.set_attribute("class", DATA_IMAGE_CLASS);
59 if (!Geary.String.is_empty(filename))
60 img.set_attribute("alt", filename);
61+ img.set_attribute("replaced-id", replaced_images_index.get(content_id));
62
63 // stash here so inlined image isn't listed as attachment (esp. if it has no
64 // Content-Disposition)
65
66=== modified file 'src/engine/rfc822/rfc822-message.vala'
67--- src/engine/rfc822/rfc822-message.vala 2015-03-12 01:11:48 +0000
68+++ src/engine/rfc822/rfc822-message.vala 2016-02-16 16:41:42 +0000
69@@ -451,8 +451,8 @@
70 /**
71 * This method is the main utility method used by the other body-generating constructors.
72 *
73- * Only text/* MIME parts of the specified subtype are added to body. If a non-text part is
74- * within a multipart/mixed container, the {@link InlinePartReplacer} is invoked.
75+ * Only text/* MIME parts of the specified subtype are added to body. For non-text parts
76+ * the {@link InlinePartReplacer} is invoked.
77 *
78 * If to_html is true, the text is run through a filter to HTML-ize it. (Obviously, this
79 * should be false if text/html is being searched for.).
80@@ -525,18 +525,14 @@
81 if (disposition == null || disposition.disposition_type == Mime.DispositionType.UNSPECIFIED)
82 return false;
83
84- // Use inline part replacer *only* if in a mixed multipart where each element is to be
85- // presented to the user as structure dictates; for alternative and related, the inline
86- // part is referred to elsewhere in the document and it's the callers responsibility to
87- // locate them
88- if (replacer == null || container_subtype != Mime.MultipartSubtype.MIXED)
89+ if (replacer == null)
90 return false;
91
92 // Hand off to the replacer for processing
93 body = replacer(RFC822.Utils.get_clean_attachment_filename(part),
94 this_content_type, disposition, part.get_content_id(), mime_part_to_memory_buffer(part));
95
96- return body != null;
97+ return false;
98 }
99
100 /**
101@@ -586,8 +582,8 @@
102 * Returns the complete email body as HTML.
103 *
104 * get_body() recursively walks the MIME structure (depth-first) serializing all text MIME
105- * parts of the specified type into a single UTF-8 string. Non-text MIME parts inside of
106- * multipart/mixed containers are offered to the {@link InlinePartReplacer}, which can either
107+ * parts of the specified type into a single UTF-8 string. Non-text MIME parts
108+ * are offered to the {@link InlinePartReplacer}, which can either
109 * return null or return a string that is inserted in lieu of the MIME part into the final
110 * document. All other MIME parts are ignored.
111 *

Subscribers

People subscribed via source and target branches