Update how inline email attachments are loaded for viewing.

* src/client/components/client-web-view.vala
  (ClientWebView::add_inline_resource): Renamed fro add_cid_resource, to
  make it more obvious what it is useful for and updated call sites.
  (ClientWebView::add_inline_resources): New method for adding a complete
  set of inline resources.

* src/client/conversation-viewer/conversation-email.vala
  (ConversationEmail::ConversationEmail): Construct a map of inline
  resources, add them to both the primary and attached messages.
  (ConversationEmail::start_loading): Only load attachments once all web
  views have been loaded, so any inline parts that were not displayed
  inline can be displayed as attachments.
This commit is contained in:
Michael James Gratton 2016-10-11 01:31:18 +11:00
parent 10ab9c6115
commit d9cca42169
4 changed files with 48 additions and 11 deletions

View file

@ -94,12 +94,19 @@ public class ClientWebView : WebKit.WebView {
}
/**
* Adds a resource that may be accessed via a cid:id url.
* Adds an inline resource that may be accessed via a cid:id url.
*/
public void add_cid_resource(string id, Geary.Memory.Buffer buf) {
public void add_inline_resource(string id, Geary.Memory.Buffer buf) {
this.cid_resources[id] = buf;
}
/**
* Adds a set of inline resource that may be accessed via a cid:id url.
*/
public void add_inline_resources(Gee.Map<string,Geary.Memory.Buffer> res) {
this.cid_resources.set_all(res);
}
/**
* Selects all content in the web view.
*/

View file

@ -1533,7 +1533,7 @@ public class ComposerWidget : Gtk.EventBox {
// attachment instead.
if (part.content_id != null) {
this.cid_files[part.content_id] = file;
this.editor.add_cid_resource(
this.editor.add_inline_resource(
part.content_id,
new Geary.Memory.FileBuffer(file, true)
);

View file

@ -418,8 +418,23 @@ public class ConversationEmail : Gtk.Box {
});
insert_action_group("eml", message_actions);
// Construct CID resources from attachments
Gee.Map<string,Geary.Memory.Buffer> cid_resources =
new Gee.HashMap<string,Geary.Memory.Buffer>();
foreach (Geary.Attachment att in email.attachments) {
if (att.content_id != null) {
try {
cid_resources[att.content_id] =
new Geary.Memory.FileBuffer(att.file, true);
} catch (Error err) {
debug("Could not open attachment: %s", err.message);
}
}
}
// Construct the view for the primary message, hook into it
Geary.RFC822.Message message;
try {
message = email.get_message();
@ -433,6 +448,7 @@ public class ConversationEmail : Gtk.Box {
contact_store,
email.load_remote_images().is_certain()
);
this.primary_message.web_view.add_inline_resources(cid_resources);
connect_message_view_signals(this.primary_message);
this.primary_message.summary.add(this.actions);
@ -475,6 +491,7 @@ public class ConversationEmail : Gtk.Box {
ConversationMessage attached_message =
new ConversationMessage(sub_message, contact_store, false);
connect_message_view_signals(attached_message);
attached_message.web_view.add_inline_resources(cid_resources);
this.sub_messages.add(attached_message);
this._attached_messages.add(attached_message);
}
@ -496,11 +513,22 @@ public class ConversationEmail : Gtk.Box {
GearyApplication.instance.controller.avatar_session,
load_cancelled
);
return !load_cancelled.is_cancelled();
});
// Only load attachments once the web views have finished
// loading, since we want to know if any attachments marked as
// being inline were actually not displayed inline, and hence
// need to be displayed as if they were attachments.
if (!load_cancelled.is_cancelled()) {
yield load_attachments(load_cancelled);
if (this.message_bodies_loaded) {
yield load_attachments(load_cancelled);
} else {
this.notify["message-bodies-loaded"].connect(() => {
load_attachments.begin(load_cancelled);
});
}
}
}
@ -636,12 +664,13 @@ public class ConversationEmail : Gtk.Box {
}
private async void load_attachments(Cancellable load_cancelled) {
// Do we have any attachments to be displayed? This relies on
// the primary and any attached message bodies having being
// already loaded, so that we know which attachments have been
// shown inline and hence do not need to be included here.
// Determine if we have any attachments to be displayed. This
// relies on the primary and any attached message bodies
// having being already loaded, so that we know which
// attachments have been shown inline and hence do not need to
// be included here.
foreach (Geary.Attachment attachment in email.attachments) {
if (!(attachment.content_id in inlined_content_ids)) {
if (!(attachment.content_id in this.inlined_content_ids)) {
Geary.Mime.DispositionType? disposition = null;
if (attachment.content_disposition != null) {
disposition = attachment.content_disposition.disposition_type;
@ -661,6 +690,7 @@ public class ConversationEmail : Gtk.Box {
}
}
// Now we can actually show the attachments, if any
if (!this.displayed_attachments.is_empty) {
this.attachments_button.show();
this.attachments_button.set_sensitive(!this.is_collapsed);

View file

@ -729,7 +729,7 @@ public class ConversationMessage : Gtk.Grid {
id = REPLACED_CID_TEMPLATE.printf(this.next_replaced_buffer_number++);
}
this.web_view.add_cid_resource(id, buffer);
this.web_view.add_inline_resource(id, buffer);
return "<img alt=\"%s\" class=\"%s\" src=\"%s%s\" />".printf(
Geary.HTML.escape_markup(filename),