From a14f5d4799ae3d5f81804c9501fc6aab3f5020a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bellegarde?= Date: Thu, 25 Aug 2022 23:12:45 +0200 Subject: [PATCH] client: accounts: Add support for Thunderbird autoconfig - Auto detect server settings - Rework accounts editor add panel Fix #1390 Fix #1350 --- meson.build | 1 + src/client/accounts/accounts-autoconfig.vala | 170 +++++++++ .../accounts/accounts-editor-add-pane.vala | 342 ++++++++++++------ .../accounts/accounts-editor-list-pane.vala | 103 +----- src/client/meson.build | 1 + ui/accounts_editor_add_pane.ui | 195 +++++----- ui/accounts_editor_list_pane.ui | 58 +-- 7 files changed, 507 insertions(+), 363 deletions(-) create mode 100644 src/client/accounts/accounts-autoconfig.vala diff --git a/meson.build b/meson.build index 1be205e3..df2ee5a8 100644 --- a/meson.build +++ b/meson.build @@ -93,6 +93,7 @@ libhandy = dependency('libhandy-1', version: '>= 1.2.1', required: false) libmath = cc.find_library('m') libpeas = dependency('libpeas-1.0', version: '>= 1.24.0') libsecret = dependency('libsecret-1', version: '>= 0.11') +libsoup = dependency('libsoup-3.0') libstemmer_dep = cc.find_library('stemmer') libunwind_dep = dependency( 'libunwind', version: '>= 1.1', required: get_option('libunwind') diff --git a/src/client/accounts/accounts-autoconfig.vala b/src/client/accounts/accounts-autoconfig.vala new file mode 100644 index 00000000..58bd8463 --- /dev/null +++ b/src/client/accounts/accounts-autoconfig.vala @@ -0,0 +1,170 @@ +/* + * Copyright 2022 Cédric Bellegarde + * + * This software is licensed under the GNU Lesser General Public License + * (version 2.1 or later). See the COPYING file in this distribution. + */ + +/** + * Thunderbird autoconfig XML values + */ +internal class Accounts.AutoConfigValues { + // emailProvider.id + public string id { get; set; default = ""; } + + // incomingServer[type="imap"].hostname + public string imap_server { get; set; default = ""; } + // incomingServer[type="imap"].port + public string imap_port { get; set; default = ""; } + // incomingServer[type="imap"].socketType + public Geary.TlsNegotiationMethod imap_tls_method { + get; set; default = Geary.TlsNegotiationMethod.TRANSPORT; + } + + // outgoingServer[type="smtp"].hostname + public string smtp_server{ get; set; default = ""; } + // outgoingServer[type="smtp"].port + public string smtp_port { get; set; default = ""; } + // outgoingServer[type="smtp"].socketType + public Geary.TlsNegotiationMethod smtp_tls_method { + get; set; default = Geary.TlsNegotiationMethod.TRANSPORT; + } + +} + +internal errordomain Accounts.AutoConfigError { + ERROR +} + +/** + * An account autoconfiguration helper + */ +internal class Accounts.AutoConfig { + + private static string AUTOCONFIG_BASE_URI = "https://autoconfig.thunderbird.net/v1.1/"; + private static string AUTOCONFIG_PATH = "/mail/config-v1.1.xml"; + + private unowned GLib.Cancellable cancellable; + + internal AutoConfig(GLib.Cancellable auto_config_cancellable) { + cancellable = auto_config_cancellable; + } + + public async AutoConfigValues get_config(string hostname) + throws AutoConfigError { + AutoConfigValues auto_config_values; + + // First try to get config from mail domain, then from thunderbird + try { + auto_config_values = yield get_config_for_uri( + "https://autoconfig." + hostname + AUTOCONFIG_PATH + ); + } catch (AutoConfigError err) { + auto_config_values = yield get_config_for_uri( + AUTOCONFIG_BASE_URI + hostname + ); + } + return auto_config_values; + } + + private async AutoConfigValues get_config_for_uri(string uri) + throws AutoConfigError { + GLib.InputStream stream; + var session = new Soup.Session(); + var msg = new Soup.Message("GET", uri); + + try { + stream = yield session.send_async( + msg, Priority.DEFAULT, this.cancellable + ); + } catch (GLib.Error err) { + throw new AutoConfigError.ERROR(err.message); + } + + try { + var stdout_stream = new MemoryOutputStream.resizable(); + yield stdout_stream.splice_async( + stream, 0, Priority.DEFAULT, null + ); + stdout_stream.write("\0".data); + stdout_stream.close(); + unowned var xml_data = (string) stdout_stream.get_data(); + return get_config_for_xml(xml_data); + } catch (GLib.Error err) { + throw new AutoConfigError.ERROR(err.message); + } finally { + try { + yield stream.close_async(); + } catch (GLib.Error err) { + // Oh well + } + } + } + + private AutoConfigValues get_config_for_xml(string xml_data) + throws AutoConfigError { + unowned Xml.Doc doc = Xml.Parser.parse_memory(xml_data, xml_data.length); + if (doc == null) { + throw new AutoConfigError.ERROR("Invalid XML"); + } + + unowned Xml.Node root = doc.get_root_element(); + unowned Xml.Node email_provider = get_node(root, "emailProvider"); + unowned Xml.Node incoming_server = get_node(email_provider, "incomingServer"); + unowned Xml.Node outgoing_server = get_node(email_provider, "outgoingServer"); + + if (incoming_server == null || outgoing_server == null) { + throw new AutoConfigError.ERROR("Invalid XML"); + } + + if (incoming_server.get_prop("type") != "imap" || + outgoing_server.get_prop("type") != "smtp") { + throw new AutoConfigError.ERROR("Unsupported protocol"); + } + + var auto_config_values = new AutoConfigValues(); + + auto_config_values.id = email_provider.get_prop("id"); + + auto_config_values.imap_server = get_node_value(incoming_server, "hostname"); + auto_config_values.imap_port = get_node_value(incoming_server, "port"); + auto_config_values.imap_tls_method = get_tls_method( + get_node_value(incoming_server, "socketType") + ); + + auto_config_values.smtp_server = get_node_value(outgoing_server, "hostname"); + auto_config_values.smtp_port = get_node_value(outgoing_server, "port"); + auto_config_values.smtp_tls_method = get_tls_method( + get_node_value(outgoing_server, "socketType") + ); + + return auto_config_values; + } + + private unowned Xml.Node? get_node(Xml.Node root, string name) { + for (unowned Xml.Node entry = root.children; entry != null; entry = entry.next) { + if (entry.type == Xml.ElementType.ELEMENT_NODE && entry.name == name) { + return entry; + } + } + return null; + } + + private string get_node_value(Xml.Node root, string name) { + unowned Xml.Node? node = get_node(root, name); + if (node == null) + return ""; + return node.get_content(); + } + + private Geary.TlsNegotiationMethod get_tls_method(string method) { + switch (method) { + case "SSL": + return Geary.TlsNegotiationMethod.TRANSPORT; + case "STARTTLS": + return Geary.TlsNegotiationMethod.START_TLS; + default: + return Geary.TlsNegotiationMethod.NONE; + } + } +} diff --git a/src/client/accounts/accounts-editor-add-pane.vala b/src/client/accounts/accounts-editor-add-pane.vala index 647711f4..1eb4eda3 100644 --- a/src/client/accounts/accounts-editor-add-pane.vala +++ b/src/client/accounts/accounts-editor-add-pane.vala @@ -37,31 +37,29 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { [GtkChild] private unowned Gtk.HeaderBar header; - [GtkChild] private unowned Gtk.Grid pane_content; + [GtkChild] private unowned Gtk.Stack stack; [GtkChild] private unowned Gtk.Adjustment pane_adjustment; [GtkChild] private unowned Gtk.ListBox details_list; - [GtkChild] private unowned Gtk.Grid receiving_panel; - [GtkChild] private unowned Gtk.ListBox receiving_list; - [GtkChild] private unowned Gtk.Grid sending_panel; - [GtkChild] private unowned Gtk.ListBox sending_list; - [GtkChild] private unowned Gtk.Button create_button; + [GtkChild] private unowned Gtk.Button action_button; [GtkChild] private unowned Gtk.Button back_button; - [GtkChild] private unowned Gtk.Spinner create_spinner; + [GtkChild] private unowned Gtk.Spinner action_spinner; private NameRow real_name; private EmailRow email = new EmailRow(); private string last_valid_email = ""; private string last_valid_hostname = ""; + private GLib.Cancellable auto_config_cancellable = new GLib.Cancellable(); + private HostnameRow imap_hostname = new HostnameRow(Geary.Protocol.IMAP); private TransportSecurityRow imap_tls = new TransportSecurityRow(); private LoginRow imap_login = new LoginRow(); @@ -76,32 +74,19 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { private bool controls_valid = false; - internal EditorAddPane(Editor editor, Geary.ServiceProvider provider) { + internal EditorAddPane(Editor editor) { this.editor = editor; - this.provider = provider; + this.provider = Geary.ServiceProvider.OTHER; this.accounts = editor.application.controller.account_manager; this.engine = editor.application.engine; - this.pane_content.set_focus_vadjustment(this.pane_adjustment); + this.stack.set_focus_vadjustment(this.pane_adjustment); this.details_list.set_header_func(Editor.seperator_headers); this.receiving_list.set_header_func(Editor.seperator_headers); this.sending_list.set_header_func(Editor.seperator_headers); - if (provider != Geary.ServiceProvider.OTHER) { - this.details_list.add( - new ServiceProviderRow( - provider, - // Translators: Label for adding an email account - // account for a generic IMAP service provider. - _("All others") - ) - ); - this.receiving_panel.hide(); - this.sending_panel.hide(); - } - this.real_name = new NameRow(this.accounts.get_account_name()); this.details_list.add(this.real_name); @@ -130,18 +115,14 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { this.smtp_password.validator.state_changed.connect(on_validated); this.smtp_password.value.activate.connect(on_activated); - if (provider == Geary.ServiceProvider.OTHER) { - this.receiving_list.add(this.imap_hostname); - this.receiving_list.add(this.imap_tls); - this.receiving_list.add(this.imap_login); - this.receiving_list.add(this.imap_password); + this.receiving_list.add(this.imap_hostname); + this.receiving_list.add(this.imap_tls); + this.receiving_list.add(this.imap_login); + this.receiving_list.add(this.imap_password); - this.sending_list.add(this.smtp_hostname); - this.sending_list.add(this.smtp_tls); - this.sending_list.add(this.smtp_auth); - } else { - this.details_list.add(this.imap_password); - } + this.sending_list.add(this.smtp_hostname); + this.sending_list.add(this.smtp_tls); + this.sending_list.add(this.smtp_auth); } internal Gtk.HeaderBar get_header() { @@ -169,7 +150,8 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { account.outgoing = new_smtp_service(); account.untrusted_host.connect(on_untrusted_host); - if (this.provider == Geary.ServiceProvider.OTHER) { + if (this.provider == Geary.ServiceProvider.OTHER && + this.imap_hostname.get_visible()) { bool imap_valid = false; bool smtp_valid = false; @@ -302,30 +284,22 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { Geary.Protocol.IMAP, this.provider ); - if (this.provider == Geary.ServiceProvider.OTHER) { - service.credentials = new Geary.Credentials( - Geary.Credentials.Method.PASSWORD, - this.imap_login.value.get_text().strip(), - this.imap_password.value.get_text().strip() - ); + service.credentials = new Geary.Credentials( + Geary.Credentials.Method.PASSWORD, + this.imap_login.value.get_text().strip(), + this.imap_password.value.get_text().strip() + ); - Components.NetworkAddressValidator host = - (Components.NetworkAddressValidator) - this.imap_hostname.validator; - GLib.NetworkAddress address = host.validated_address; - service.host = address.hostname; - service.port = (uint16) address.port; - service.transport_security = this.imap_tls.value.method; + Components.NetworkAddressValidator host = + (Components.NetworkAddressValidator) + this.imap_hostname.validator; + GLib.NetworkAddress address = host.validated_address; + service.host = address.hostname; + service.port = (uint16) address.port; + service.transport_security = this.imap_tls.value.method; - if (service.port == 0) { - service.port = service.get_default_port(); - } - } else { - service.credentials = new Geary.Credentials( - Geary.Credentials.Method.PASSWORD, - this.email.value.get_text().strip(), - this.imap_password.value.get_text().strip() - ); + if (service.port == 0) { + service.port = service.get_default_port(); } return service; @@ -336,96 +310,121 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { Geary.Protocol.SMTP, this.provider ); - if (this.provider == Geary.ServiceProvider.OTHER) { - service.credentials_requirement = this.smtp_auth.value.source; - if (service.credentials_requirement == - Geary.Credentials.Requirement.CUSTOM) { - service.credentials = new Geary.Credentials( - Geary.Credentials.Method.PASSWORD, - this.smtp_login.value.get_text().strip(), - this.smtp_password.value.get_text().strip() - ); - } + service.credentials_requirement = this.smtp_auth.value.source; + if (service.credentials_requirement == + Geary.Credentials.Requirement.CUSTOM) { + service.credentials = new Geary.Credentials( + Geary.Credentials.Method.PASSWORD, + this.smtp_login.value.get_text().strip(), + this.smtp_password.value.get_text().strip() + ); + } - Components.NetworkAddressValidator host = - (Components.NetworkAddressValidator) - this.smtp_hostname.validator; - GLib.NetworkAddress address = host.validated_address; + Components.NetworkAddressValidator host = + (Components.NetworkAddressValidator) + this.smtp_hostname.validator; + GLib.NetworkAddress address = host.validated_address; - service.host = address.hostname; - service.port = (uint16) address.port; - service.transport_security = this.smtp_tls.value.method; + service.host = address.hostname; + service.port = (uint16) address.port; + service.transport_security = this.smtp_tls.value.method; - if (service.port == 0) { - service.port = service.get_default_port(); - } + if (service.port == 0) { + service.port = service.get_default_port(); } return service; } private void check_validation() { + bool server_settings_visible = this.stack.get_visible_child_name() == "server_settings"; bool controls_valid = true; - foreach (Gtk.ListBox list in new Gtk.ListBox[] { + Gtk.ListBox[] list_boxes; + if (server_settings_visible) { + list_boxes = new Gtk.ListBox[] { this.details_list, this.receiving_list, this.sending_list - }) { - list.foreach((child) => { + }; + } else { + list_boxes = new Gtk.ListBox[] { this.details_list }; + } + foreach (Gtk.ListBox list_box in list_boxes) { + list_box.foreach((child) => { AddPaneRow? validatable = child as AddPaneRow; if (validatable != null && !validatable.validator.is_valid) { controls_valid = false; } }); } - this.create_button.set_sensitive(controls_valid); + this.action_button.set_sensitive(controls_valid); this.controls_valid = controls_valid; } private void update_operation_ui(bool is_running) { - this.create_spinner.visible = is_running; - this.create_spinner.active = is_running; - this.create_button.sensitive = !is_running; + this.action_spinner.visible = is_running; + this.action_spinner.active = is_running; + this.action_button.sensitive = !is_running; this.back_button.sensitive = !is_running; this.sensitive = !is_running; } - private void on_validated(Components.Validator.Trigger reason) { - check_validation(); - if (this.controls_valid && reason == Components.Validator.Trigger.ACTIVATED) { - this.create_button.clicked(); - } + private void switch_to_user_settings() { + this.stack.set_visible_child_name("user_settings"); + this.action_button.set_label(_("_Next")); + this.action_button.set_sensitive(true); + this.action_button.get_style_context().remove_class("suggested-action"); } - private void on_activated() { - if (this.controls_valid) { - this.create_button.clicked(); - } + private void switch_to_server_settings() { + this.stack.set_visible_child_name("server_settings"); + this.action_button.set_label(_("_Create")); + this.action_button.set_sensitive(false); + this.action_button.get_style_context().add_class("suggested-action"); } - private void on_email_changed() { - Gtk.Entry imap_login_entry = this.imap_login.value; - Gtk.Entry smtp_login_entry = this.smtp_login.value; + private void set_server_settings_from_autoconfig(AutoConfig auto_config, + GLib.AsyncResult res) + throws Accounts.AutoConfigError { + AutoConfigValues auto_config_values = auto_config.get_config.end(res); Gtk.Entry imap_hostname_entry = this.imap_hostname.value; Gtk.Entry smtp_hostname_entry = this.smtp_hostname.value; - string email = ""; - string hostname = ""; - string imap_hostname = ""; - string smtp_hostname = ""; + TlsComboBox imap_tls_combo_box = this.imap_tls.value; + TlsComboBox smtp_tls_combo_box = this.smtp_tls.value; + + imap_hostname_entry.text = auto_config_values.imap_server + + ":" + auto_config_values.imap_port; + smtp_hostname_entry.text = auto_config_values.smtp_server + + ":" + auto_config_values.smtp_port; + imap_tls_combo_box.method = auto_config_values.imap_tls_method; + smtp_tls_combo_box.method = auto_config_values.smtp_tls_method; + + this.imap_hostname.hide(); + this.smtp_hostname.hide(); + this.imap_tls.hide(); + this.smtp_tls.hide(); + + switch (auto_config_values.id) { + case "googlemail.com": + this.provider = Geary.ServiceProvider.GMAIL; + break; + case "hotmail.com": + this.provider = Geary.ServiceProvider.OUTLOOK; + break; + default: + this.provider = Geary.ServiceProvider.OTHER; + break; + } + } + + private void set_server_settings_from_hostname(string hostname) { + Gtk.Entry imap_hostname_entry = this.imap_hostname.value; + Gtk.Entry smtp_hostname_entry = this.smtp_hostname.value; + string smtp_hostname = "smtp." + hostname; + string imap_hostname = "imap." + hostname; string last_imap_hostname = ""; string last_smtp_hostname = ""; - if (this.email.validator.state == Components.Validator.Validity.VALID) { - email = this.email.value.text; - hostname = email.split("@")[1]; - smtp_hostname = "smtp." + hostname; - imap_hostname = "imap." + hostname; - } - - if (imap_login_entry.text == this.last_valid_email) { - imap_login_entry.text = email; - } - if (smtp_login_entry.text == this.last_valid_email) { - smtp_login_entry.text = email; - } + this.imap_hostname.show(); + this.smtp_hostname.show(); if (this.last_valid_hostname != "") { last_imap_hostname = "imap." + this.last_valid_hostname; @@ -437,9 +436,102 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { if (smtp_hostname_entry.text == last_smtp_hostname) { smtp_hostname_entry.text = smtp_hostname; } + this.last_valid_hostname = hostname; + } + + private void add_goa_account() { + this.accounts.add_goa_account.begin( + this.provider, this.op_cancellable, + (obj, res) => { + bool add_local = false; + try { + this.accounts.add_goa_account.end(res); + } catch (GLib.IOError.NOT_SUPPORTED err) { + // Not a supported type, so don't bother logging the error + add_local = true; + } catch (GLib.Error err) { + debug("Failed to add %s via GOA: %s", + this.provider.to_string(), err.message); + add_local = true; + } + // Google Mail does not support "Less secure apps" anymore + if (add_local) { + switch (this.provider) { + case Geary.ServiceProvider.GMAIL: + this.editor.add_notification( + new Components.InAppNotification( + // Translators: In-app notification label, when + // GNOME Online Accounts are missing + _("Online accounts are missing") + ) + ); + add_local = false; + break; + default: + break; + } + } + + if (add_local) { + switch_to_server_settings(); + } else { + this.editor.pop(); + } + } + ); + } + + private void on_validated(Components.Validator.Trigger reason) { + check_validation(); + if (this.controls_valid && reason == Components.Validator.Trigger.ACTIVATED) { + this.action_button.clicked(); + } + } + + private void on_activated() { + if (this.controls_valid) { + this.action_button.clicked(); + } + } + + private void on_email_changed() { + Gtk.Entry imap_login_entry = this.imap_login.value; + Gtk.Entry smtp_login_entry = this.smtp_login.value; + + this.auto_config_cancellable.cancel(); + + if (this.email.validator.state != Components.Validator.Validity.VALID) { + return; + } + + string email = this.email.value.text; + string hostname = email.split("@")[1]; + + // Do not update entries if changed by user + if (imap_login_entry.text == this.last_valid_email) { + imap_login_entry.text = email; + } + if (smtp_login_entry.text == this.last_valid_email) { + smtp_login_entry.text = email; + } this.last_valid_email = email; - this.last_valid_hostname = hostname; + + // Try to get configuration from Thunderbird autoconfig service + this.action_spinner.visible = true; + this.action_spinner.active = true; + this.auto_config_cancellable = new GLib.Cancellable(); + var auto_config = new AutoConfig(this.auto_config_cancellable); + auto_config.get_config.begin(hostname, (obj, res) => { + try { + set_server_settings_from_autoconfig(auto_config, res); + } catch (Accounts.AutoConfigError err) { + debug("Error getting auto configuration: %s", err.message); + set_server_settings_from_hostname(hostname); + } + this.action_spinner.visible = false; + this.action_spinner.active = false; + }); } private void on_smtp_auth_changed() { @@ -474,13 +566,29 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane { } [GtkCallback] - private void on_create_button_clicked() { - this.validate_account.begin(this.op_cancellable); + private void on_action_button_clicked() { + if (this.stack.get_visible_child_name() == "user_settings") { + switch (this.provider) { + case Geary.ServiceProvider.GMAIL: + case Geary.ServiceProvider.OUTLOOK: + add_goa_account(); + break; + case Geary.ServiceProvider.OTHER: + switch_to_server_settings(); + break; + } + } else { + this.validate_account.begin(this.op_cancellable); + } } [GtkCallback] private void on_back_button_clicked() { - this.editor.pop(); + if (this.stack.get_visible_child_name() == "user_settings") { + this.editor.pop(); + } else { + switch_to_user_settings(); + } } [GtkCallback] diff --git a/src/client/accounts/accounts-editor-list-pane.vala b/src/client/accounts/accounts-editor-list-pane.vala index c156eeaf..2f0918d8 100644 --- a/src/client/accounts/accounts-editor-list-pane.vala +++ b/src/client/accounts/accounts-editor-list-pane.vala @@ -31,7 +31,7 @@ internal class Accounts.EditorListPane : Gtk.Grid, EditorPane, CommandPane { /** {@inheritDoc} */ internal Gtk.Widget initial_widget { get { - return this.show_welcome ? this.service_list : this.accounts_list; + return this.accounts_list; } } @@ -73,10 +73,6 @@ internal class Accounts.EditorListPane : Gtk.Grid, EditorPane, CommandPane { [GtkChild] private unowned Gtk.Frame accounts_list_frame; - [GtkChild] private unowned Gtk.Label add_service_label; - - [GtkChild] private unowned Gtk.ListBox service_list; - private Gee.Map edit_pane_cache = new Gee.HashMap(); @@ -97,12 +93,6 @@ internal class Accounts.EditorListPane : Gtk.Grid, EditorPane, CommandPane { add_account(account, this.accounts.get_status(account)); } - this.service_list.set_header_func(Editor.seperator_headers); - this.service_list.add(new AddServiceProviderRow(Geary.ServiceProvider.GMAIL)); - this.service_list.add(new AddServiceProviderRow(Geary.ServiceProvider.OUTLOOK)); - this.service_list.add(new AddServiceProviderRow(Geary.ServiceProvider.YAHOO)); - this.service_list.add(new AddServiceProviderRow(Geary.ServiceProvider.OTHER)); - this.accounts.account_added.connect(on_account_added); this.accounts.account_status_changed.connect(on_account_status_changed); this.accounts.account_removed.connect(on_account_removed); @@ -128,8 +118,8 @@ internal class Accounts.EditorListPane : Gtk.Grid, EditorPane, CommandPane { base.destroy(); } - internal void show_new_account(Geary.ServiceProvider provider) { - this.editor.push(new EditorAddPane(this.editor, provider)); + internal void show_new_account() { + this.editor.push(new EditorAddPane(this.editor)); } internal void show_existing_account(Geary.AccountInformation account) { @@ -171,13 +161,11 @@ internal class Accounts.EditorListPane : Gtk.Grid, EditorPane, CommandPane { // pane and service list. this.welcome_panel.show(); this.accounts_list_frame.hide(); - this.add_service_label.hide(); } else { // There are some accounts available, so show them and // the full add service UI. this.welcome_panel.hide(); this.accounts_list_frame.show(); - this.add_service_label.show(); } } @@ -266,21 +254,9 @@ internal class Accounts.EditorListPane : Gtk.Grid, EditorPane, CommandPane { } [GtkCallback] - private bool on_list_keynav_failed(Gtk.Widget widget, - Gtk.DirectionType direction) { - bool ret = Gdk.EVENT_PROPAGATE; - if (direction == Gtk.DirectionType.DOWN && - widget == this.accounts_list) { - this.service_list.child_focus(direction); - ret = Gdk.EVENT_STOP; - } else if (direction == Gtk.DirectionType.UP && - widget == this.service_list) { - this.accounts_list.child_focus(direction); - ret = Gdk.EVENT_STOP; - } - return ret; + private void on_add_button_clicked() { + show_new_account(); } - } @@ -424,75 +400,6 @@ private class Accounts.AccountListRow : AccountRow { } -private class Accounts.AddServiceProviderRow : EditorRow { - - - internal Geary.ServiceProvider provider; - - private Gtk.Label service_name = new Gtk.Label(""); - private Gtk.Image next_icon = new Gtk.Image.from_icon_name( - "go-next-symbolic", Gtk.IconSize.SMALL_TOOLBAR - ); - - - public AddServiceProviderRow(Geary.ServiceProvider provider) { - this.provider = provider; - - // Translators: Label for adding a generic email account - string? name = null; - switch (provider) { - case Geary.ServiceProvider.GMAIL: - name = _("Gmail"); - break; - - case Geary.ServiceProvider.OUTLOOK: - name = _("Outlook.com"); - break; - - case Geary.ServiceProvider.YAHOO: - name = _("Yahoo"); - break; - - case Geary.ServiceProvider.OTHER: - name = _("Other email providers"); - break; - } - this.service_name.set_text(name); - this.service_name.set_hexpand(true); - this.service_name.halign = Gtk.Align.START; - this.service_name.show(); - - this.next_icon.show(); - - this.layout.add(this.service_name); - this.layout.add(this.next_icon); - } - - public override void activated(EditorListPane pane) { - pane.accounts.add_goa_account.begin( - this.provider, pane.op_cancellable, - (obj, res) => { - bool add_local = false; - try { - pane.accounts.add_goa_account.end(res); - } catch (GLib.IOError.NOT_SUPPORTED err) { - // Not a supported type, so don't bother logging the error - add_local = true; - } catch (GLib.Error err) { - debug("Failed to add %s via GOA: %s", - this.provider.to_string(), err.message); - add_local = true; - } - - if (add_local) { - pane.show_new_account(this.provider); - } - }); - } - -} - - internal class Accounts.ReorderAccountCommand : Application.Command { diff --git a/src/client/meson.build b/src/client/meson.build index 71535832..18ad1ecb 100644 --- a/src/client/meson.build +++ b/src/client/meson.build @@ -34,6 +34,7 @@ client_vala_sources = files( 'application/goa-mediator.vala', 'application/secret-mediator.vala', + 'accounts/accounts-autoconfig.vala', 'accounts/accounts-editor.vala', 'accounts/accounts-editor-add-pane.vala', 'accounts/accounts-editor-edit-pane.vala', diff --git a/ui/accounts_editor_add_pane.ui b/ui/accounts_editor_add_pane.ui index cfe25902..8a38f67a 100644 --- a/ui/accounts_editor_add_pane.ui +++ b/ui/accounts_editor_add_pane.ui @@ -7,34 +7,29 @@ Add an account False - + True + True + - + True - True - - - - True - True - go-previous-symbolic - - + True + go-previous-symbolic - - 0 - 0 - + + start + 1 + True 12 - + True @@ -43,16 +38,13 @@ - - _Create + + _Next True False True True - - + 1 @@ -89,13 +81,14 @@ True 24 - + True True 0 in + start True @@ -105,102 +98,98 @@ - 0 - 0 + user_settings - + True + vertical - + True - start - Receiving - - - - - - - 0 - 0 - - - - - True - 0 - in - + True - none - + start + Receiving + + + + + + 0 + 0 + + + + + True + 0 + in + + + True + none + + + + + + 0 + 1 + + + + + + + True + + + True + start + Sending + + + + + + + 0 + 0 + + + + + True + 0 + in + + + True + none + + + + + + 0 + 1 + - - 0 - 1 - - 0 - 1 + server_settings - - - True - - - True - start - Sending - - - - - - - 0 - 0 - - - - - True - 0 - in - - - True - none - - - - - - 0 - 1 - - - - - 0 - 2 - - - - diff --git a/ui/accounts_editor_list_pane.ui b/ui/accounts_editor_list_pane.ui index 2f5e6af2..975853a4 100644 --- a/ui/accounts_editor_list_pane.ui +++ b/ui/accounts_editor_list_pane.ui @@ -7,6 +7,19 @@ Accounts False True + + + _Add + Add an account + True + True + True + + + + 100 @@ -103,7 +116,6 @@ True none - @@ -115,53 +127,9 @@ 1 - - - True - start - Add an account - - - - - - - 0 - 2 - - - - - True - start - True - True - 0 - in - - - 0 - True - start - none - - - - - - - - - 0 - 3 - - -