diff --git a/src/client/application/geary-application.vala b/src/client/application/geary-application.vala index 52e5b794..d5de58a1 100644 --- a/src/client/application/geary-application.vala +++ b/src/client/application/geary-application.vala @@ -158,6 +158,7 @@ public class GearyApplication : Gtk.Application { { null } }; + private const string MAILTO_URI_SCHEME_PREFIX = "mailto:"; private const int64 USEC_PER_SEC = 1000000; private const int64 FORCE_SHUTDOWN_USEC = 5 * USEC_PER_SEC; @@ -478,10 +479,11 @@ public class GearyApplication : Gtk.Application { string mailto = target.get_uri(); // Due to GNOME/glib#1886, the email address may be // prefixed by a '///'. If so, remove it. - if (mailto.has_prefix("mailto:///")) { + const string B0RKED_GLIB_MAILTO_PREFIX = "mailto:///"; + if (mailto.has_prefix(B0RKED_GLIB_MAILTO_PREFIX)) { mailto = ( - Geary.ComposedEmail.MAILTO_SCHEME + - mailto.substring("mailto:///".length) + MAILTO_URI_SCHEME_PREFIX + + mailto.substring(B0RKED_GLIB_MAILTO_PREFIX.length) ); } this.new_composer.begin(mailto); @@ -635,19 +637,25 @@ public class GearyApplication : Gtk.Application { } /** Displays a URI on the current active window, if any. */ - public void show_uri(string uri) throws Error { - string uri_ = uri; + public async void show_uri(string uri) { + yield create_controller(); - // Support web URLs that omit the protocol. - if (!uri.contains(":")) { - uri_ = "http://" + uri; - } + if (uri.down().has_prefix(MAILTO_URI_SCHEME_PREFIX)) { + yield this.new_composer(uri); + } else { + string uri_ = uri; + // Support web URLs that omit the protocol. + if (!uri.contains(":")) { + uri_ = "http://" + uri; + } - bool success = Gtk.show_uri_on_window( - get_active_window(), uri, Gdk.CURRENT_TIME - ); - if (!success) { - throw new IOError.FAILED("gtk_show_uri() returned false"); + try { + Gtk.show_uri_on_window( + get_active_window(), uri_, Gdk.CURRENT_TIME + ); + } catch (GLib.Error err) { + this.controller.report_problem(new Geary.ProblemReport(err)); + } } } @@ -864,10 +872,10 @@ public class GearyApplication : Gtk.Application { ).get_strv(); foreach (string arg in args) { // the only acceptable arguments are mailto:'s - if (arg == Geary.ComposedEmail.MAILTO_SCHEME) { + if (arg == MAILTO_URI_SCHEME_PREFIX) { activate_action(GearyApplication.ACTION_COMPOSE, null); activated = true; - } else if (arg.has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) { + } else if (arg.down().has_prefix(MAILTO_URI_SCHEME_PREFIX)) { activate_action( GearyApplication.ACTION_MAILTO, new GLib.Variant.string(arg) @@ -1000,7 +1008,7 @@ public class GearyApplication : Gtk.Application { private void on_activate_help() { try { if (this.is_installed) { - show_uri("help:geary"); + this.show_uri.begin("help:geary"); } else { Pid pid; File exec_dir = this.exec_dir; diff --git a/src/client/components/main-window.vala b/src/client/components/main-window.vala index f9f2db0d..5e248814 100644 --- a/src/client/components/main-window.vala +++ b/src/client/components/main-window.vala @@ -1416,7 +1416,6 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface { this.on_shift_key.connect(view.shift_key_changed); foreach (ConversationMessage msg_view in view) { - msg_view.link_activated.connect(on_link_activated); msg_view.save_image.connect((url, alt_text, buf) => { on_save_image_extended(view, url, alt_text, buf); }); @@ -1870,12 +1869,7 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface { } foreach (Geary.Attachment attachment in attachments) { - string uri = attachment.file.get_uri(); - try { - this.application.show_uri(uri); - } catch (Error err) { - message("Unable to open attachment \"%s\": %s", uri, err.message); - } + this.application.show_uri.begin(attachment.file.get_uri()); } } @@ -1911,7 +1905,7 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface { FileUtils.chmod(temporary_filename, (int) (Posix.S_IRUSR | Posix.S_IWUSR)); string temporary_uri = Filename.to_uri(temporary_filename, null); - this.application.show_uri(temporary_uri); + this.application.show_uri.begin(temporary_uri); } catch (Error error) { ErrorDialog dialog = new ErrorDialog( this, @@ -1969,19 +1963,4 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface { } } - private void on_link_activated(string uri) { - try { - if (uri.down().has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) { - this.application.controller.compose(uri); - } else { - this.application.show_uri(uri); - } - } catch (GLib.Error err) { - handle_error( - this.selected_account != null ? this.selected_account.information : null, - err - ); - } - } - } diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala index 1c3c17ee..5d62420c 100644 --- a/src/client/composer/composer-widget.vala +++ b/src/client/composer/composer-widget.vala @@ -164,6 +164,8 @@ public class ComposerWidget : Gtk.EventBox, Geary.BaseInterface { private const string URI_LIST_MIME_TYPE = "text/uri-list"; private const string FILE_URI_PREFIX = "file://"; + private const string MAILTO_URI_PREFIX = "mailto:"; + // Keep these in sync with the next const below. private const string ATTACHMENT_KEYWORDS = "attach|attaching|attaches|attachment|attachments|attached|enclose|enclosed|enclosing|encloses|enclosure|enclosures"; @@ -566,9 +568,9 @@ public class ComposerWidget : Gtk.EventBox, Geary.BaseInterface { this(application, initial_account, null, ComposeType.NEW_MESSAGE); Gee.HashMultiMap headers = new Gee.HashMultiMap(); - if (mailto.length > Geary.ComposedEmail.MAILTO_SCHEME.length) { + if (mailto.has_prefix(MAILTO_URI_PREFIX)) { // Parse the mailto link. - string[] parts = mailto.substring(Geary.ComposedEmail.MAILTO_SCHEME.length).split("?", 2); + string[] parts = mailto.substring(MAILTO_URI_PREFIX.length).split("?", 2); string email = Uri.unescape_string(parts[0]); string[] params = parts.length == 2 ? parts[1].split("&") : new string[0]; foreach (string param in params) { @@ -2337,11 +2339,7 @@ public class ComposerWidget : Gtk.EventBox, Geary.BaseInterface { this.editor.delete_link(selection_id); }); popover.link_open.connect(() => { - try { - this.application.show_uri(popover.link_uri); - } catch (GLib.Error err) { - debug("Failed to open URI: %s", err.message); - } + this.application.show_uri.begin(popover.link_uri); }); return popover; } diff --git a/src/client/conversation-viewer/conversation-message.vala b/src/client/conversation-viewer/conversation-message.vala index 0180aa7e..fb0cf1d0 100644 --- a/src/client/conversation-viewer/conversation-message.vala +++ b/src/client/conversation-viewer/conversation-message.vala @@ -25,6 +25,9 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface { private const string REPLACED_CID_TEMPLATE = "replaced_%02u@geary"; private const string REPLACED_IMAGE_CLASS = "geary_replaced_inline_image"; + private const string MAILTO_URI_PREFIX = "mailto:"; + + private const int MAX_PREVIEW_BYTES = Geary.Email.MAX_PREVIEW_BYTES; private const int SHOW_PROGRESS_TIMEOUT_MSEC = 1000; @@ -332,9 +335,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface { private Geary.TimeoutManager progress_pulse; - /** Fired when the user clicks a link in the email. */ - public signal void link_activated(string link); - /** Fired when the user clicks a internal link in the email. */ public signal void internal_link_activated(int y); @@ -400,7 +400,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface { // Actions add_action(ACTION_CONVERSATION_NEW, true, VariantType.STRING) - .activate.connect(on_new_conversation); + .activate.connect(on_link_activated); add_action(ACTION_COPY_EMAIL, true, VariantType.STRING) .activate.connect(on_copy_email_address); add_action(ACTION_COPY_LINK, true, VariantType.STRING) @@ -1104,7 +1104,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface { if (hit_test.context_is_link()) { string link_url = hit_test.get_link_uri(); MenuModel link_menu = - link_url.has_prefix(Geary.ComposedEmail.MAILTO_SCHEME) + link_url.has_prefix(MAILTO_URI_PREFIX) ? context_menu_email : context_menu_link; model.append_section( @@ -1221,26 +1221,10 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface { clipboard.store(); } - private void on_new_conversation(Variant? param) { - string value = param.get_string(); - if (value.has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) { - value = value.substring(Geary.ComposedEmail.MAILTO_SCHEME.length, -1); - } - - MainWindow? main = this.get_toplevel() as MainWindow; - if (main != null && - Geary.RFC822.MailboxAddress.is_valid_address(value)) { - Geary.RFC822.MailboxAddress mailbox = new Geary.RFC822.MailboxAddress( - null, value - ); - main.open_composer_for_mailbox(mailbox); - } - } - private void on_copy_email_address(Variant? param) { string value = param.get_string(); - if (value.has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) { - value = value.substring(Geary.ComposedEmail.MAILTO_SCHEME.length, -1); + if (value.has_prefix(MAILTO_URI_PREFIX)) { + value = value.substring(MAILTO_URI_PREFIX.length, -1); } Gtk.Clipboard clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD); clipboard.set_text(value, -1); @@ -1291,7 +1275,10 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface { } }); } else { - link_activated(link); + MainWindow? main = this.get_toplevel() as MainWindow; + if (main != null) { + main.application.show_uri.begin(link); + } } } diff --git a/src/engine/api/geary-composed-email.vala b/src/engine/api/geary-composed-email.vala index 5b9be5f2..4c1eb9e4 100644 --- a/src/engine/api/geary-composed-email.vala +++ b/src/engine/api/geary-composed-email.vala @@ -9,8 +9,6 @@ */ public class Geary.ComposedEmail : BaseObject { - public const string MAILTO_SCHEME = "mailto:"; - private const string IMG_SRC_TEMPLATE = "src=\"%s\""; public const Geary.Email.Field REQUIRED_REPLY_FIELDS =