[geary/wip/714104-refine-account-dialog] Clean up AccountInformation and ServiceInformation APIs



commit 1bccd51a25e7dca0ec9347d0893cea544e641d57
Author: Michael Gratton <mike vee net>
Date:   Sun Dec 9 10:11:03 2018 +1100

    Clean up AccountInformation and ServiceInformation APIs
    
    Remove remaining crufty properties left over from pulling accounts out
    of the engine, rename imap/smtp to incoming/outgoing since maybe one
    day other protocols or implementations will be supported. Remove the
    old pairs of properties for TLS and SMTP auth, replace the
    SmtpCredentials enum with something that is also independent of
    protocol.

 src/client/accounts/accounts-editor-add-pane.vala  |  42 +--
 src/client/accounts/accounts-editor-edit-pane.vala |  36 +--
 src/client/accounts/accounts-editor-list-pane.vala |  16 +-
 .../accounts/accounts-editor-remove-pane.vala      |   6 +-
 src/client/accounts/accounts-editor-row.vala       |  46 +--
 .../accounts/accounts-editor-servers-pane.vala     |  57 ++--
 src/client/accounts/accounts-editor.vala           |   2 +-
 src/client/accounts/accounts-manager.vala          | 147 +++++----
 src/client/application/geary-controller.vala       |  20 +-
 src/client/application/goa-mediator.vala           |   8 +-
 src/client/application/secret-mediator.vala        |   2 +-
 src/client/components/main-window.vala             |   3 +-
 src/client/components/search-bar.vala              |  32 +-
 src/client/composer/composer-widget.vala           |   4 +-
 src/client/dialogs/password-dialog.vala            |   2 +-
 .../folder-list/folder-list-account-branch.vala    |  30 +-
 .../folder-list-inbox-folder-entry.vala            |  28 +-
 .../folder-list/folder-list-search-branch.vala     |   2 +-
 src/client/util/util-migrate.vala                  |   2 +-
 src/engine/api/geary-account-information.vala      | 337 +++++++++++----------
 src/engine/api/geary-credentials.vala              |  27 ++
 src/engine/api/geary-engine.vala                   |  40 +--
 src/engine/api/geary-service-information.vala      | 139 ++-------
 .../gmail/imap-engine-gmail-account.vala           |   4 +-
 .../imap-engine-account-synchronizer.vala          |   2 +-
 .../imap-engine/imap-engine-generic-account.vala   |  17 +-
 .../outlook/imap-engine-outlook-account.vala       |   5 +-
 .../yahoo/imap-engine-yahoo-account.vala           |   4 +-
 src/engine/smtp/smtp-client-service.vala           |   8 +-
 src/engine/util/util-config-file.vala              |   3 +
 test/client/accounts/accounts-manager-test.vala    |  50 +--
 test/engine/api/geary-account-mock.vala            |   4 +-
 32 files changed, 538 insertions(+), 587 deletions(-)
---
diff --git a/src/client/accounts/accounts-editor-add-pane.vala 
b/src/client/accounts/accounts-editor-add-pane.vala
index ad07d298..6b28061b 100644
--- a/src/client/accounts/accounts-editor-add-pane.vala
+++ b/src/client/accounts/accounts-editor-add-pane.vala
@@ -168,10 +168,8 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane {
                 )
             );
 
