Make GearyApplication::show_uri handle mailto: URIs

This lets us simplify several code paths where these were handled,
and remove a signal and handler from ConversationMessage.
This commit is contained in:
Michael Gratton 2019-10-27 21:15:40 +11:00 committed by Michael James Gratton
parent 50749d9823
commit bcce3a3a83
5 changed files with 43 additions and 73 deletions

View file

@ -158,6 +158,7 @@ public class GearyApplication : Gtk.Application {
{ null } { null }
}; };
private const string MAILTO_URI_SCHEME_PREFIX = "mailto:";
private const int64 USEC_PER_SEC = 1000000; private const int64 USEC_PER_SEC = 1000000;
private const int64 FORCE_SHUTDOWN_USEC = 5 * USEC_PER_SEC; private const int64 FORCE_SHUTDOWN_USEC = 5 * USEC_PER_SEC;
@ -478,10 +479,11 @@ public class GearyApplication : Gtk.Application {
string mailto = target.get_uri(); string mailto = target.get_uri();
// Due to GNOME/glib#1886, the email address may be // Due to GNOME/glib#1886, the email address may be
// prefixed by a '///'. If so, remove it. // 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 = ( mailto = (
Geary.ComposedEmail.MAILTO_SCHEME + MAILTO_URI_SCHEME_PREFIX +
mailto.substring("mailto:///".length) mailto.substring(B0RKED_GLIB_MAILTO_PREFIX.length)
); );
} }
this.new_composer.begin(mailto); this.new_composer.begin(mailto);
@ -635,19 +637,25 @@ public class GearyApplication : Gtk.Application {
} }
/** Displays a URI on the current active window, if any. */ /** Displays a URI on the current active window, if any. */
public void show_uri(string uri) throws Error { public async void show_uri(string uri) {
string uri_ = uri; yield create_controller();
// Support web URLs that omit the protocol. if (uri.down().has_prefix(MAILTO_URI_SCHEME_PREFIX)) {
if (!uri.contains(":")) { yield this.new_composer(uri);
uri_ = "http://" + 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( try {
get_active_window(), uri, Gdk.CURRENT_TIME Gtk.show_uri_on_window(
); get_active_window(), uri_, Gdk.CURRENT_TIME
if (!success) { );
throw new IOError.FAILED("gtk_show_uri() returned false"); } catch (GLib.Error err) {
this.controller.report_problem(new Geary.ProblemReport(err));
}
} }
} }
@ -864,10 +872,10 @@ public class GearyApplication : Gtk.Application {
).get_strv(); ).get_strv();
foreach (string arg in args) { foreach (string arg in args) {
// the only acceptable arguments are mailto:'s // 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); activate_action(GearyApplication.ACTION_COMPOSE, null);
activated = true; activated = true;
} else if (arg.has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) { } else if (arg.down().has_prefix(MAILTO_URI_SCHEME_PREFIX)) {
activate_action( activate_action(
GearyApplication.ACTION_MAILTO, GearyApplication.ACTION_MAILTO,
new GLib.Variant.string(arg) new GLib.Variant.string(arg)
@ -1000,7 +1008,7 @@ public class GearyApplication : Gtk.Application {
private void on_activate_help() { private void on_activate_help() {
try { try {
if (this.is_installed) { if (this.is_installed) {
show_uri("help:geary"); this.show_uri.begin("help:geary");
} else { } else {
Pid pid; Pid pid;
File exec_dir = this.exec_dir; File exec_dir = this.exec_dir;

View file

@ -1416,7 +1416,6 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
this.on_shift_key.connect(view.shift_key_changed); this.on_shift_key.connect(view.shift_key_changed);
foreach (ConversationMessage msg_view in view) { foreach (ConversationMessage msg_view in view) {
msg_view.link_activated.connect(on_link_activated);
msg_view.save_image.connect((url, alt_text, buf) => { msg_view.save_image.connect((url, alt_text, buf) => {
on_save_image_extended(view, 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) { foreach (Geary.Attachment attachment in attachments) {
string uri = attachment.file.get_uri(); this.application.show_uri.begin(attachment.file.get_uri());
try {
this.application.show_uri(uri);
} catch (Error err) {
message("Unable to open attachment \"%s\": %s", uri, err.message);
}
} }
} }
@ -1911,7 +1905,7 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
FileUtils.chmod(temporary_filename, (int) (Posix.S_IRUSR | Posix.S_IWUSR)); FileUtils.chmod(temporary_filename, (int) (Posix.S_IRUSR | Posix.S_IWUSR));
string temporary_uri = Filename.to_uri(temporary_filename, null); 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) { } catch (Error error) {
ErrorDialog dialog = new ErrorDialog( ErrorDialog dialog = new ErrorDialog(
this, 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
);
}
}
} }

View file

@ -164,6 +164,8 @@ public class ComposerWidget : Gtk.EventBox, Geary.BaseInterface {
private const string URI_LIST_MIME_TYPE = "text/uri-list"; private const string URI_LIST_MIME_TYPE = "text/uri-list";
private const string FILE_URI_PREFIX = "file://"; private const string FILE_URI_PREFIX = "file://";
private const string MAILTO_URI_PREFIX = "mailto:";
// Keep these in sync with the next const below. // Keep these in sync with the next const below.
private const string ATTACHMENT_KEYWORDS = private const string ATTACHMENT_KEYWORDS =
"attach|attaching|attaches|attachment|attachments|attached|enclose|enclosed|enclosing|encloses|enclosure|enclosures"; "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); this(application, initial_account, null, ComposeType.NEW_MESSAGE);
Gee.HashMultiMap<string, string> headers = new Gee.HashMultiMap<string, string>(); Gee.HashMultiMap<string, string> headers = new Gee.HashMultiMap<string, string>();
if (mailto.length > Geary.ComposedEmail.MAILTO_SCHEME.length) { if (mailto.has_prefix(MAILTO_URI_PREFIX)) {
// Parse the mailto link. // 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 email = Uri.unescape_string(parts[0]);
string[] params = parts.length == 2 ? parts[1].split("&") : new string[0]; string[] params = parts.length == 2 ? parts[1].split("&") : new string[0];
foreach (string param in params) { foreach (string param in params) {
@ -2337,11 +2339,7 @@ public class ComposerWidget : Gtk.EventBox, Geary.BaseInterface {
this.editor.delete_link(selection_id); this.editor.delete_link(selection_id);
}); });
popover.link_open.connect(() => { popover.link_open.connect(() => {
try { this.application.show_uri.begin(popover.link_uri);
this.application.show_uri(popover.link_uri);
} catch (GLib.Error err) {
debug("Failed to open URI: %s", err.message);
}
}); });
return popover; return popover;
} }

View file

@ -25,6 +25,9 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
private const string REPLACED_CID_TEMPLATE = "replaced_%02u@geary"; private const string REPLACED_CID_TEMPLATE = "replaced_%02u@geary";
private const string REPLACED_IMAGE_CLASS = "geary_replaced_inline_image"; 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 MAX_PREVIEW_BYTES = Geary.Email.MAX_PREVIEW_BYTES;
private const int SHOW_PROGRESS_TIMEOUT_MSEC = 1000; private const int SHOW_PROGRESS_TIMEOUT_MSEC = 1000;
@ -332,9 +335,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
private Geary.TimeoutManager progress_pulse; 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. */ /** Fired when the user clicks a internal link in the email. */
public signal void internal_link_activated(int y); public signal void internal_link_activated(int y);
@ -400,7 +400,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
// Actions // Actions
add_action(ACTION_CONVERSATION_NEW, true, VariantType.STRING) 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) add_action(ACTION_COPY_EMAIL, true, VariantType.STRING)
.activate.connect(on_copy_email_address); .activate.connect(on_copy_email_address);
add_action(ACTION_COPY_LINK, true, VariantType.STRING) 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()) { if (hit_test.context_is_link()) {
string link_url = hit_test.get_link_uri(); string link_url = hit_test.get_link_uri();
MenuModel link_menu = MenuModel link_menu =
link_url.has_prefix(Geary.ComposedEmail.MAILTO_SCHEME) link_url.has_prefix(MAILTO_URI_PREFIX)
? context_menu_email ? context_menu_email
: context_menu_link; : context_menu_link;
model.append_section( model.append_section(
@ -1221,26 +1221,10 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
clipboard.store(); 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) { private void on_copy_email_address(Variant? param) {
string value = param.get_string(); string value = param.get_string();
if (value.has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) { if (value.has_prefix(MAILTO_URI_PREFIX)) {
value = value.substring(Geary.ComposedEmail.MAILTO_SCHEME.length, -1); value = value.substring(MAILTO_URI_PREFIX.length, -1);
} }
Gtk.Clipboard clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD); Gtk.Clipboard clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD);
clipboard.set_text(value, -1); clipboard.set_text(value, -1);
@ -1291,7 +1275,10 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
} }
}); });
} else { } else {
link_activated(link); MainWindow? main = this.get_toplevel() as MainWindow;
if (main != null) {
main.application.show_uri.begin(link);
}
} }
} }

View file

@ -9,8 +9,6 @@
*/ */
public class Geary.ComposedEmail : BaseObject { public class Geary.ComposedEmail : BaseObject {
public const string MAILTO_SCHEME = "mailto:";
private const string IMG_SRC_TEMPLATE = "src=\"%s\""; private const string IMG_SRC_TEMPLATE = "src=\"%s\"";
public const Geary.Email.Field REQUIRED_REPLY_FIELDS = public const Geary.Email.Field REQUIRED_REPLY_FIELDS =