-        account.imap = new_imap_service();
-        account.imap = new_smtp_service();
-
-        account.nickname = account.primary_mailbox.address;
+        account.incoming = new_imap_service();
+        account.outgoing = new_smtp_service();
 
         if (this.provider == Geary.ServiceProvider.OTHER) {
             bool imap_valid = false;
@@ -179,7 +177,7 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane {
 
             try {
                 yield this.engine.validate_imap(
-                    account, account.imap, cancellable
+                    account, account.incoming, cancellable
                 );
                 imap_valid = true;
             } catch (Geary.ImapError.UNAUTHENTICATED err) {
@@ -200,8 +198,8 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane {
                 try {
                     yield this.engine.validate_smtp(
                         account,
-                        account.smtp,
-                        account.imap.credentials,
+                        account.outgoing,
+                        account.incoming.credentials,
                         cancellable
                     );
                     smtp_valid = true;
@@ -210,7 +208,8 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane {
                     // There was an SMTP auth error, but IMAP already
                     // succeeded, so the user probably needs to
                     // specify custom creds here
-                    this.smtp_auth.value.source = Geary.SmtpCredentials.CUSTOM;
+                    this.smtp_auth.value.source =
+                        Geary.Credentials.Requirement.CUSTOM;
                     to_focus = this.smtp_login.value;
                     // Translators: In-app notification label
                     message = _("Check your sending login and password");
@@ -227,7 +226,7 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane {
         } else {
             try {
                 yield this.engine.validate_imap(
-                    account, account.imap, cancellable
+                    account, account.incoming, cancellable
                 );
                 is_valid = true;
             } catch (Geary.ImapError.UNAUTHENTICATED err) {
@@ -316,26 +315,14 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane {
             new Geary.ServiceInformation(Geary.Protocol.SMTP);
 
         if (this.provider == Geary.ServiceProvider.OTHER) {
-            switch (this.smtp_auth.value.source) {
-            case Geary.SmtpCredentials.NONE:
-                service.smtp_noauth = true;
-                service.smtp_use_imap_credentials = false;
-                break;
-
-            case Geary.SmtpCredentials.IMAP:
-                service.smtp_noauth = false;
-                service.smtp_use_imap_credentials = true;
-                break;
-
-            case Geary.SmtpCredentials.CUSTOM:
-                service.smtp_noauth = false;
-                service.smtp_use_imap_credentials = false;
+            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()
                 );
-                break;
             }
 
             Components.NetworkAddressValidator host =
@@ -350,9 +337,6 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane {
             if (service.port == 0) {
                 service.port = service.get_default_port();
             }
-
-            debug("SMTP service: TLS: %s, STARTTLS: %s",
-                  service.use_ssl.to_string(), service.use_starttls.to_string());
         } else {
             this.provider.setup_service(service);
         }
@@ -406,7 +390,7 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane {
     }
 
     private void on_smtp_auth_changed() {
-        if (this.smtp_auth.value.source == Geary.SmtpCredentials.CUSTOM) {
+        if (this.smtp_auth.value.source == Geary.Credentials.Requirement.CUSTOM) {
             this.sending_list.add(this.smtp_login);
             this.sending_list.add(this.smtp_password);
         } else if (this.smtp_login.parent != null) {
@@ -621,7 +605,7 @@ private class Accounts.SmtpAuthRow :
         base(value.label, value);
 
         this.activatable = false;
-        this.value.source = Geary.SmtpCredentials.IMAP;
+        this.value.source = Geary.Credentials.Requirement.USE_INCOMING;
     }
 
 }
diff --git a/src/client/accounts/accounts-editor-edit-pane.vala 
b/src/client/accounts/accounts-editor-edit-pane.vala
index 5043c8f1..d6676d01 100644
--- a/src/client/accounts/accounts-editor-edit-pane.vala
+++ b/src/client/accounts/accounts-editor-edit-pane.vala
@@ -59,7 +59,7 @@ internal class Accounts.EditorEditPane : Gtk.Grid, EditorPane, AccountPane {
         this.pane_content.set_focus_vadjustment(this.pane_adjustment);
 
         this.details_list.set_header_func(Editor.seperator_headers);
-        this.details_list.add(new NicknameRow(account));
+        this.details_list.add(new DisplayNameRow(account));
 
         this.senders_list.set_header_func(Editor.seperator_headers);
         foreach (Geary.RFC822.MailboxAddress sender in
@@ -101,7 +101,7 @@ internal class Accounts.EditorEditPane : Gtk.Grid, EditorPane, AccountPane {
 
         this.signature_preview.show();
         this.signature_preview.load_html(
-            Geary.HTML.smart_escape(account.email_signature)
+            Geary.HTML.smart_escape(account.signature)
         );
 
         this.signature_frame.add(this.signature_preview);
@@ -113,7 +113,7 @@ internal class Accounts.EditorEditPane : Gtk.Grid, EditorPane, AccountPane {
             !this.editor.accounts.is_goa_account(account)
         );
 
-        this.account.information_changed.connect(on_account_changed);
+        this.account.changed.connect(on_account_changed);
         update_header();
 
         this.commands.executed.connect(on_command);
@@ -122,7 +122,7 @@ internal class Accounts.EditorEditPane : Gtk.Grid, EditorPane, AccountPane {
     }
 
     ~EditorEditPane() {
-        this.account.information_changed.disconnect(on_account_changed);
+        this.account.changed.disconnect(on_account_changed);
 
         this.commands.executed.disconnect(on_command);
         this.commands.undone.disconnect(on_command);
@@ -270,10 +270,10 @@ internal class Accounts.EditorEditPane : Gtk.Grid, EditorPane, AccountPane {
 }
 
 
-private class Accounts.NicknameRow : AccountRow<EditorEditPane,Gtk.Label> {
+private class Accounts.DisplayNameRow : AccountRow<EditorEditPane,Gtk.Label> {
 
 
-    public NicknameRow(Geary.AccountInformation account) {
+    public DisplayNameRow(Geary.AccountInformation account) {
         base(
             account,
             // Translators: Label in the account editor for the user's
@@ -287,7 +287,7 @@ private class Accounts.NicknameRow : AccountRow<EditorEditPane,Gtk.Label> {
     public override void activated(EditorEditPane pane) {
         EditorPopover popover = new EditorPopover();
 
-        string? value = this.account.nickname;
+        string? value = this.account.display_name;
         Gtk.Entry entry = new Gtk.Entry();
         entry.set_text(value ?? "");
         entry.set_placeholder_text(value ?? "");
@@ -297,7 +297,7 @@ private class Accounts.NicknameRow : AccountRow<EditorEditPane,Gtk.Label> {
                     new PropertyCommand<string>(
                         this.account,
                         this.account,
-                        Geary.AccountInformation.PROP_NICKNAME,
+                        "label",
                         entry.get_text(),
                         // Translators: Tooltip used to undo changing
                         // the name of an account. The string
@@ -317,7 +317,7 @@ private class Accounts.NicknameRow : AccountRow<EditorEditPane,Gtk.Label> {
     }
 
     public override void update() {
-        this.value.set_text(this.account.nickname);
+        this.value.set_text(this.account.display_name);
     }
 
 }
@@ -559,13 +559,13 @@ internal class Accounts.AppendMailboxCommand : Application.Command {
     public async override void execute(GLib.Cancellable? cancellable) {
         this.senders_list.insert(this.new_row, this.mailbox_index);
         this.new_row.account.append_sender(this.new_row.mailbox);
-        this.new_row.account.information_changed();
+        this.new_row.account.changed();
     }
 
     public async override void undo(GLib.Cancellable? cancellable) {
         this.senders_list.remove(this.new_row);
         this.new_row.account.remove_sender(this.new_row.mailbox);
-        this.new_row.account.information_changed();
+        this.new_row.account.changed();
     }
 
 }
@@ -602,14 +602,14 @@ internal class Accounts.UpdateMailboxCommand : Application.Command {
         this.row.mailbox = this.new_mailbox;
         this.row.account.remove_sender(this.old_mailbox);
         this.row.account.insert_sender(this.mailbox_index, this.new_mailbox);
-        this.row.account.information_changed();
+        this.row.account.changed();
     }
 
     public async override void undo(GLib.Cancellable? cancellable) {
         this.row.mailbox = this.old_mailbox;
         this.row.account.remove_sender(this.new_mailbox);
         this.row.account.insert_sender(this.mailbox_index, this.old_mailbox);
-        this.row.account.information_changed();
+        this.row.account.changed();
     }
 
 }
@@ -688,13 +688,13 @@ internal class Accounts.RemoveMailboxCommand : Application.Command {
     public async override void execute(GLib.Cancellable? cancellable) {
         this.list.remove(this.row);
         this.row.account.remove_sender(this.mailbox);
-        this.row.account.information_changed();
+        this.row.account.changed();
     }
 
     public async override void undo(GLib.Cancellable? cancellable) {
         this.list.insert(this.row, this.mailbox_index);
         this.row.account.insert_sender(this.mailbox_index, this.mailbox);
-        this.row.account.information_changed();
+        this.row.account.changed();
     }
 
 }
@@ -715,7 +715,7 @@ internal class Accounts.SignatureChangedCommand : Application.Command {
         this.signature_view = signature_view;
         this.account = account;
 
-        this.old_value = Geary.HTML.smart_escape(account.email_signature);
+        this.old_value = Geary.HTML.smart_escape(account.signature);
 
         // Translators: Label used as the undo tooltip after removing
         // a sender address from an account. The string substitution
@@ -740,8 +740,8 @@ internal class Accounts.SignatureChangedCommand : Application.Command {
     }
 
     private inline void update_account_signature(string value) {
-        this.account.email_signature = value;
-        this.account.information_changed();
+        this.account.signature = value;
+        this.account.changed();
     }
 
 }
diff --git a/src/client/accounts/accounts-editor-list-pane.vala 
b/src/client/accounts/accounts-editor-list-pane.vala
index 71f1958b..4d47ccba 100644
--- a/src/client/accounts/accounts-editor-list-pane.vala
+++ b/src/client/accounts/accounts-editor-list-pane.vala
@@ -310,13 +310,13 @@ private class Accounts.AccountListRow : AccountRow<EditorListPane,Gtk.Grid> {
 
         this.service_label.show();
 
-        this.account.information_changed.connect(on_account_changed);
+        this.account.changed.connect(on_account_changed);
         update();
         update_status(status);
     }
 
     ~AccountListRow() {
-        this.account.information_changed.disconnect(on_account_changed);
+        this.account.changed.disconnect(on_account_changed);
     }
 
     public override void activated(EditorListPane pane) {
@@ -345,7 +345,7 @@ private class Accounts.AccountListRow : AccountRow<EditorListPane,Gtk.Grid> {
     }
 
     public override void update() {
-        string name = this.account.nickname;
+        string name = this.account.display_name;
         if (Geary.String.is_empty(name)) {
             name = account.primary_mailbox.to_address_display("", "");
         }
@@ -513,7 +513,7 @@ internal class Accounts.ReorderAccountCommand : Application.Command {
         foreach (Geary.AccountInformation account in accounts) {
             if (account.ordinal != ord) {
                 account.ordinal = ord;
-                account.information_changed();
+                account.changed();
             }
             ord++;
         }
@@ -539,12 +539,16 @@ internal class Accounts.RemoveAccountCommand : Application.Command {
         // Translators: Notification shown after removing an
         // account. The string substitution is the name of the
         // account.
-        this.executed_label = _("Account “%s” removed").printf(account.nickname);
+        this.executed_label = _("Account “%s” removed").printf(
+            account.display_name
+        );
 
         // Translators: Notification shown after removing an account
         // is undone. The string substitution is the name of the
         // account.
-        this.undone_label = _("Account “%s” restored").printf(account.nickname);
+        this.undone_label = _("Account “%s” restored").printf(
+            account.display_name
+        );
     }
 
     public async override void execute(GLib.Cancellable? cancellable)
diff --git a/src/client/accounts/accounts-editor-remove-pane.vala 
b/src/client/accounts/accounts-editor-remove-pane.vala
index d8976205..5e212db2 100644
--- a/src/client/accounts/accounts-editor-remove-pane.vala
+++ b/src/client/accounts/accounts-editor-remove-pane.vala
@@ -28,15 +28,15 @@ internal class Accounts.EditorRemovePane : Gtk.Grid, EditorPane, AccountPane {
         this.account = account;
 
         this.warning_label.set_text(
-            this.warning_label.get_text().printf(account.nickname)
+            this.warning_label.get_text().printf(account.display_name)
         );
 
-        this.account.information_changed.connect(on_account_changed);
+        this.account.changed.connect(on_account_changed);
         update_header();
     }
 
     ~EditorRemovePane() {
-        this.account.information_changed.disconnect(on_account_changed);
+        this.account.changed.disconnect(on_account_changed);
     }
 
     internal Gtk.HeaderBar get_header() {
diff --git a/src/client/accounts/accounts-editor-row.vala b/src/client/accounts/accounts-editor-row.vala
index 45f8fe18..247ace9e 100644
--- a/src/client/accounts/accounts-editor-row.vala
+++ b/src/client/accounts/accounts-editor-row.vala
@@ -304,13 +304,13 @@ internal abstract class Accounts.AccountRow<PaneType,V> :
     public AccountRow(Geary.AccountInformation account, string label, V value) {
         base(label, value);
         this.account = account;
-        this.account.information_changed.connect(on_account_changed);
+        this.account.changed.connect(on_account_changed);
 
         set_dim_label(true);
     }
 
     ~AccountRow() {
-        this.account.information_changed.disconnect(on_account_changed);
+        this.account.changed.disconnect(on_account_changed);
     }
 
     public abstract void update();
@@ -449,12 +449,12 @@ internal class Accounts.SmtpAuthComboBox : Gtk.ComboBoxText {
 
     public string label { get; private set; }
 
-    public Geary.SmtpCredentials source {
+    public Geary.Credentials.Requirement source {
         get {
             try {
-                return Geary.SmtpCredentials.for_value(this.active_id);
+                return Geary.Credentials.Requirement.for_value(this.active_id);
             } catch {
-                return Geary.SmtpCredentials.IMAP;
+                return Geary.Credentials.Requirement.USE_INCOMING;
             }
         }
         set {
@@ -469,19 +469,29 @@ internal class Accounts.SmtpAuthComboBox : Gtk.ComboBoxText {
         // account
         this.label = _("Login");
 
-        // Translators: ComboBox value for source of SMTP
-        // authentication credentials (none) when adding a new account
-        append(Geary.SmtpCredentials.NONE.to_value(), _("No login needed"));
+        append(
+            Geary.Credentials.Requirement.NONE.to_value(),
+            // Translators: ComboBox value for source of SMTP
+            // authentication credentials (none) when adding a new
+            // account
+            _("No login needed")
+        );
 
-        // Translators: ComboBox value for source of SMTP
-        // authentication credentials (use IMAP) when adding a new
-        // account
-        append(Geary.SmtpCredentials.IMAP.to_value(), _("Use IMAP login"));
+        append(
+            Geary.Credentials.Requirement.USE_INCOMING.to_value(),
+            // Translators: ComboBox value for source of SMTP
+            // authentication credentials (use IMAP) when adding a new
+            // account
+            _("Use incoming server login")
+        );
 
-        // Translators: ComboBox value for source of SMTP
-        // authentication credentials (custom) when adding a new
-        // account
-        append(Geary.SmtpCredentials.CUSTOM.to_value(), _("Use different login"));
+        append(
+            Geary.Credentials.Requirement.CUSTOM.to_value(),
+            // Translators: ComboBox value for source of SMTP
+            // authentication credentials (custom) when adding a new
+            // account
+            _("Use different login")
+        );
     }
 
 }
@@ -626,12 +636,12 @@ internal class PropertyCommand<T> : Application.Command {
 
     public async override void execute(GLib.Cancellable? cancellable) {
         this.object.set(this.property_name, this.new_value);
-        this.account.information_changed();
+        this.account.changed();
     }
 
     public async override void undo(GLib.Cancellable? cancellable) {
         this.object.set(this.property_name, this.old_value);
-        this.account.information_changed();
+        this.account.changed();
     }
 
 }
diff --git a/src/client/accounts/accounts-editor-servers-pane.vala 
b/src/client/accounts/accounts-editor-servers-pane.vala
index 09dd5aef..6d488acc 100644
--- a/src/client/accounts/accounts-editor-servers-pane.vala
+++ b/src/client/accounts/accounts-editor-servers-pane.vala
@@ -3,7 +3,7 @@
  * Copyright 2018 Michael Gratton <mike vee net>
  *
  * This software is licensed under the GNU Lesser General Public License
- * (version 2.1 or later).  See the COPYING file in this distribution.
+ * (version 2.1 or later). See the COPYING file in this distribution.
  */
 
 /**
@@ -21,8 +21,8 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
 
     // These are copies of the originals that can be updated before
     // validating on apply, without breaking anything.
-    private Geary.ServiceInformation imap_mutable;
-    private Geary.ServiceInformation smtp_mutable;
+    private Geary.ServiceInformation incoming_mutable;
+    private Geary.ServiceInformation outgoing_mutable;
 
 
     [GtkChild]
@@ -61,8 +61,8 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
         this.editor = editor;
         this.account = account;
         this.engine = ((GearyApplication) editor.application).engine;
-        this.imap_mutable = new Geary.ServiceInformation.copy(account.imap);
-        this.smtp_mutable = new Geary.ServiceInformation.copy(account.smtp);
+        this.incoming_mutable = new Geary.ServiceInformation.copy(account.incoming);
+        this.outgoing_mutable = new Geary.ServiceInformation.copy(account.outgoing);
 
         this.pane_content.set_focus_vadjustment(this.pane_adjustment);
 
@@ -85,29 +85,29 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
         this.details_list.add(this.save_drafts);
 
         this.receiving_list.set_header_func(Editor.seperator_headers);
-        this.receiving_list.add(new ServiceHostRow(account, this.imap_mutable));
-        this.receiving_list.add(new ServiceSecurityRow(account, this.imap_mutable));
-        this.receiving_list.add(new ServiceLoginRow(account, this.imap_mutable));
+        this.receiving_list.add(new ServiceHostRow(account, this.incoming_mutable));
+        this.receiving_list.add(new ServiceSecurityRow(account, this.incoming_mutable));
+        this.receiving_list.add(new ServiceLoginRow(account, this.incoming_mutable));
 
         this.sending_list.set_header_func(Editor.seperator_headers);
-        this.sending_list.add(new ServiceHostRow(account, this.smtp_mutable));
-        this.sending_list.add(new ServiceSecurityRow(account, this.smtp_mutable));
+        this.sending_list.add(new ServiceHostRow(account, this.outgoing_mutable));
+        this.sending_list.add(new ServiceSecurityRow(account, this.outgoing_mutable));
         this.smtp_auth = new ServiceSmtpAuthRow(
-            account, this.smtp_mutable, this.imap_mutable
+            account, this.outgoing_mutable, this.incoming_mutable
         );
         this.smtp_auth.value.changed.connect(on_smtp_auth_changed);
         this.sending_list.add(this.smtp_auth);
-        this.smtp_login = new ServiceLoginRow(account, this.smtp_mutable);
+        this.smtp_login = new ServiceLoginRow(account, this.outgoing_mutable);
         this.sending_list.add(this.smtp_login);
 
-        this.account.information_changed.connect(on_account_changed);
+        this.account.changed.connect(on_account_changed);
 
         update_header();
         update_smtp_auth();
     }
 
     ~EditorServersPane() {
-        this.account.information_changed.disconnect(on_account_changed);
+        this.account.changed.disconnect(on_account_changed);
     }
 
     internal Gtk.HeaderBar get_header() {
@@ -128,10 +128,10 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
             if (is_valid) {
                 try {
                     has_changed = this.engine.update_account_service(
-                        this.account, imap_mutable
+                        this.account, incoming_mutable
                     );
                     has_changed = this.engine.update_account_service(
-                        this.account, smtp_mutable
+                        this.account, outgoing_mutable
                     );
                 } catch (Geary.EngineError err) {
                     warning("Could not update account services: %s", err.message);
@@ -146,7 +146,7 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
             }
 
             if (has_changed) {
-                this.account.information_changed();
+                this.account.changed();
             }
 
             this.editor.pop();
@@ -162,7 +162,7 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
         bool imap_valid = false;
         try {
             yield this.engine.validate_imap(
-                this.account, this.imap_mutable, cancellable
+                this.account, this.incoming_mutable, cancellable
             );
             imap_valid = true;
         } catch (Geary.ImapError.UNAUTHENTICATED err) {
@@ -181,8 +181,8 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
             try {
                 yield this.engine.validate_smtp(
                     this.account,
-                    this.smtp_mutable,
-                    this.imap_mutable.credentials,
+                    this.outgoing_mutable,
+                    this.incoming_mutable.credentials,
                     cancellable
                 );
                 smtp_valid = true;
@@ -191,7 +191,7 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
                 // There was an SMTP auth error, but IMAP already
                 // succeeded, so the user probably needs to
                 // specify custom creds here
-                this.smtp_auth.value.source = Geary.SmtpCredentials.CUSTOM;
+                this.smtp_auth.value.source = Geary.Credentials.Requirement.CUSTOM;
                 // Translators: In-app notification label
                 message = _("Check your sending login and password");
             } catch (GLib.Error err) {
@@ -224,7 +224,7 @@ internal class Accounts.EditorServersPane : Gtk.Grid, EditorPane, AccountPane {
 
     private void update_smtp_auth() {
         this.smtp_login.set_visible(
-            this.smtp_auth.value.source == Geary.SmtpCredentials.CUSTOM
+            this.smtp_auth.value.source == Geary.Credentials.Requirement.CUSTOM
         );
     }
 
@@ -575,8 +575,9 @@ private class Accounts.ServiceLoginRow :
 
             label = method.printf(login);
         } else if (this.service.protocol == Geary.Protocol.SMTP &&
-                   this.service.smtp_use_imap_credentials) {
-            label = _("Use IMAP login");
+                   this.service.credentials_requirement ==
+                   Geary.Credentials.Requirement.USE_INCOMING) {
+            label = _("Use incoming server login");
         } else {
             // Translators: Label used when no auth scheme is used
             // by an account's IMAP or SMTP service.
@@ -614,11 +615,11 @@ private class Accounts.ServiceSmtpAuthRow :
     }
 
     public override void update() {
-        this.value.source = this.service.smtp_credentials_source;
+        this.value.source = this.service.credentials_requirement;
     }
 
     private void on_value_changed() {
-        if (this.service.smtp_credentials_source != this.value.source) {
+        if (this.service.credentials_requirement != this.value.source) {
             // The default SMTP port also depends on the auth method
             // used, so also update the port here if we're currently
             // using the default, otherwise keep the custom port
@@ -626,9 +627,9 @@ private class Accounts.ServiceSmtpAuthRow :
             bool update_port = (
                 this.service.port == this.service.get_default_port()
             );
-            this.service.smtp_credentials_source = this.value.source;
+            this.service.credentials_requirement = this.value.source;
             this.service.credentials =
-                (this.service.smtp_credentials_source != CUSTOM)
+                (this.service.credentials_requirement != CUSTOM)
                 ? null
                 : new Geary.Credentials(Geary.Credentials.Method.PASSWORD, "");
             if (update_port) {
diff --git a/src/client/accounts/accounts-editor.vala b/src/client/accounts/accounts-editor.vala
index 07da5b0b..296e494a 100644
--- a/src/client/accounts/accounts-editor.vala
+++ b/src/client/accounts/accounts-editor.vala
@@ -216,7 +216,7 @@ internal interface Accounts.AccountPane : Gtk.Grid, EditorPane {
 
 
     protected void update_header() {
-        get_header().subtitle = this.account.nickname;
+        get_header().subtitle = this.account.display_name;
     }
 
 }
diff --git a/src/client/accounts/accounts-manager.vala b/src/client/accounts/accounts-manager.vala
index 319ea1b9..b0baa56a 100644
--- a/src/client/accounts/accounts-manager.vala
+++ b/src/client/accounts/accounts-manager.vala
@@ -109,6 +109,9 @@ public errordomain Accounts.ConfigError {
 public class Accounts.Manager : GLib.Object {
 
 
+    /** The name of the Geary configuration file. */
+    public const string SETTINGS_FILENAME = "geary.ini";
+
     private const string LOCAL_ID_PREFIX = "account_";
     private const string LOCAL_ID_FORMAT = "account_%02u";
     private const string GOA_ID_PREFIX = "goa_";
@@ -312,8 +315,8 @@ public class Accounts.Manager : GLib.Object {
         // if it's a local account, save the passwords now
         SecretMediator? mediator = account.mediator as SecretMediator;
         if (mediator != null) {
-            yield mediator.update_token(account, account.imap, cancellable);
-            yield mediator.update_token(account, account.smtp, cancellable);
+            yield mediator.update_token(account, account.incoming, cancellable);
+            yield mediator.update_token(account, account.outgoing, cancellable);
         }
     }
 
@@ -511,7 +514,7 @@ public class Accounts.Manager : GLib.Object {
         GLib.File data_dir = this.user_data_dir.get_child(id);
 
         Geary.ConfigFile config = new Geary.ConfigFile(
-            config_dir.get_child(Geary.AccountInformation.SETTINGS_FILENAME)
+            config_dir.get_child(SETTINGS_FILENAME)
         );
 
         try {
@@ -537,6 +540,15 @@ public class Accounts.Manager : GLib.Object {
 
         string? goa_id = metadata_config.get_string(METADATA_GOA, null);
         bool is_goa = (goa_id != null);
+
+        // This exists purely for people were running master with GOA
+        // accounts before the new accounts editor landed and 0.13 was
+        // released. It can be removed once 0.14 is out.
+        if (goa_id == null && id.has_prefix(GOA_ID_PREFIX)) {
+            goa_id = to_goa_id(id);
+            is_goa = true;
+        }
+
         GoaMediator? goa_mediator = null;
         Geary.ServiceProvider? default_provider = null;
         Geary.CredentialsMediator mediator = this.libsecret;
@@ -608,8 +620,11 @@ public class Accounts.Manager : GLib.Object {
 
         if (!is_goa) {
             try {
-                services.load(config, account, account.imap);
-                services.load(config, account, account.smtp);
+                services.load(config, account, account.incoming);
+                services.load(config, account, account.outgoing);
+
+                debug("IMAP host name: %s", account.incoming.host);
+
             } catch (GLib.KeyFileError err) {
                 throw new ConfigError.SYNTAX(err.message);
             }
@@ -635,14 +650,15 @@ public class Accounts.Manager : GLib.Object {
     private async void save_account_locked(Geary.AccountInformation account,
                                            GLib.Cancellable? cancellable)
         throws GLib.Error {
-        File? file = account.settings_file;
-        if (file == null) {
+        if (account.config_dir == null) {
             throw new GLib.IOError.NOT_SUPPORTED(
-                "Account %s does not have a settings file", account.id
+                "Account %s does not have a config directory", account.id
             );
         }
 
-        Geary.ConfigFile config = new Geary.ConfigFile(file);
+        Geary.ConfigFile config = new Geary.ConfigFile(
+            account.config_dir.get_child(SETTINGS_FILENAME)
+        );
 
         // Load the file first so we maintain old settings
         try {
@@ -671,11 +687,11 @@ public class Accounts.Manager : GLib.Object {
 
         if (!is_goa) {
             ServiceConfig services = new ServiceConfigV1();
-            services.save(account, account.imap, config);
-            services.save(account, account.smtp, config);
+            services.save(account, account.incoming, config);
+            services.save(account, account.outgoing, config);
         }
 
-        debug("Writing config to: %s", file.get_path());
+        debug("Writing config to: %s", config.file.get_path());
         yield config.save(cancellable);
     }
 
@@ -688,13 +704,13 @@ public class Accounts.Manager : GLib.Object {
         SecretMediator? mediator = info.mediator as SecretMediator;
         if (mediator != null) {
             try {
-                yield mediator.clear_token(info, info.imap, cancellable);
+                yield mediator.clear_token(info, info.incoming, cancellable);
             } catch (Error e) {
                 debug("Error clearing IMAP password: %s", e.message);
             }
 
             try {
-                yield mediator.clear_token(info, info.smtp, cancellable);
+                yield mediator.clear_token(info, info.outgoing, cancellable);
             } catch (Error e) {
                 debug("Error clearing IMAP password: %s", e.message);
             }
@@ -801,7 +817,7 @@ public class Accounts.Manager : GLib.Object {
 
             info.ordinal = Geary.AccountInformation.next_ordinal++;
             info.service_label = mediator.get_service_label();
-            info.nickname = account.get_account().presentation_identity;
+            info.label = account.get_account().presentation_identity;
 
             try {
                 yield create_account_dirs(info, cancellable);
@@ -956,7 +972,7 @@ public class Accounts.AccountConfigV1 : AccountConfig, GLib.Object {
 
     private const string FOLDER_ARCHIVE = "archive_folder";
     private const string FOLDER_DRAFTS = "drafts_folder";
-    private const string FOLDER_SENT = "sent_mail_folder";
+    private const string FOLDER_SENT = "sent_folder";
     private const string FOLDER_SPAM = "spam_folder";
     private const string FOLDER_TRASH = "trash_folder";
 
@@ -1012,8 +1028,8 @@ public class Accounts.AccountConfigV1 : AccountConfig, GLib.Object {
         account.ordinal = account_config.get_int(
             ACCOUNT_ORDINAL, Geary.AccountInformation.next_ordinal++
         );
-        account.nickname = account_config.get_string(
-            ACCOUNT_LABEL, account.nickname
+        account.label = account_config.get_string(
+            ACCOUNT_LABEL, account.label
         );
         account.prefetch_period_days = account_config.get_int(
             ACCOUNT_PREFETCH, account.prefetch_period_days
@@ -1021,14 +1037,14 @@ public class Accounts.AccountConfigV1 : AccountConfig, GLib.Object {
         account.save_drafts = account_config.get_bool(
             ACCOUNT_SAVE_DRAFTS, account.save_drafts
         );
-        account.save_sent_mail = account_config.get_bool(
-            ACCOUNT_SAVE_SENT, account.save_sent_mail
+        account.save_sent = account_config.get_bool(
+            ACCOUNT_SAVE_SENT, account.save_sent
         );
-        account.use_email_signature = account_config.get_bool(
-            ACCOUNT_USE_SIG, account.use_email_signature
+        account.use_signature = account_config.get_bool(
+            ACCOUNT_USE_SIG, account.use_signature
         );
-        account.email_signature = account_config.get_string(
-            ACCOUNT_SIG, account.email_signature
+        account.signature = account_config.get_string(
+            ACCOUNT_SIG, account.signature
         );
         foreach (Geary.RFC822.MailboxAddress sender in senders) {
             account.append_sender(sender);
@@ -1038,7 +1054,7 @@ public class Accounts.AccountConfigV1 : AccountConfig, GLib.Object {
             config.get_group(GROUP_FOLDERS);
         account.archive_folder_path = load_folder(folder_config, FOLDER_ARCHIVE);
         account.drafts_folder_path = load_folder(folder_config, FOLDER_DRAFTS);
-        account.sent_mail_folder_path = load_folder(folder_config, FOLDER_SENT);
+        account.sent_folder_path = load_folder(folder_config, FOLDER_SENT);
         account.spam_folder_path = load_folder(folder_config, FOLDER_SPAM);
         account.trash_folder_path = load_folder(folder_config, FOLDER_TRASH);
 
@@ -1051,12 +1067,12 @@ public class Accounts.AccountConfigV1 : AccountConfig, GLib.Object {
         Geary.ConfigFile.Group account_config =
             config.get_group(GROUP_ACCOUNT);
         account_config.set_int(ACCOUNT_ORDINAL, account.ordinal);
-        account_config.set_string(ACCOUNT_LABEL, account.nickname);
+        account_config.set_string(ACCOUNT_LABEL, account.label);
         account_config.set_int(ACCOUNT_PREFETCH, account.prefetch_period_days);
         account_config.set_bool(ACCOUNT_SAVE_DRAFTS, account.save_drafts);
-        account_config.set_bool(ACCOUNT_SAVE_SENT, account.save_sent_mail);
-        account_config.set_bool(ACCOUNT_USE_SIG, account.use_email_signature);
-        account_config.set_string(ACCOUNT_SIG, account.email_signature);
+        account_config.set_bool(ACCOUNT_SAVE_SENT, account.save_sent);
+        account_config.set_bool(ACCOUNT_USE_SIG, account.use_signature);
+        account_config.set_string(ACCOUNT_SIG, account.signature);
         account_config.set_string_list(
             ACCOUNT_SENDERS,
             Geary.traverse(account.sender_mailboxes)
@@ -1074,7 +1090,7 @@ public class Accounts.AccountConfigV1 : AccountConfig, GLib.Object {
             config.get_group(GROUP_FOLDERS);
         save_folder(folder_config, FOLDER_ARCHIVE, account.archive_folder_path);
         save_folder(folder_config, FOLDER_DRAFTS, account.drafts_folder_path);
-        save_folder(folder_config, FOLDER_SENT, account.sent_mail_folder_path);
+        save_folder(folder_config, FOLDER_SENT, account.sent_folder_path);
         save_folder(folder_config, FOLDER_SPAM, account.spam_folder_path);
         save_folder(folder_config, FOLDER_TRASH, account.trash_folder_path);
     }
@@ -1162,7 +1178,7 @@ public class Accounts.AccountConfigLegacy : AccountConfig, GLib.Object {
             config.get_string(REAL_NAME_KEY), primary_email
         ));
 
-        info.nickname = config.get_string(NICKNAME_KEY);
+        info.label = config.get_string(NICKNAME_KEY);
 
         // Store alternate emails in a list of case-insensitive strings
         Gee.List<string> alt_email_list = config.get_string_list(
@@ -1179,20 +1195,20 @@ public class Accounts.AccountConfigLegacy : AccountConfig, GLib.Object {
         info.prefetch_period_days = config.get_int(
             PREFETCH_PERIOD_DAYS_KEY, info.prefetch_period_days
         );
-        info.save_sent_mail = config.get_bool(
-            SAVE_SENT_MAIL_KEY, info.save_sent_mail
+        info.save_sent = config.get_bool(
+            SAVE_SENT_MAIL_KEY, info.save_sent
         );
-        info.use_email_signature = config.get_bool(
-            USE_EMAIL_SIGNATURE_KEY, info.use_email_signature
+        info.use_signature = config.get_bool(
+            USE_EMAIL_SIGNATURE_KEY, info.use_signature
         );
-        info.email_signature = config.get_string(
-            EMAIL_SIGNATURE_KEY, info.email_signature
+        info.signature = config.get_string(
+            EMAIL_SIGNATURE_KEY, info.signature
         );
 
         info.drafts_folder_path = Geary.AccountInformation.build_folder_path(
             config.get_string_list(DRAFTS_FOLDER_KEY)
         );
-        info.sent_mail_folder_path = Geary.AccountInformation.build_folder_path(
+        info.sent_folder_path = Geary.AccountInformation.build_folder_path(
             config.get_string_list(SENT_MAIL_FOLDER_KEY)
         );
         info.spam_folder_path = Geary.AccountInformation.build_folder_path(
@@ -1217,13 +1233,13 @@ public class Accounts.AccountConfigLegacy : AccountConfig, GLib.Object {
 
         config.set_string(REAL_NAME_KEY, info.primary_mailbox.name ?? "");
         config.set_string(PRIMARY_EMAIL_KEY, info.primary_mailbox.address);
-        config.set_string(NICKNAME_KEY, info.nickname);
+        config.set_string(NICKNAME_KEY, info.label);
         config.set_string(SERVICE_PROVIDER_KEY, info.service_provider.to_value());
         config.set_int(ORDINAL_KEY, info.ordinal);
         config.set_int(PREFETCH_PERIOD_DAYS_KEY, info.prefetch_period_days);
-        config.set_bool(SAVE_SENT_MAIL_KEY, info.save_sent_mail);
-        config.set_bool(USE_EMAIL_SIGNATURE_KEY, info.use_email_signature);
-        config.set_string(EMAIL_SIGNATURE_KEY, info.email_signature);
+        config.set_bool(SAVE_SENT_MAIL_KEY, info.save_sent);
+        config.set_bool(USE_EMAIL_SIGNATURE_KEY, info.use_signature);
+        config.set_string(EMAIL_SIGNATURE_KEY, info.signature);
         if (info.has_sender_aliases) {
             Gee.List<Geary.RFC822.MailboxAddress> alts = info.sender_mailboxes;
             // Don't include the primary in the list
@@ -1240,8 +1256,8 @@ public class Accounts.AccountConfigLegacy : AccountConfig, GLib.Object {
         Gee.LinkedList<string> empty = new Gee.LinkedList<string>();
         config.set_string_list(DRAFTS_FOLDER_KEY, (info.drafts_folder_path != null
             ? info.drafts_folder_path.as_list() : empty));
-        config.set_string_list(SENT_MAIL_FOLDER_KEY, (info.sent_mail_folder_path != null
-            ? info.sent_mail_folder_path.as_list() : empty));
+        config.set_string_list(SENT_MAIL_FOLDER_KEY, (info.sent_folder_path != null
+            ? info.sent_folder_path.as_list() : empty));
         config.set_string_list(SPAM_FOLDER_KEY, (info.spam_folder_path != null
             ? info.spam_folder_path.as_list() : empty));
         config.set_string_list(TRASH_FOLDER_KEY, (info.trash_folder_path != null
@@ -1306,15 +1322,13 @@ public class Accounts.ServiceConfigV1 : ServiceConfig, GLib.Object {
                       account.id, service.protocol.to_value());
             }
 
-            if (service.protocol == Geary.Protocol.SMTP) {
-                try {
-                    service.smtp_credentials_source =
-                    Geary.SmtpCredentials.for_value(
+            try {
+                service.credentials_requirement =
+                    Geary.Credentials.Requirement.for_value(
                         service_config.get_required_string(CREDENTIALS)
                     );
-                } catch (Geary.EngineError err) {
-                    debug("%s: No/invalid SMTP auth config", account.id);
-                }
+            } catch (Geary.EngineError err) {
+                debug("%s: No/invalid SMTP auth config", account.id);
             }
 
             if (service.port == 0) {
@@ -1343,11 +1357,9 @@ public class Accounts.ServiceConfigV1 : ServiceConfig, GLib.Object {
                 SECURITY, service.transport_security.to_value()
             );
 
-            if (service.protocol == Geary.Protocol.SMTP) {
-                service_config.set_string(
-                    CREDENTIALS, service.smtp_credentials_source.to_value()
-                );
-            }
+            service_config.set_string(
+                CREDENTIALS, service.credentials_requirement.to_value()
+            );
         }
     }
 
@@ -1379,7 +1391,10 @@ public class Accounts.ServiceConfigLegacy : ServiceConfig, GLib.Object {
         Geary.ConfigFile.Group service_config =
             config.get_group(AccountConfigLegacy.GROUP);
 
-        string prefix = service.protocol.to_value() + "_";
+        debug("Loading...");
+
+        string prefix = service.protocol == Geary.Protocol.IMAP
+            ? "imap_" :  "smtp_";
 
         string? login = service_config.get_string(
             prefix + USERNAME, account.primary_mailbox.address
@@ -1399,6 +1414,8 @@ public class Accounts.ServiceConfigLegacy : ServiceConfig, GLib.Object {
                 prefix + PORT, service.port
             );
 
+            debug("Host name: %s", service.host);
+
             bool use_tls = service_config.get_bool(
                 prefix + SSL, service.protocol == Geary.Protocol.IMAP
             );
@@ -1421,14 +1438,14 @@ public class Accounts.ServiceConfigLegacy : ServiceConfig, GLib.Object {
                     SMTP_NOAUTH, false
                 );
                 if (use_imap) {
-                    service.smtp_credentials_source =
-                        Geary.SmtpCredentials.IMAP;
+                    service.credentials_requirement =
+                        Geary.Credentials.Requirement.USE_INCOMING;
                 } else if (!no_auth) {
-                    service.smtp_credentials_source =
-                        Geary.SmtpCredentials.CUSTOM;
+                    service.credentials_requirement =
+                        Geary.Credentials.Requirement.CUSTOM;
                 } else {
-                    service.smtp_credentials_source =
-                        Geary.SmtpCredentials.NONE;
+                    service.credentials_requirement =
+                        Geary.Credentials.Requirement.NONE;
                 }
             }
         }
@@ -1474,13 +1491,13 @@ public class Accounts.ServiceConfigLegacy : ServiceConfig, GLib.Object {
             }
 
             if (service.protocol == Geary.Protocol.SMTP) {
-                switch (service.smtp_credentials_source) {
+                switch (service.credentials_requirement) {
                 case NONE:
                     service_config.set_bool(SMTP_USE_IMAP_CREDENTIALS, false);
                     service_config.set_bool(SMTP_NOAUTH, true);
                     break;
 
-                case IMAP:
+                case USE_INCOMING:
                     service_config.set_bool(SMTP_USE_IMAP_CREDENTIALS, true);
                     service_config.set_bool(SMTP_NOAUTH, false);
                     break;
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index 7cb7c218..7deae462 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -808,7 +808,7 @@ public class GearyController : Geary.BaseObject {
         bool imap_prompted, imap_retry_required;
         validation_result = validation_check_endpoint_for_tls_warnings(
             config,
-            config.imap,
+            config.incoming,
             validation_result,
             out imap_prompted,
             out imap_retry_required
@@ -817,7 +817,7 @@ public class GearyController : Geary.BaseObject {
         bool smtp_prompted, smtp_retry_required;
         validation_result = validation_check_endpoint_for_tls_warnings(
             config,
-            config.smtp,
+            config.outgoing,
             validation_result,
             out smtp_prompted,
             out smtp_retry_required
@@ -840,20 +840,6 @@ public class GearyController : Geary.BaseObject {
         return validation_result;
     }
 
-    // Returns the "real" account info associated with a copy.  If it's not a copy, null is returned.
-    public Geary.AccountInformation? get_real_account_information(
-        Geary.AccountInformation account_information) {
-        if (account_information.is_copy) {
-            try {
-                 return Geary.Engine.instance.get_accounts().get(account_information.id);
-            } catch (Error e) {
-                error("Account information is out of sync: %s", e.message);
-            }
-        }
-        
-        return null;
-    }
-
     private void report_problem(Geary.ProblemReport report) {
         debug("Problem reported: %s", report.to_string());
 
@@ -3044,7 +3030,7 @@ public class GearyController : Geary.BaseObject {
             new Geary.ServiceProblemReport(
                 Geary.ProblemType.GENERIC_ERROR,
                 account,
-                account.imap,
+                account.incoming,
                 err
             )
         );
diff --git a/src/client/application/goa-mediator.vala b/src/client/application/goa-mediator.vala
index 79be20b1..58bb05c0 100644
--- a/src/client/application/goa-mediator.vala
+++ b/src/client/application/goa-mediator.vala
@@ -72,8 +72,8 @@ public class GoaMediator : Geary.CredentialsMediator, Object {
         this.oauth2 = this.account.get_oauth2_based();
         this.password = this.account.get_password_based();
 
-        update_imap_config(geary_account.imap);
-        update_smtp_config(geary_account.smtp);
+        update_imap_config(geary_account.incoming);
+        update_smtp_config(geary_account.outgoing);
     }
 
     public virtual async bool load_token(Geary.AccountInformation account,
@@ -170,9 +170,9 @@ public class GoaMediator : Geary.CredentialsMediator, Object {
             }
 
             if (mail.smtp_use_auth) {
-                service.smtp_credentials_source = Geary.SmtpCredentials.CUSTOM;
+                service.credentials_requirement = Geary.Credentials.Requirement.CUSTOM;
             } else {
-                service.smtp_credentials_source = Geary.SmtpCredentials.NONE;
+                service.credentials_requirement = Geary.Credentials.Requirement.NONE;
             }
 
             if (mail.smtp_use_auth) {
diff --git a/src/client/application/secret-mediator.vala b/src/client/application/secret-mediator.vala
index 0e41be55..af7a5c0d 100644
--- a/src/client/application/secret-mediator.vala
+++ b/src/client/application/secret-mediator.vala
@@ -109,7 +109,7 @@ public class SecretMediator : Geary.CredentialsMediator, Object {
 
             yield update_token(account, service, cancellable);
 
-            account.information_changed();
+            account.changed();
         }
         return true;
     }
diff --git a/src/client/components/main-window.vala b/src/client/components/main-window.vala
index ee79f4f6..dceb3f2a 100644
--- a/src/client/components/main-window.vala
+++ b/src/client/components/main-window.vala
@@ -420,7 +420,8 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
             return;
         }
 
-        this.main_toolbar.account = this.current_folder.account.information.nickname;
+        this.main_toolbar.account =
+            this.current_folder.account.information.display_name;
 
         /// Current folder's name followed by its unread count, i.e. "Inbox (42)"
         // except for Drafts and Outbox, where we show total count
diff --git a/src/client/components/search-bar.vala b/src/client/components/search-bar.vala
index 4cbd90d1..1cb7c1be 100644
--- a/src/client/components/search-bar.vala
+++ b/src/client/components/search-bar.vala
@@ -79,12 +79,12 @@ public class SearchBar : Gtk.SearchBar {
             search_upgrade_progress_monitor.finish.disconnect(on_search_upgrade_finished);
             search_upgrade_progress_monitor = null;
         }
-        
+
         if (current_account != null) {
-            current_account.information.notify[Geary.AccountInformation.PROP_NICKNAME].disconnect(
-                on_nickname_changed);
+            current_account.information.changed.disconnect(
+                on_information_changed);
         }
-        
+
         if (account != null) {
             search_upgrade_progress_monitor = account.search_upgrade_monitor;
             search_upgrade_progress_bar.set_progress_monitor(search_upgrade_progress_monitor);
@@ -93,21 +93,23 @@ public class SearchBar : Gtk.SearchBar {
             search_upgrade_progress_monitor.finish.connect(on_search_upgrade_finished);
             if (search_upgrade_progress_monitor.is_in_progress)
                 on_search_upgrade_start(); // Remove search box, we're already in progress.
-            
-            account.information.notify[Geary.AccountInformation.PROP_NICKNAME].connect(
-                on_nickname_changed);
-            
-            search_upgrade_progress_bar.text = _("Indexing %s account").printf(account.information.nickname);
+
+            account.information.changed.connect(
+                on_information_changed);
+
+            search_upgrade_progress_bar.text =
+                _("Indexing %s account").printf(account.information.display_name);
         }
-        
+
         current_account = account;
-        
-        on_nickname_changed(); // Set new account name.
+
+        on_information_changed(); // Set new account name.
     }
-    
-    private void on_nickname_changed() {
+
+    private void on_information_changed() {
         set_search_placeholder_text(current_account == null ||
             GearyApplication.instance.controller.get_num_accounts() == 1 ? DEFAULT_SEARCH_TEXT :
-            _("Search %s account").printf(current_account.information.nickname));
+            _("Search %s account").printf(current_account.information.display_name));
     }
+
 }
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index f774761e..05da827d 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -2140,8 +2140,8 @@ public class ComposerWidget : Gtk.EventBox {
     private async string load_signature(Cancellable? cancellable = null) {
         string account_sig = "";
 
-        if (this.account.information.use_email_signature) {
-            account_sig = account.information.email_signature ?? "";
+        if (this.account.information.use_signature) {
+            account_sig = account.information.signature;
             if (Geary.String.is_empty_or_whitespace(account_sig)) {
                 // No signature is specified in the settings, so use
                 // ~/.signature
diff --git a/src/client/dialogs/password-dialog.vala b/src/client/dialogs/password-dialog.vala
index b1866e49..e8985cfc 100644
--- a/src/client/dialogs/password-dialog.vala
+++ b/src/client/dialogs/password-dialog.vala
@@ -46,7 +46,7 @@ public class PasswordDialog {
         bool is_smtp = service.protocol == Geary.Protocol.SMTP;
 
         Geary.Credentials? credentials = (is_smtp)
-            ? account.get_smtp_credentials() : account.imap.credentials;
+            ? account.get_outgoing_credentials() : account.incoming.credentials;
 
         if (credentials != null) {
             label_username.set_text(credentials.user);
diff --git a/src/client/folder-list/folder-list-account-branch.vala 
b/src/client/folder-list/folder-list-account-branch.vala
index 42e09cc7..ac6a5457 100644
--- a/src/client/folder-list/folder-list-account-branch.vala
+++ b/src/client/folder-list/folder-list-account-branch.vala
@@ -9,31 +9,37 @@ public class FolderList.AccountBranch : Sidebar.Branch {
     public Geary.Account account { get; private set; }
     public SpecialGrouping user_folder_group { get; private set; }
     public Gee.HashMap<Geary.FolderPath, FolderEntry> folder_entries { get; private set; }
-    
+
+    private string display_name = "";
+
     public AccountBranch(Geary.Account account) {
-        base(new Sidebar.Header(account.information.nickname),
+        base(new Sidebar.Header(account.information.display_name),
              Sidebar.Branch.Options.AUTO_OPEN_ON_NEW_CHILD, normal_folder_comparator, 
special_folder_comparator);
-        
+
         this.account = account;
         user_folder_group = new SpecialGrouping(2, "", "tag-symbolic");
         folder_entries = new Gee.HashMap<Geary.FolderPath, FolderEntry>();
-        
-        account.information.notify["nickname"].connect(on_nicknamed_changed);
-        
+
+        this.display_name = account.information.display_name;
+        account.information.changed.connect(on_information_changed);
+
         entry_removed.connect(on_entry_removed);
         entry_moved.connect(check_user_folders);
     }
-    
+
     ~AccountBranch() {
-        account.information.notify["nickname"].disconnect(on_nicknamed_changed);
+        account.information.changed.disconnect(on_information_changed);
         entry_removed.disconnect(on_entry_removed);
         entry_moved.disconnect(check_user_folders);
     }
-    
-    private void on_nicknamed_changed() {
-        ((Sidebar.Grouping) get_root()).rename(account.information.nickname);
+
+    private void on_information_changed() {
+        if (this.display_name != this.account.information.display_name) {
+            this.display_name = account.information.display_name;
+            ((Sidebar.Grouping) get_root()).rename(this.display_name);
+        }
     }
-    
+
     private static int special_grouping_comparator(Sidebar.Entry a, Sidebar.Entry b) {
         SpecialGrouping? grouping_a = a as SpecialGrouping;
         SpecialGrouping? grouping_b = b as SpecialGrouping;
diff --git a/src/client/folder-list/folder-list-inbox-folder-entry.vala 
b/src/client/folder-list/folder-list-inbox-folder-entry.vala
index fab3c70a..652ad3b3 100644
--- a/src/client/folder-list/folder-list-inbox-folder-entry.vala
+++ b/src/client/folder-list/folder-list-inbox-folder-entry.vala
@@ -6,25 +6,33 @@
 
 // A FolderEntry for inboxes in the Inboxes branch.
 public class FolderList.InboxFolderEntry : FolderList.FolderEntry {
+
+
+    private string display_name = "";
+
+
     public InboxFolderEntry(Geary.Folder folder) {
         base(folder);
-        folder.account.information.notify["nickname"].connect(on_nicknamed_changed);
+        this.display_name = folder.account.information.display_name;
+        folder.account.information.changed.connect(on_information_changed);
     }
-    
+
     ~InboxFolderEntry() {
-        folder.account.information.notify["nickname"].disconnect(on_nicknamed_changed);
+        folder.account.information.changed.disconnect(on_information_changed);
     }
-    
+
     public override string get_sidebar_name() {
-        return folder.account.information.nickname;
+        return this.display_name;
     }
-    
+
     public Geary.AccountInformation get_account_information() {
         return folder.account.information;
     }
-    
-    private void on_nicknamed_changed() {
-        sidebar_name_changed(folder.account.information.nickname);
+
+    private void on_information_changed(Geary.AccountInformation config) {
+        if (this.display_name != config.display_name) {
+            this.display_name = config.display_name;
+            sidebar_name_changed(this.display_name);
+        }
     }
 }
-
diff --git a/src/client/folder-list/folder-list-search-branch.vala 
b/src/client/folder-list/folder-list-search-branch.vala
index 8c5c644d..ba6c64de 100644
--- a/src/client/folder-list/folder-list-search-branch.vala
+++ b/src/client/folder-list/folder-list-search-branch.vala
@@ -36,7 +36,7 @@ public class FolderList.SearchEntry : FolderList.AbstractFolderEntry {
     
     public override string get_sidebar_name() {
         return GearyApplication.instance.controller.get_num_accounts() == 1 ? _("Search") :
-            _("Search %s account").printf(folder.account.information.nickname);
+            _("Search %s account").printf(folder.account.information.display_name);
     }
     
     public override string? get_sidebar_tooltip() {
diff --git a/src/client/util/util-migrate.vala b/src/client/util/util-migrate.vala
index 201fa214..ec86c101 100644
--- a/src/client/util/util-migrate.vala
+++ b/src/client/util/util-migrate.vala
@@ -7,7 +7,7 @@
 namespace Migrate {
     private const string GROUP = "AccountInformation";
     private const string PRIMARY_EMAIL_KEY = "primary_email";
-    private const string SETTINGS_FILENAME = Geary.AccountInformation.SETTINGS_FILENAME;
+    private const string SETTINGS_FILENAME = Accounts.Manager.SETTINGS_FILENAME;
     private const string MIGRATED_FILENAME = ".config_migrated";
 
     /**
diff --git a/src/engine/api/geary-account-information.vala b/src/engine/api/geary-account-information.vala
index ea0a791b..de6d9b49 100644
--- a/src/engine/api/geary-account-information.vala
+++ b/src/engine/api/geary-account-information.vala
@@ -8,64 +8,42 @@
 
 public class Geary.AccountInformation : BaseObject {
 
-    /** Name of of the nickname property, for signal handlers. */
-    public const string PROP_NICKNAME = "nickname";
 
     public const int DEFAULT_PREFETCH_PERIOD_DAYS = 14;
 
-    public const string SETTINGS_FILENAME = "geary.ini";
-
 
+    /** The next ordinal that should be allocated for an account. */
     public static int next_ordinal = 0;
 
-
     /** Comparator for account info objects based on their ordinals. */
     public static int compare_ascending(AccountInformation a, AccountInformation b) {
         int diff = a.ordinal - b.ordinal;
         if (diff != 0)
             return diff;
 
-        // Stabilize on nickname, which should always be unique.
+        // Stabilize on display name, which should always be unique.
         return a.display_name.collate(b.display_name);
     }
 
-    /** Location of the account information's settings key file. */
-    public File? settings_file {
-        owned get {
-            File? settings = null;
-            if (this.config_dir != null) {
-                settings = this.config_dir.get_child(SETTINGS_FILENAME);
-            }
-            return settings;
-        }
+    public static Geary.FolderPath? build_folder_path(Gee.List<string>? parts) {
+        if (parts == null || parts.size == 0)
+            return null;
+
+        Geary.FolderPath path = new Imap.FolderRoot(parts[0]);
+        for (int i = 1; i < parts.size; i++)
+            path = path.get_child(parts.get(i));
+        return path;
     }
 
-    /**
-     * Location of the account's config directory.
-     *
-     * This directory is used to store small, per-account
-     * configuration files, including the account's settings key file.
-     */
-    public File? config_dir { get; private set; default = null; }
 
-    /**
-     * Location of the account's data directory.
-     *
-     * This directory is used to store large, per-account data files
-     * such as the account database.
-     */
-    public File? data_dir { get; private set; default = null; }
-
-    /**
-     * A unique, immutable, machine-readable identifier for this account.
-     *
-     * This string's value should be treated as an opaque, private
-     * implementation detail and not parsed at all. For older accounts
-     * it will be an email address, for newer accounts it will be
-     * something else. Once created, this string will never change.
-     */
+    /** A unique (engine-wide), opaque identifier for the account. */
     public string id { get; private set; }
 
+    /** A unique (engine-wide) ordering for the account. */
+    public int ordinal {
+        get; set; default = AccountInformation.next_ordinal++;
+    }
+
     /** Specifies the email provider for this account. */
     public Geary.ServiceProvider service_provider { get; private set; }
 
@@ -81,7 +59,7 @@ public class Geary.AccountInformation : BaseObject {
         owned get {
             string? value = this._service_label;
             if (value == null) {
-                string[] host_parts = this.imap.host.split(".");
+                string[] host_parts = this.incoming.host.split(".");
                 if (host_parts.length > 1) {
                     host_parts = host_parts[1:host_parts.length];
                 }
@@ -105,8 +83,8 @@ public class Geary.AccountInformation : BaseObject {
      */
     public string display_name {
         get {
-            return (!String.is_empty_or_whitespace(this.nickname))
-                ? this.nickname
+            return (!String.is_empty_or_whitespace(this.label))
+                ? this.label
                 : this.primary_mailbox.address;
         }
     }
@@ -117,7 +95,7 @@ public class Geary.AccountInformation : BaseObject {
      * This is not to be used in the UI (use `display_name` instead)
      * and not transmitted on the wire or used in correspondence.
      */
-    public string nickname { get; set; default = ""; }
+    public string label { get; set; default = ""; }
 
     /**
      * The default sender mailbox address for the account.
@@ -143,28 +121,29 @@ public class Geary.AccountInformation : BaseObject {
         get { return this.sender_mailboxes.size > 1; }
     }
 
+    /** Specifies the number of days to be fetched by the account sync. */
     public int prefetch_period_days {
         get; set; default = DEFAULT_PREFETCH_PERIOD_DAYS;
     }
 
     /**
-     * Whether the user has requested that sent mail be saved.  Note that Geary
-     * will only actively push sent mail when this AND allow_save_sent_mail()
-     * are both true.
+     * Specifies if the user has requested that sent mail be saved.
+     *
+     * Note that Geary will only actively push sent mail when this AND
+     * {@link allow_save_sent} are both true.
      */
-    public bool save_sent_mail {
+    public bool save_sent {
         // If we aren't allowed to save sent mail due to account type, we want
         // to return true here on the assumption that the account will save
         // sent mail for us, and thus the user can't disable sent mail from
         // being saved.
-        get { return (allow_save_sent_mail() ? _save_sent_mail : true); }
-        set { _save_sent_mail = value; }
+        get { return (allow_save_sent() ? this._save_sent : true); }
+        set { this._save_sent = value; }
     }
+    private bool _save_sent = true;
 
-    // Order for display purposes.
-    public int ordinal {
-        get; set; default = AccountInformation.next_ordinal++;
-    }
+    /** Determines if drafts should be saved on the server. */
+    public bool save_drafts { get; set; default = true; }
 
     /**
      * The source of authentication credentials for this account.
@@ -172,13 +151,13 @@ public class Geary.AccountInformation : BaseObject {
     public CredentialsMediator mediator { get; private set; }
 
     /* Incoming email service configuration. */
-    public ServiceInformation imap {
+    public ServiceInformation incoming {
         get; set;
         default = new ServiceInformation(Protocol.IMAP);
     }
 
     /* Outgoing email service configuration. */
-    public ServiceInformation smtp {
+    public ServiceInformation outgoing {
         get; set;
         default = new ServiceInformation(Protocol.SMTP);
     }
@@ -188,29 +167,48 @@ public class Geary.AccountInformation : BaseObject {
         get; private set; default = new Nonblocking.Mutex();
     }
 
-    // These properties are only used if the service provider's
-    // account type does not override them.
+    /** Specifies if an email sig should be appended to new messages. */
+    public bool use_signature { get; set; default = false; }
 
-    public bool use_email_signature { get; set; default = false; }
-    public string email_signature { get; set; default = ""; }
+    /** Specifies the email sig to be appended to new messages. */
+    public string signature { get; set; default = ""; }
 
+    /** Draft special folder path. */
     public Geary.FolderPath? drafts_folder_path { get; set; default = null; }
-    public Geary.FolderPath? sent_mail_folder_path { get; set; default = null; }
+
+    /** Sent special folder path. */
+    public Geary.FolderPath? sent_folder_path { get; set; default = null; }
+
+    /** Spam special folder path. */
     public Geary.FolderPath? spam_folder_path { get; set; default = null; }
+
+    /** Trash special folder path. */
     public Geary.FolderPath? trash_folder_path { get; set; default = null; }
+
+    /** Archive special folder path. */
     public Geary.FolderPath? archive_folder_path { get; set; default = null; }
 
-    public bool save_drafts { get; set; default = true; }
+    /**
+     * Location of the account's config directory.
+     *
+     * This directory is used to store small, per-account
+     * configuration files, including the account's settings key file.
+     */
+    public File? config_dir { get; private set; default = null; }
 
-    public bool is_copy { get; set; default = false; }
+    /**
+     * Location of the account's data directory.
+     *
+     * This directory is used to store large, per-account data files
+     * such as the account database.
+     */
+    public File? data_dir { get; private set; default = null; }
 
     private Gee.List<Geary.RFC822.MailboxAddress> mailboxes {
         get; private set;
         default = new Gee.LinkedList<Geary.RFC822.MailboxAddress>();
     }
 
-    private bool _save_sent_mail = true;
-
 
     /**
      * Emitted when a service has reported TLS certificate warnings.
@@ -222,8 +220,8 @@ public class Geary.AccountInformation : BaseObject {
                                       TlsNegotiationMethod method,
                                       GLib.TlsConnection cx);
 
-    /** Indicates that properties contained herein have changed. */
-    public signal void information_changed();
+    /** Emitted when the account settings have changed. */
+    public signal void changed();
 
     /**
      * Creates a new account with default settings.
@@ -249,23 +247,23 @@ public class Geary.AccountInformation : BaseObject {
             other.primary_mailbox
         );
         this.service_label = other.service_label;
-        this.nickname = other.nickname;
+        this.label = other.label;
         if (other.mailboxes.size > 1) {
             this.mailboxes.add_all(
                 other.mailboxes.slice(1, other.mailboxes.size)
             );
         }
         this.prefetch_period_days = other.prefetch_period_days;
-        this.save_sent_mail = other.save_sent_mail;
-        this.use_email_signature = other.use_email_signature;
-        this.email_signature = other.email_signature;
+        this.save_sent = other.save_sent;
         this.save_drafts = other.save_drafts;
+        this.use_signature = other.use_signature;
+        this.signature = other.signature;
 
-        this.imap = new ServiceInformation.copy(other.imap);
-        this.smtp = new ServiceInformation.copy(other.smtp);
+        this.incoming = new ServiceInformation.copy(other.incoming);
+        this.outgoing = new ServiceInformation.copy(other.outgoing);
 
         this.drafts_folder_path = other.drafts_folder_path;
-        this.sent_mail_folder_path = other.sent_mail_folder_path;
+        this.sent_folder_path = other.sent_folder_path;
         this.spam_folder_path = other.spam_folder_path;
         this.trash_folder_path = other.trash_folder_path;
         this.archive_folder_path = other.archive_folder_path;
@@ -339,120 +337,133 @@ public class Geary.AccountInformation : BaseObject {
     }
 
     /**
-     * Return whether this account allows setting the save_sent_mail option.
-     * If not, save_sent_mail will always be true and setting it will be
-     * ignored.
+     * Determines if {@link save_sent} property can be set.
+     *
+     * If not, that property will always be true and setting it will
+     * be ignored.
      */
-    public bool allow_save_sent_mail() {
-        // We should never push mail to Gmail, since its servers automatically
-        // push sent mail to the sent mail folder.
-        return service_provider != ServiceProvider.GMAIL;
+    public bool allow_save_sent() {
+        // We should never push mail to Gmail, since its servers
+        // automatically push sent mail to the sent mail folder.
+        return this.service_provider != ServiceProvider.GMAIL;
     }
-    
+
     /**
-     * Gets the path used when Geary has found or created a special folder for
-     * this account.  This will be null if Geary has always been told about the
-     * special folders by the server, and hasn't had to go looking for them.
-     * Only the DRAFTS, SENT, SPAM, and TRASH special folder types are valid to
-     * pass to this function.
+     * Returns the configured path for a special folder type.
+     *
+     * This is used when Geary has found or created a special folder
+     * for this account. The path will be null if Geary has always
+     * been told about the special folders by the server, and hasn't
+     * had to go looking for them.  Only the ARCHIVE, DRAFTS, SENT,
+     * SPAM, and TRASH special folder types are valid to pass to this
+     * function.
      */
     public Geary.FolderPath? get_special_folder_path(Geary.SpecialFolderType special) {
         switch (special) {
             case Geary.SpecialFolderType.DRAFTS:
-                return drafts_folder_path;
+                return this.drafts_folder_path;
 
             case Geary.SpecialFolderType.SENT:
-                return sent_mail_folder_path;
-            
+                return this.sent_folder_path;
+
             case Geary.SpecialFolderType.SPAM:
-                return spam_folder_path;
-            
+                return this.spam_folder_path;
+
             case Geary.SpecialFolderType.TRASH:
-                return trash_folder_path;
+                return this.trash_folder_path;
 
             case Geary.SpecialFolderType.ARCHIVE:
-                return archive_folder_path;
-            
-            default:
-                assert_not_reached();
+                return this.archive_folder_path;
         }
+
+        return null;
     }
-    
+
     /**
-     * Sets the path Geary will look for or create a special folder.  This is
-     * only obeyed if the server doesn't tell Geary which folders are special.
-     * Only the DRAFTS, SENT, SPAM, TRASH and ARCHIVE special folder types are
-     * valid to pass to this function.
+     * Sets the configured path for a special folder type.
+     *
+     * This is only obeyed if the server doesn't tell Geary which
+     * folders are special. Only the DRAFTS, SENT, SPAM, TRASH and
+     * ARCHIVE special folder types are valid to pass to this
+     * function.
      */
-    public void set_special_folder_path(Geary.SpecialFolderType special, Geary.FolderPath? path) {
+    public void set_special_folder_path(Geary.SpecialFolderType special,
+                                        Geary.FolderPath? new_path) {
+        Geary.FolderPath? old_path = null;
         switch (special) {
             case Geary.SpecialFolderType.DRAFTS:
-                drafts_folder_path = path;
+                old_path = this.drafts_folder_path;
+                this.drafts_folder_path = new_path;
             break;
-            
+
             case Geary.SpecialFolderType.SENT:
-                sent_mail_folder_path = path;
+                old_path = this.sent_folder_path;
+                this.sent_folder_path = new_path;
             break;
-            
+
             case Geary.SpecialFolderType.SPAM:
-                spam_folder_path = path;
+                old_path = this.spam_folder_path;
+                this.spam_folder_path = new_path;
             break;
-            
+
             case Geary.SpecialFolderType.TRASH:
-                trash_folder_path = path;
+                old_path = this.trash_folder_path;
+                this.trash_folder_path = new_path;
             break;
 
             case Geary.SpecialFolderType.ARCHIVE:
-                archive_folder_path = path;
+                old_path = this.archive_folder_path;
+                this.archive_folder_path = new_path;
             break;
-            
-            default:
-                assert_not_reached();
         }
 
-        // This account's information should be stored again. Signal this.
-        information_changed();
+        if (old_path == null && new_path != null ||
+            old_path != null && !old_path.equal_to(new_path)) {
+            changed();
+        }
     }
 
     /**
-     * Returns the best credentials to use for SMTP authentication.
+     * Returns the best credentials to use for the outgoing service.
      *
-     * This method checks for SMTP services that use IMAP credentials
-     * for authentication and if enabled, returns those. If this
-     * method returns null, then SMTP authentication should not be
-     * attempted for this account.
+     * This method checks for an outgoing service that use incoming
+     * service's credentials for authentication and if enabled,
+     * returns those. If this method returns null, then outgoing
+     * authentication should not be attempted for this account.
      */
-    public Credentials? get_smtp_credentials() {
-        Credentials? smtp = null;
-        switch (this.smtp.smtp_credentials_source) {
-        case IMAP:
-            smtp = this.imap.credentials;
+    public Credentials? get_outgoing_credentials() {
+        Credentials? outgoing = null;
+        switch (this.outgoing.credentials_requirement) {
+        case USE_INCOMING:
+            outgoing = this.incoming.credentials;
             break;
         case CUSTOM:
-            smtp = this.smtp.credentials;
+            outgoing = this.outgoing.credentials;
             break;
         }
-        return smtp;
+        return outgoing;
     }
 
     /**
-     * Loads this account's SMTP credentials from the mediator, if needed.
+     * Loads this account's outgoing service credentials, if needed.
      *
-     * This method may cause the user to be prompted for their
-     * secrets, thus it may yield for some time.
+     * Credentials are loaded from the mediator, which may cause the
+     * user to be prompted for the secret, thus it may yield for some
+     * time.
      *
      * Returns true if the credentials were successfully loaded or had
-     * been previously loaded, the credentials could not be loaded and
-     * the SMTP credentials are invalid.
+     * been previously loaded, or false the credentials could not be
+     * loaded and the service's credentials are invalid.
      */
-    public async bool load_smtp_credentials(GLib.Cancellable? cancellable)
+    public async bool load_outgoing_credentials(GLib.Cancellable? cancellable)
         throws GLib.Error {
-        Credentials? creds = get_smtp_credentials();
+        Credentials? creds = get_outgoing_credentials();
         bool loaded = (creds == null || creds.is_complete());
         if (!loaded && creds != null) {
-            ServiceInformation service = this.smtp;
-            if (this.smtp.smtp_use_imap_credentials) {
-                service = this.imap;
+            ServiceInformation service = this.outgoing;
+            if (this.outgoing.credentials_requirement ==
+                Credentials.Requirement.USE_INCOMING) {
+                service = this.incoming;
             }
             loaded = yield this.mediator.load_token(
                 this, service, cancellable
@@ -462,63 +473,54 @@ public class Geary.AccountInformation : BaseObject {
     }
 
     /**
-     * Prompts the user for their SMTP authentication secret.
+     * Prompts the user for their outgoing service authentication secret.
      *
      * Returns true if the credentials were successfully entered, else
      * false if the user dismissed the prompt.
      */
-    public async bool prompt_smtp_credentials(GLib.Cancellable? cancellable)
+    public async bool prompt_outgoing_credentials(GLib.Cancellable? cancellable)
         throws GLib.Error {
         return yield this.mediator.prompt_token(
-            this, this.smtp, cancellable
+            this, this.outgoing, cancellable
         );
     }
 
     /**
-     * Loads this account's IMAP credentials from the mediator, if needed.
+     * Loads this account's incoming service credentials, if needed.
      *
-     * This method may cause the user to be prompted for their
-     * secrets, thus it may yield for some time.
+     * Credentials are loaded from the mediator, which may cause the
+     * user to be prompted for the secret, thus it may yield for some
+     * time.
      *
      * Returns true if the credentials were successfully loaded or had
-     * been previously loaded, the credentials could not be loaded and
-     * the IMAP credentials are invalid.
+     * been previously loaded, or false the credentials could not be
+     * loaded and the service's credentials are invalid.
      */
-    public async bool load_imap_credentials(GLib.Cancellable? cancellable)
+    public async bool load_incoming_credentials(GLib.Cancellable? cancellable)
         throws GLib.Error {
-        Credentials? creds = this.imap.credentials;
+        Credentials? creds = this.incoming.credentials;
         bool loaded = creds.is_complete();
         if (!loaded) {
             loaded = yield this.mediator.load_token(
-                this, this.imap, cancellable
+                this, this.incoming, cancellable
             );
         }
         return loaded;
     }
 
     /**
-     * Prompts the user for their IMAP authentication secret.
+     * Prompts the user for their incoming service authentication secret.
      *
      * Returns true if the credentials were successfully entered, else
      * false if the user dismissed the prompt.
      */
-    public async bool prompt_imap_credentials(GLib.Cancellable? cancellable)
+    public async bool prompt_incoming_credentials(GLib.Cancellable? cancellable)
         throws GLib.Error {
         return yield this.mediator.prompt_token(
-            this, this.imap, cancellable
+            this, this.incoming, cancellable
         );
     }
 
-    public static Geary.FolderPath? build_folder_path(Gee.List<string>? parts) {
-        if (parts == null || parts.size == 0)
-            return null;
-        
-        Geary.FolderPath path = new Imap.FolderRoot(parts[0]);
-        for (int i = 1; i < parts.size; i++)
-            path = path.get_child(parts.get(i));
-        return path;
-    }
-
     public bool equal_to(AccountInformation other) {
         return (
             this == other || (
@@ -528,22 +530,21 @@ public class Geary.AccountInformation : BaseObject {
                 this.mediator == other.mediator &&
                 this.service_provider == other.service_provider &&
                 this.service_label == other.service_label &&
-                this.nickname == other.nickname &&
+                this.label == other.label &&
                 this.primary_mailbox.equal_to(other.primary_mailbox) &&
-                this.has_sender_aliases == other.has_sender_aliases &&
                 this.sender_mailboxes.size == other.sender_mailboxes.size &&
                 traverse(this.sender_mailboxes).all(
                     addr => other.sender_mailboxes.contains(addr)
                 ) &&
                 this.prefetch_period_days == other.prefetch_period_days &&
-                this.save_sent_mail == other.save_sent_mail &&
-                this.imap.equal_to(other.imap) &&
-                this.smtp.equal_to(other.smtp) &&
-                this.use_email_signature == other.use_email_signature &&
-                this.email_signature == other.email_signature &&
+                this.save_sent == other.save_sent &&
                 this.save_drafts == other.save_drafts &&
+                this.use_signature == other.use_signature &&
+                this.signature == other.signature &&
+                this.incoming.equal_to(other.incoming) &&
+                this.outgoing.equal_to(other.outgoing) &&
                 this.drafts_folder_path == other.drafts_folder_path &&
-                this.sent_mail_folder_path == other.sent_mail_folder_path &&
+                this.sent_folder_path == other.sent_folder_path &&
                 this.spam_folder_path == other.spam_folder_path &&
                 this.trash_folder_path == other.trash_folder_path &&
                 this.archive_folder_path == other.archive_folder_path &&
diff --git a/src/engine/api/geary-credentials.vala b/src/engine/api/geary-credentials.vala
index 50a14453..e1b58cf9 100644
--- a/src/engine/api/geary-credentials.vala
+++ b/src/engine/api/geary-credentials.vala
@@ -70,6 +70,33 @@ public class Geary.Credentials : BaseObject, Gee.Hashable<Geary.Credentials> {
     }
 
 
+    /** The requirements for a service's credentials. */
+    public enum Requirement {
+        /** No credentials are required. */
+        NONE,
+
+        /** The incoming service's credentials should be used. */
+        USE_INCOMING,
+
+        /** Custom credentials are required. */
+        CUSTOM;
+
+        public static Requirement for_value(string value)
+            throws EngineError {
+            return ObjectUtils.from_enum_nick<Requirement>(
+                typeof(Requirement), value.ascii_down()
+            );
+        }
+
+        public string to_value() {
+            return ObjectUtils.to_enum_nick<Requirement>(
+                typeof(Requirement), this
+            );
+        }
+
+    }
+
+
     public Method supported_method { get; private set; }
     public string user { get; private set; }
     public string? token { get; private set; }
diff --git a/src/engine/api/geary-engine.vala b/src/engine/api/geary-engine.vala
index f345b3e7..08998c39 100644
--- a/src/engine/api/geary-engine.vala
+++ b/src/engine/api/geary-engine.vala
@@ -297,7 +297,7 @@ public class Geary.Engine : BaseObject {
      */
     public async void validate_smtp(AccountInformation account,
                                     ServiceInformation service,
-                                    Credentials? imap_credentials,
+                                    Credentials? incoming_credentials,
                                     GLib.Cancellable? cancellable = null)
         throws GLib.Error {
         check_opened();
@@ -309,9 +309,9 @@ public class Geary.Engine : BaseObject {
         );
 
         Credentials? credentials = null;
-        switch (service.smtp_credentials_source) {
-        case IMAP:
-            credentials = imap_credentials;
+        switch (service.credentials_requirement) {
+        case USE_INCOMING:
+            credentials = incoming_credentials;
             break;
         case CUSTOM:
             credentials = service.credentials;
@@ -374,15 +374,15 @@ public class Geary.Engine : BaseObject {
                 assert_not_reached();
         }
 
-        Endpoint imap = get_shared_endpoint(
-            config.service_provider, config.imap
+        Endpoint incoming = get_shared_endpoint(
+            config.service_provider, config.incoming
         );
-        account.set_endpoint(account.incoming, imap);
+        account.set_endpoint(account.incoming, incoming);
 
-        Endpoint smtp = get_shared_endpoint(
-            config.service_provider, config.smtp
+        Endpoint outgoing = get_shared_endpoint(
+            config.service_provider, config.outgoing
         );
-        account.set_endpoint(account.outgoing, smtp);
+        account.set_endpoint(account.outgoing, outgoing);
 
         account_instances.set(config.id, account);
         return account;
@@ -460,16 +460,16 @@ public class Geary.Engine : BaseObject {
         bool was_updated = false;
         switch (updated.protocol) {
         case Protocol.IMAP:
-            if (!account.imap.equal_to(updated)) {
+            if (!account.incoming.equal_to(updated)) {
                 was_updated = true;
-                account.imap = updated;
+                account.incoming = updated;
             }
             service = impl.incoming;
             break;
         case Protocol.SMTP:
-            if (!account.smtp.equal_to(updated)) {
+            if (!account.outgoing.equal_to(updated)) {
                 was_updated = true;
-                account.smtp = updated;
+                account.outgoing = updated;
             }
             service = impl.outgoing;
             break;
@@ -480,7 +480,7 @@ public class Geary.Engine : BaseObject {
                 account.service_provider, updated
             );
             impl.set_endpoint(service, endpoint);
-            account.information_changed();
+            account.changed();
         }
 
         return was_updated;
@@ -500,14 +500,6 @@ public class Geary.Engine : BaseObject {
             shared = cached.get() as Endpoint;
         }
         if (shared == null) {
-            // Prefer SSL by RFC 8314
-            TlsNegotiationMethod method = TlsNegotiationMethod.NONE;
-            if (service.use_ssl) {
-                method = TlsNegotiationMethod.TRANSPORT;
-            } else if (service.use_starttls) {
-                method = TlsNegotiationMethod.START_TLS;
-            }
-
             uint timeout = service.protocol == Protocol.IMAP
                 ? Imap.ClientConnection.RECOMMENDED_TIMEOUT_SEC
                 : Smtp.ClientConnection.DEFAULT_TIMEOUT_SEC;
@@ -515,7 +507,7 @@ public class Geary.Engine : BaseObject {
             shared = new Endpoint(
                 service.host,
                 service.port,
-                method,
+                service.transport_security,
                 timeout
             );
 
diff --git a/src/engine/api/geary-service-information.vala b/src/engine/api/geary-service-information.vala
index 3a565df1..1453b95e 100644
--- a/src/engine/api/geary-service-information.vala
+++ b/src/engine/api/geary-service-information.vala
@@ -84,38 +84,13 @@ public enum Geary.TlsNegotiationMethod {
 }
 
 
-/** The credential source used to negotiate SMTP authentication, if any. */
-public enum Geary.SmtpCredentials {
-    /** No SMTP credentials are required. */
-    NONE,
-    /** The account's IMAP credentials should be used. */
-    IMAP,
-    /** Custom credentials are required for SMTP. */
-    CUSTOM;
-
-    public static SmtpCredentials for_value(string value)
-        throws EngineError {
-        return ObjectUtils.from_enum_nick<SmtpCredentials>(
-            typeof(SmtpCredentials), value.ascii_down()
-        );
-    }
-
-    public string to_value() {
-        return ObjectUtils.to_enum_nick<SmtpCredentials>(
-            typeof(SmtpCredentials), this
-        );
-    }
-
-}
-
-
 /**
  * Encapsulates configuration information for a network service.
  */
 public class Geary.ServiceInformation : GLib.Object {
 
 
-    /** Specifies if this service is for IMAP or SMTP. */
+    /** Specifies the network protocol for this service. */
     public Protocol protocol { get; private set; }
 
     /** The server's address. */
@@ -125,39 +100,12 @@ public class Geary.ServiceInformation : GLib.Object {
     public uint16 port { get; set; default = 0; }
 
     /** The transport security method to use */
-    public TlsNegotiationMethod transport_security {
-        get {
-            if (this.use_ssl) {
-                return TlsNegotiationMethod.TRANSPORT;
-            } else if (this.use_starttls) {
-                return TlsNegotiationMethod.START_TLS;
-            } else {
-                return TlsNegotiationMethod.NONE;
-            }
-        }
-        set {
-            switch (value) {
-            case TlsNegotiationMethod.NONE:
-                this.use_starttls = false;
-                this.use_ssl = false;
-                break;
-            case TlsNegotiationMethod.START_TLS:
-                this.use_starttls = true;
-                this.use_ssl = false;
-                break;
-            case TlsNegotiationMethod.TRANSPORT:
-                this.use_starttls = false;
-                this.use_ssl = true;
-                break;
-            }
-        }
-    }
+    public TlsNegotiationMethod transport_security { get; set; }
 
-    /** Whether STARTTLS is used when connecting to the server. */
-    public bool use_starttls { get; set; default = false; }
-
-    /** Whether SSL is used when connecting to the server. */
-    public bool use_ssl { get; set; default = true; }
+    /**
+     * Determines the source of auth credentials for SMTP services.
+     */
+    public Credentials.Requirement credentials_requirement { get; set; }
 
     /** The credentials used for authenticating. */
     public Credentials? credentials { get; set; default = null; }
@@ -170,57 +118,19 @@ public class Geary.ServiceInformation : GLib.Object {
      */
     public bool remember_password { get; set; default = true; }
 
-    /**
-     * Determines the source of auth credentials for SMTP services.
-     */
-    public SmtpCredentials smtp_credentials_source {
-        get {
-            if (this.smtp_use_imap_credentials) {
-                return SmtpCredentials.IMAP;
-            } else if (this.smtp_noauth) {
-                return SmtpCredentials.NONE;
-            } else {
-                return SmtpCredentials.CUSTOM;
-            }
-        }
-        set {
-            switch (value) {
-            case SmtpCredentials.NONE:
-                this.smtp_use_imap_credentials = false;
-                this.smtp_noauth = true;
-                break;
-            case SmtpCredentials.IMAP:
-                this.smtp_use_imap_credentials = true;
-                this.smtp_noauth = false;
-                break;
-            case SmtpCredentials.CUSTOM:
-                this.smtp_use_imap_credentials = false;
-                this.smtp_noauth = false;
-                break;
-            }
-        }
-    }
-
-    /**
-     * Whether we should NOT authenticate with the server.
-     *
-     * Only valid if this instance represents an SMTP server.
-     */
-    public bool smtp_noauth { get; set; default = false; }
-
-    /**
-     * Specifies if we should use IMAP credentials.
-     *
-     * Only valid if this instance represents an SMTP server.
-     */
-    public bool smtp_use_imap_credentials { get; set; default = true; }
-
-
     /**
      * Constructs a new configuration for a specific service.
      */
     public ServiceInformation(Protocol proto) {
         this.protocol = proto;
+        // Prefer TLS by RFC 8314, but use START_TLS for SMTP for the
+        // moment while its still more widely deployed.
+        this.transport_security = (proto == Protocol.SMTP)
+            ? TlsNegotiationMethod.START_TLS
+            : TlsNegotiationMethod.TRANSPORT;
+        this.credentials_requirement = (proto == Protocol.SMTP)
+            ? Credentials.Requirement.USE_INCOMING
+            : Credentials.Requirement.CUSTOM;
     }
 
     /**
@@ -230,14 +140,12 @@ public class Geary.ServiceInformation : GLib.Object {
         this(other.protocol);
         this.host = other.host;
         this.port = other.port;
-        this.use_starttls = other.use_starttls;
-        this.use_ssl = other.use_ssl;
+        this.transport_security = other.transport_security;
         this.credentials = (
             other.credentials != null ? other.credentials.copy() : null
         );
+        this.credentials_requirement = other.credentials_requirement;
         this.remember_password = other.remember_password;
-        this.smtp_noauth = other.smtp_noauth;
-        this.smtp_use_imap_credentials = other.smtp_use_imap_credentials;
     }
 
 
@@ -249,15 +157,16 @@ public class Geary.ServiceInformation : GLib.Object {
 
         switch (this.protocol) {
         case IMAP:
-            port = this.use_ssl
+            port = (this.transport_security == TlsNegotiationMethod.TRANSPORT)
                 ? Imap.IMAP_TLS_PORT
                 : Imap.IMAP_PORT;
             break;
 
         case SMTP:
-            if (this.use_ssl) {
+            if (this.transport_security == TlsNegotiationMethod.TRANSPORT) {
                 port = Smtp.SUBMISSION_TLS_PORT;
-            } else if (this.smtp_noauth) {
+            } else if (this.credentials_requirement ==
+                       Credentials.Requirement.NONE) {
                 port = Smtp.SMTP_PORT;
             } else {
                 port = Smtp.SUBMISSION_PORT;
@@ -276,13 +185,11 @@ public class Geary.ServiceInformation : GLib.Object {
             this == other ||
             (this.host == other.host &&
              this.port == other.port &&
-             this.use_starttls == other.use_starttls &&
-             this.use_ssl == other.use_ssl &&
+             this.transport_security == other.transport_security &&
              (this.credentials == null && other.credentials == null ||
               this.credentials != null && this.credentials.equal_to(other.credentials)) &&
-             this.remember_password == other.remember_password &&
-             this.smtp_noauth == other.smtp_noauth &&
-             this.smtp_use_imap_credentials == other.smtp_use_imap_credentials)
+             this.credentials_requirement == other.credentials_requirement &&
+             this.remember_password == other.remember_password)
         );
     }
 
diff --git a/src/engine/imap-engine/gmail/imap-engine-gmail-account.vala 
b/src/engine/imap-engine/gmail/imap-engine-gmail-account.vala
index f8d45d63..2e9567be 100644
--- a/src/engine/imap-engine/gmail/imap-engine-gmail-account.vala
+++ b/src/engine/imap-engine/gmail/imap-engine-gmail-account.vala
@@ -20,13 +20,13 @@ private class Geary.ImapEngine.GmailAccount : Geary.ImapEngine.GenericAccount {
         case Protocol.IMAP:
             service.host = "imap.gmail.com";
             service.port = Imap.IMAP_TLS_PORT;
-            service.use_ssl = true;
+            service.transport_security = TlsNegotiationMethod.TRANSPORT;
             break;
 
         case Protocol.SMTP:
             service.host = "smtp.gmail.com";
             service.port = Smtp.SUBMISSION_TLS_PORT;
-            service.use_ssl = true;
+            service.transport_security = TlsNegotiationMethod.TRANSPORT;
             break;
         }
     }
diff --git a/src/engine/imap-engine/imap-engine-account-synchronizer.vala 
b/src/engine/imap-engine/imap-engine-account-synchronizer.vala
index 07405e1b..33ded58f 100644
--- a/src/engine/imap-engine/imap-engine-account-synchronizer.vala
+++ b/src/engine/imap-engine/imap-engine-account-synchronizer.vala
@@ -129,7 +129,7 @@ private class Geary.ImapEngine.RefreshFolderSync : FolderOperation {
                 new ServiceProblemReport(
                     ProblemType.GENERIC_ERROR,
                     this.account.information,
-                    this.account.information.imap,
+                    this.account.information.outgoing,
                     err
                 )
             );
diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala 
b/src/engine/imap-engine/imap-engine-generic-account.vala
index 538f0e8f..041ccb11 100644
--- a/src/engine/imap-engine/imap-engine-generic-account.vala
+++ b/src/engine/imap-engine/imap-engine-generic-account.vala
@@ -67,14 +67,14 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
         this.local = new ImapDB.Account(config);
         this.local.contacts_loaded.connect(() => { contacts_loaded(); });
 
-        this.imap = new Imap.ClientService(config, config.imap);
+        this.imap = new Imap.ClientService(config, config.incoming);
         this.imap.min_pool_size = IMAP_MIN_POOL_SIZE;
         this.imap.ready.connect(on_pool_session_ready);
         this.imap.connection_failed.connect(on_pool_connection_failed);
         this.imap.login_failed.connect(on_pool_login_failed);
 
         this.smtp = new Smtp.ClientService(
-            config, config.smtp, new Outbox.Folder(this, this.local)
+            config, config.outgoing, new Outbox.Folder(this, this.local)
         );
         this.smtp.email_sent.connect(on_email_sent);
         this.smtp.report_problem.connect(notify_report_problem);
@@ -153,8 +153,8 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
 
         // To prevent spurious connection failures, we make sure we
         // have passwords before attempting a connection.
-        yield this.information.load_imap_credentials(cancellable);
-        yield this.information.load_smtp_credentials(cancellable);
+        yield this.information.load_incoming_credentials(cancellable);
+        yield this.information.load_outgoing_credentials(cancellable);
 
         // Start the mail services. Start incoming directly, but queue
         // outgoing so local folders can be loaded first in case
@@ -843,7 +843,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
 
     /** Fires a {@link Account.report_problem} signal for an IMAP service. */
     protected void notify_imap_problem(Geary.ProblemType type, Error? err) {
-        notify_service_problem(type, this.information.imap, err);
+        notify_service_problem(type, this.information.incoming, err);
     }
 
     /**
@@ -1009,7 +1009,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
     private void on_operation_error(AccountOperation op, Error error) {
         if (error is ImapError) {
             notify_service_problem(
-                ProblemType.SERVER_ERROR, this.information.imap, error
+                ProblemType.SERVER_ERROR, this.information.incoming, error
             );
         } else if (error is IOError) {
             // IOErrors could be network related or disk related, need
@@ -1077,11 +1077,12 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
                 notify_imap_problem(ProblemType.SERVER_ERROR, login_error);
             } else {
                 // Now, we should ask the user for their password
-                this.information.prompt_imap_credentials.begin(
+                this.information.prompt_incoming_credentials.begin(
                     this.open_cancellable,
                     (obj, ret) => {
                         try {
-                            if (this.information.prompt_imap_credentials.end(ret)) {
+                            if (this.information
+                                .prompt_incoming_credentials.end(ret)) {
                                 // Have a new password, so try that
                                 this.restart_incoming_service.begin();
                             } else {
diff --git a/src/engine/imap-engine/outlook/imap-engine-outlook-account.vala 
b/src/engine/imap-engine/outlook/imap-engine-outlook-account.vala
index 3a9f17ea..57c1c948 100644
--- a/src/engine/imap-engine/outlook/imap-engine-outlook-account.vala
+++ b/src/engine/imap-engine/outlook/imap-engine-outlook-account.vala
@@ -12,14 +12,13 @@ private class Geary.ImapEngine.OutlookAccount : Geary.ImapEngine.GenericAccount
         case Protocol.IMAP:
             service.host = "imap-mail.outlook.com";
             service.port = Imap.IMAP_TLS_PORT;
-            service.use_ssl = true;
+            service.transport_security = TlsNegotiationMethod.TRANSPORT;
             break;
 
         case Protocol.SMTP:
             service.host = "smtp-mail.outlook.com";
             service.port = Smtp.SUBMISSION_PORT;
-            service.use_ssl = false;
-            service.use_starttls = true;
+            service.transport_security = TlsNegotiationMethod.START_TLS;
             break;
         }
     }
diff --git a/src/engine/imap-engine/yahoo/imap-engine-yahoo-account.vala 
b/src/engine/imap-engine/yahoo/imap-engine-yahoo-account.vala
index ddd9f40b..bbdc543d 100644
--- a/src/engine/imap-engine/yahoo/imap-engine-yahoo-account.vala
+++ b/src/engine/imap-engine/yahoo/imap-engine-yahoo-account.vala
@@ -15,13 +15,13 @@ private class Geary.ImapEngine.YahooAccount : Geary.ImapEngine.GenericAccount {
         case Protocol.IMAP:
             service.host = "imap.mail.yahoo.com";
             service.port = Imap.IMAP_TLS_PORT;
-            service.use_ssl = true;
+            service.transport_security = TlsNegotiationMethod.TRANSPORT;
             break;
 
         case Protocol.SMTP:
             service.host = "smtp.mail.yahoo.com";
             service.port = Smtp.SUBMISSION_TLS_PORT;
-            service.use_ssl = true;
+            service.transport_security = TlsNegotiationMethod.TRANSPORT;
             break;
         }
     }
diff --git a/src/engine/smtp/smtp-client-service.vala b/src/engine/smtp/smtp-client-service.vala
index 911790ee..42b3f2a6 100644
--- a/src/engine/smtp/smtp-client-service.vala
+++ b/src/engine/smtp/smtp-client-service.vala
@@ -255,7 +255,8 @@ internal class Geary.Smtp.ClientService : Geary.ClientService {
 
                         // At this point we may already have a
                         // password in memory -- but it's incorrect.
-                        if (!yield this.account.prompt_smtp_credentials(cancellable)) {
+                        if (!yield this.account
+                            .prompt_outgoing_credentials(cancellable)) {
                             // The user cancelled and hence they don't
                             // want to be prompted again, so bail out.
                             throw send_err;
@@ -289,8 +290,7 @@ internal class Geary.Smtp.ClientService : Geary.ClientService {
         // If we get to this point, the message has either been just
         // sent, or previously sent but not saved. So now try flagging
         // as such and saving it.
-        if (this.account.allow_save_sent_mail() &&
-            this.account.save_sent_mail) {
+        if (this.account.save_sent) {
             try {
                 debug("Outbox postie: Saving %s to sent mail", email.id.to_string());
                 yield save_sent_mail_async(email, cancellable);
@@ -318,7 +318,7 @@ internal class Geary.Smtp.ClientService : Geary.ClientService {
         Error? smtp_err = null;
         try {
             yield smtp.login_async(
-                this.account.get_smtp_credentials(), cancellable
+                this.account.get_outgoing_credentials(), cancellable
             );
         } catch (Error login_err) {
             debug("SMTP login error: %s", login_err.message);
diff --git a/src/engine/util/util-config-file.vala b/src/engine/util/util-config-file.vala
index 92eac5c3..245ab098 100644
--- a/src/engine/util/util-config-file.vala
+++ b/src/engine/util/util-config-file.vala
@@ -201,6 +201,9 @@ public class Geary.ConfigFile {
     }
 
 
+    /** The file this config will be read from and written to. */
+    public GLib.File file { get { return this.config_file; } }
+
     private GLib.File config_file;
     private GLib.KeyFile backing = new KeyFile();
 
diff --git a/test/client/accounts/accounts-manager-test.vala b/test/client/accounts/accounts-manager-test.vala
index 64ee42dd..6d792767 100644
--- a/test/client/accounts/accounts-manager-test.vala
+++ b/test/client/accounts/accounts-manager-test.vala
@@ -126,13 +126,13 @@ class Accounts.ManagerTest : TestCase {
     }
 
     public void account_config_v1() throws GLib.Error {
-        this.account.email_signature = "blarg";
-        this.account.nickname = "test-name";
+        this.account.label = "test-name";
         this.account.ordinal = 100;
         this.account.prefetch_period_days = 42;
         this.account.save_drafts = false;
-        this.account.save_sent_mail = false;
-        this.account.use_email_signature = false;
+        this.account.save_sent = false;
+        this.account.signature = "blarg";
+        this.account.use_signature = false;
         Accounts.AccountConfigV1 config = new Accounts.AccountConfigV1(false);
 
         Geary.ConfigFile file =
@@ -147,13 +147,13 @@ class Accounts.ManagerTest : TestCase {
     }
 
     public void account_config_legacy() throws GLib.Error {
-        this.account.email_signature = "blarg";
-        this.account.nickname = "test-name";
+        this.account.label = "test-name";
         this.account.ordinal = 100;
         this.account.prefetch_period_days = 42;
         this.account.save_drafts = false;
-        this.account.save_sent_mail = false;
-        this.account.use_email_signature = false;
+        this.account.save_sent = false;
+        this.account.signature = "blarg";
+        this.account.use_signature = false;
         Accounts.AccountConfigLegacy config =
             new Accounts.AccountConfigLegacy();
 
@@ -175,21 +175,22 @@ class Accounts.ManagerTest : TestCase {
             this.account
         );
 
-        this.account.smtp.host = "blarg";
-        this.account.smtp.port = 1234;
-        this.account.smtp.transport_security = Geary.TlsNegotiationMethod.NONE;
-        this.account.smtp.smtp_credentials_source = Geary.SmtpCredentials.CUSTOM;
-        this.account.smtp.credentials = new Geary.Credentials(
+        this.account.outgoing.host = "blarg";
+        this.account.outgoing.port = 1234;
+        this.account.outgoing.transport_security = Geary.TlsNegotiationMethod.NONE;
+        this.account.outgoing.credentials = new Geary.Credentials(
             Geary.Credentials.Method.PASSWORD, "testerson"
         );
+        this.account.outgoing.credentials_requirement =
+            Geary.Credentials.Requirement.NONE;
         Accounts.ServiceConfigV1 config = new Accounts.ServiceConfigV1();
         Geary.ConfigFile file =
             new Geary.ConfigFile(this.tmp.get_child("config"));
 
-        config.save(this.account, this.account.smtp, file);
-        config.load(file, copy, copy.smtp);
+        config.save(this.account, this.account.outgoing, file);
+        config.load(file, copy, copy.outgoing);
 
-        assert_true(this.account.smtp.equal_to(copy.smtp));
+        assert_true(this.account.outgoing.equal_to(copy.outgoing));
     }
 
     public void service_config_legacy() throws GLib.Error {
@@ -199,21 +200,22 @@ class Accounts.ManagerTest : TestCase {
             this.account
         );
 
-        this.account.smtp.host = "blarg";
-        this.account.smtp.port = 1234;
-        this.account.smtp.transport_security = Geary.TlsNegotiationMethod.NONE;
-        this.account.smtp.smtp_credentials_source = Geary.SmtpCredentials.CUSTOM;
-        this.account.smtp.credentials = new Geary.Credentials(
+        this.account.outgoing.host = "blarg";
+        this.account.outgoing.port = 1234;
+        this.account.outgoing.transport_security = Geary.TlsNegotiationMethod.NONE;
+        this.account.outgoing.credentials = new Geary.Credentials(
             Geary.Credentials.Method.PASSWORD, "testerson"
         );
+        this.account.outgoing.credentials_requirement =
+            Geary.Credentials.Requirement.NONE;
         Accounts.ServiceConfigLegacy config = new Accounts.ServiceConfigLegacy();
         Geary.ConfigFile file =
             new Geary.ConfigFile(this.tmp.get_child("config"));
 
-        config.save(this.account, this.account.smtp, file);
-        config.load(file, copy, copy.smtp);
+        config.save(this.account, this.account.outgoing, file);
+        config.load(file, copy, copy.outgoing);
 
-        assert_true(this.account.smtp.equal_to(copy.smtp));
+        assert_true(this.account.outgoing.equal_to(copy.outgoing));
     }
 
     private void delete(File parent) throws GLib.Error {
diff --git a/test/engine/api/geary-account-mock.vala b/test/engine/api/geary-account-mock.vala
index 319c1067..b1efca93 100644
--- a/test/engine/api/geary-account-mock.vala
+++ b/test/engine/api/geary-account-mock.vala
@@ -70,8 +70,8 @@ public class Geary.MockAccount : Account, MockObject {
 
     public MockAccount(AccountInformation config) {
         base(config);
-        this._incoming = new MockClientService(config, config.imap);
-        this._outgoing = new MockClientService(config, config.smtp);
+        this._incoming = new MockClientService(config, config.incoming);
+        this._outgoing = new MockClientService(config, config.outgoing);
     }
 
     public override async void open_async(Cancellable? cancellable = null) throws Error {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]