[geary/wip/714104-refine-account-dialog] Enable config file versioning
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/714104-refine-account-dialog] Enable config file versioning
- Date: Sun, 9 Dec 2018 08:27:42 +0000 (UTC)
commit 123f51dbb2349417c6804fad2ae0144022f6934a
Author: Michael Gratton <mike vee net>
Date: Fri Dec 7 10:12:02 2018 +1100
Enable config file versioning
This (way too large patch) enables versioning in config files, and
provides a mechanism by which to load older versions from a newer
version of Geary. It also properly introduces a new v1 config format
that adds several groups to geary.ini to make it easier to read and to
distinguish between incoming/outgoig services rather than IMAP/SMTP.
To do this, a few things that should have happened in seperate patches
were also done:
* Make AccountInformation's imap and smtp properties mutable (they
aren't stateful any more anyway), make ServiceInformation non-abstract
again and remove the subclasses (to get config versioning happening
without an explosion of a classes, it all has to be handled from the
AccountManager anyway), and some other misc things.
po/POTFILES.in | 2 -
src/client/accounts/accounts-editor-add-pane.vala | 26 +-
src/client/accounts/accounts-editor-list-pane.vala | 2 +-
.../accounts/accounts-editor-servers-pane.vala | 4 +-
src/client/accounts/accounts-manager.vala | 1093 ++++++++++++++------
src/client/accounts/add-edit-page.vala | 29 +-
src/client/accounts/goa-service-information.vala | 105 --
src/client/accounts/local-service-information.vala | 84 --
src/client/application/goa-mediator.vala | 105 +-
src/client/meson.build | 2 -
src/engine/api/geary-account-information.vala | 140 +--
src/engine/api/geary-engine.vala | 32 +-
src/engine/api/geary-service-information.vala | 51 +-
src/engine/util/util-config-file.vala | 38 +-
src/engine/util/util-object.vala | 4 +-
test/client/accounts/accounts-manager-test.vala | 126 ++-
.../engine/api/geary-account-information-test.vala | 10 +-
test/engine/api/geary-engine-test.vala | 9 +-
.../engine/api/geary-service-information-mock.vala | 29 -
test/engine/app/app-conversation-monitor-test.vala | 3 +-
.../engine/imap-engine/account-processor-test.vala | 3 +-
test/engine/util-config-file-test.vala | 7 -
test/meson.build | 2 -
23 files changed, 1181 insertions(+), 725 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0fddc2a9..d3f2263c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -24,8 +24,6 @@ src/client/accounts/accounts-editor-row.vala
src/client/accounts/accounts-editor-servers-pane.vala
src/client/accounts/accounts-manager.vala
src/client/accounts/add-edit-page.vala
-src/client/accounts/goa-service-information.vala
-src/client/accounts/local-service-information.vala
src/client/accounts/login-dialog.vala
src/client/application/application-avatar-store.vala
src/client/application/autostart-manager.vala
diff --git a/src/client/accounts/accounts-editor-add-pane.vala
b/src/client/accounts/accounts-editor-add-pane.vala
index bb85ab25..e8771d05 100644
--- a/src/client/accounts/accounts-editor-add-pane.vala
+++ b/src/client/accounts/accounts-editor-add-pane.vala
@@ -159,16 +159,18 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane {
string message = "";
Gtk.Widget? to_focus = null;
- Geary.ServiceInformation imap = new_imap_service();
- Geary.ServiceInformation smtp = new_smtp_service();
-
Geary.AccountInformation account =
- this.accounts.new_orphan_account(this.provider, imap, smtp);
+ this.accounts.new_orphan_account(
+ this.provider,
+ new Geary.RFC822.MailboxAddress(
+ this.real_name.value.text.strip(),
+ this.email.value.text.strip()
+ )
+ );
+
+ account.imap = new_imap_service();
+ account.imap = new_smtp_service();
- account.append_sender(new Geary.RFC822.MailboxAddress(
- this.real_name.value.text.strip(),
- this.email.value.text.strip()
- ));
account.nickname = account.primary_mailbox.address;
if (this.provider == Geary.ServiceProvider.OTHER) {
@@ -275,8 +277,8 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane {
}
}
- private LocalServiceInformation new_imap_service() {
- LocalServiceInformation service =
+ private Geary.ServiceInformation new_imap_service() {
+ Geary.ServiceInformation service =
this.accounts.new_libsecret_service(Geary.Protocol.IMAP);
if (this.provider == Geary.ServiceProvider.OTHER) {
@@ -309,8 +311,8 @@ internal class Accounts.EditorAddPane : Gtk.Grid, EditorPane {
return service;
}
- private LocalServiceInformation new_smtp_service() {
- LocalServiceInformation service =
+ private Geary.ServiceInformation new_smtp_service() {
+ Geary.ServiceInformation service =
this.accounts.new_libsecret_service(Geary.Protocol.SMTP);
if (this.provider == Geary.ServiceProvider.OTHER) {
diff --git a/src/client/accounts/accounts-editor-list-pane.vala
b/src/client/accounts/accounts-editor-list-pane.vala
index aa49936d..71f1958b 100644
--- a/src/client/accounts/accounts-editor-list-pane.vala
+++ b/src/client/accounts/accounts-editor-list-pane.vala
@@ -454,7 +454,7 @@ private class Accounts.AddServiceProviderRow : EditorRow<EditorListPane> {
bool add_local = false;
try {
pane.accounts.add_goa_account.end(res);
- } catch (Error.INVALID err) {
+ } catch (GLib.IOError.NOT_SUPPORTED err) {
// Not a supported type, so don't bother logging the error
add_local = true;
} catch (GLib.Error err) {
diff --git a/src/client/accounts/accounts-editor-servers-pane.vala
b/src/client/accounts/accounts-editor-servers-pane.vala
index edd610ab..3cf8db9d 100644
--- a/src/client/accounts/accounts-editor-servers-pane.vala
+++ b/src/client/accounts/accounts-editor-servers-pane.vala
@@ -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 = account.imap.temp_copy();
- this.smtp_mutable = account.smtp.temp_copy();
+ this.imap_mutable = new Geary.ServiceInformation.copy(account.imap);
+ this.smtp_mutable = new Geary.ServiceInformation.copy(account.smtp);
this.pane_content.set_focus_vadjustment(this.pane_adjustment);
diff --git a/src/client/accounts/accounts-manager.vala b/src/client/accounts/accounts-manager.vala
index 836085bd..63fec935 100644
--- a/src/client/accounts/accounts-manager.vala
+++ b/src/client/accounts/accounts-manager.vala
@@ -47,10 +47,49 @@ public enum Accounts.CredentialsProvider {
}
}
-public errordomain Accounts.Error {
- INVALID,
- LOCAL_REMOVED,
- GOA_REMOVED;
+
+/** Objects that can be used load/save account configuration. */
+public interface Accounts.AccountConfig : GLib.Object {
+
+ /** Loads a supported account from a config file. */
+ public abstract Geary.AccountInformation
+ load(Geary.ConfigFile config,
+ string id,
+ Geary.ServiceProvider? default_provider,
+ string? default_name)
+ throws ConfigError, GLib.KeyFileError;
+
+ /** Saves an account to a config file. */
+ public abstract void save(Geary.AccountInformation account,
+ Geary.ConfigFile config);
+
+}
+
+
+/** Objects that can be used load/save service configuration. */
+public interface Accounts.ServiceConfig : GLib.Object {
+
+ /** Loads a service from a config file. */
+ public abstract Geary.ServiceInformation
+ load(Geary.ConfigFile config,
+ Geary.AccountInformation account,
+ Geary.Protocol protocol,
+ Geary.CredentialsMediator mediator)
+ throws ConfigError, GLib.KeyFileError;
+
+ /** Saves a service to a config file. */
+ public abstract void save(Geary.AccountInformation account,
+ Geary.ServiceInformation service,
+ Geary.ConfigFile config);
+
+}
+
+public errordomain Accounts.ConfigError {
+ IO,
+ SYNTAX,
+ UNSUPPORTED_VERSION,
+ UNAVAILABLE,
+ REMOVED;
}
@@ -61,7 +100,8 @@ public errordomain Accounts.Error {
* removing accounts and their persisted data (configuration,
* databases, caches, authentication tokens). The manager supports
* both locally-specified accounts (i.e. those created by the user in
- * the app) and from SSO systems such as GOA.
+ * the app) and from SSO systems such as GOA via the Accounts.Provider
+ * interface.
*
* Newly loaded and newly created accounts are first added to the
* manager with a particular status (enabled, disabled, etc). Accounts
@@ -74,30 +114,13 @@ public class Accounts.Manager : GLib.Object {
private const string LOCAL_ID_FORMAT = "account_%02u";
private const string GOA_ID_PREFIX = "goa_";
- private const string ACCOUNT_CONFIG_GROUP = "AccountInformation";
- private const string ACCOUNT_MANAGER_GROUP = "AccountManager";
- private const string IMAP_CONFIG_GROUP = "IMAP";
- private const string SMTP_CONFIG_GROUP = "SMTP";
+ private const int CONFIG_VERSION = 1;
- private const string ALTERNATE_EMAILS_KEY = "alternate_emails";
- private const string ARCHIVE_FOLDER_KEY = "archive_folder";
- private const string CREDENTIALS_METHOD_KEY = "credentials_method";
- private const string CREDENTIALS_PROVIDER_KEY = "credentials_provider";
- private const string DRAFTS_FOLDER_KEY = "drafts_folder";
- private const string EMAIL_SIGNATURE_KEY = "email_signature";
- private const string NICKNAME_KEY = "nickname";
- private const string ORDINAL_KEY = "ordinal";
- private const string PREFETCH_PERIOD_DAYS_KEY = "prefetch_period_days";
- private const string PRIMARY_EMAIL_KEY = "primary_email";
- private const string REMOVED_KEY = "removed";
- private const string REAL_NAME_KEY = "real_name";
- private const string SAVE_DRAFTS_KEY = "save_drafts";
- private const string SAVE_SENT_MAIL_KEY = "save_sent_mail";
- private const string SENT_MAIL_FOLDER_KEY = "sent_mail_folder";
- private const string SERVICE_PROVIDER_KEY = "service_provider";
- private const string SPAM_FOLDER_KEY = "spam_folder";
- private const string TRASH_FOLDER_KEY = "trash_folder";
- private const string USE_EMAIL_SIGNATURE_KEY = "use_email_signature";
+ private const string GROUP_METADATA = "Metadata";
+
+ private const string METADATA_STATUS = "status";
+ private const string METADATA_VERSION = "version";
+ private const string METADATA_GOA = "goa_id";
/**
@@ -110,8 +133,24 @@ public class Accounts.Manager : GLib.Object {
/** The account was disabled by the user. */
DISABLED,
- /** The account is unavailable to be used, by may come back. */
- UNAVAILABLE;
+ /** The account is unavailable to be used, but may come back. */
+ UNAVAILABLE,
+
+ /** The account has been removed and is scheduled for deletion. */
+ REMOVED;
+
+ public static Status for_value(string value)
+ throws Geary.EngineError {
+ return Geary.ObjectUtils.from_enum_nick<Status>(
+ typeof(Status), value.ascii_down()
+ );
+ }
+
+ public string to_value() {
+ return Geary.ObjectUtils.to_enum_nick<Status>(
+ typeof(Status), this
+ );
+ }
}
@@ -241,8 +280,7 @@ public class Accounts.Manager : GLib.Object {
*/
public Geary.AccountInformation
new_orphan_account(Geary.ServiceProvider provider,
- Geary.ServiceInformation imap,
- Geary.ServiceInformation smtp) {
+ Geary.RFC822.MailboxAddress primary_mailbox) {
string? last_account = this.accounts.keys.fold<string?>((next, last) => {
string? result = last;
if (next.has_prefix(LOCAL_ID_PREFIX)) {
@@ -257,11 +295,11 @@ public class Accounts.Manager : GLib.Object {
}
string id = LOCAL_ID_FORMAT.printf(next_id);
- return new Geary.AccountInformation(id, provider, imap, smtp);
+ return new Geary.AccountInformation(id, provider, primary_mailbox);
}
- public LocalServiceInformation new_libsecret_service(Geary.Protocol service) {
- return new LocalServiceInformation(service, libsecret);
+ public Geary.ServiceInformation new_libsecret_service(Geary.Protocol service) {
+ return new Geary.ServiceInformation(service, libsecret);
}
/**
@@ -432,7 +470,7 @@ public class Accounts.Manager : GLib.Object {
* Determines if an account is a GOA account or not.
*/
public bool is_goa_account(Geary.AccountInformation account) {
- return (account.imap is GoaServiceInformation);
+ return (account.imap.mediator is GoaMediator);
}
/**
@@ -454,7 +492,7 @@ public class Accounts.Manager : GLib.Object {
break;
default:
- throw new Error.INVALID("Not supported for GOA");
+ throw new GLib.IOError.NOT_SUPPORTED("Not supported for GOA");
}
}
@@ -467,14 +505,12 @@ public class Accounts.Manager : GLib.Object {
public async void show_goa_account(Geary.AccountInformation account,
GLib.Cancellable? cancellable)
throws GLib.Error {
- GoaServiceInformation? goa_service =
- account.imap as GoaServiceInformation;
- if (goa_service == null) {
- throw new Error.INVALID("Not a GOA Account");
+ if (!is_goa_account(account)) {
+ throw new GLib.IOError.NOT_SUPPORTED("Not a GOA Account");
}
yield open_goa_settings(
- goa_service.account.account.id, null, cancellable
+ to_goa_id(account.id), null, cancellable
);
}
@@ -486,228 +522,182 @@ public class Accounts.Manager : GLib.Object {
*/
private async Geary.AccountInformation
load_account(string id, GLib.Cancellable? cancellable)
- throws GLib.Error {
+ throws ConfigError {
GLib.File config_dir = this.user_config_dir.get_child(id);
GLib.File data_dir = this.user_data_dir.get_child(id);
- Geary.ConfigFile config_file = new Geary.ConfigFile(
+ Geary.ConfigFile config = new Geary.ConfigFile(
config_dir.get_child(Geary.AccountInformation.SETTINGS_FILENAME)
);
- yield config_file.load(cancellable);
-
- Geary.ConfigFile.Group config = config_file.get_group(ACCOUNT_CONFIG_GROUP);
- CredentialsProvider provider = CredentialsProvider.from_string(
- config.get_string(
- CREDENTIALS_PROVIDER_KEY,
- CredentialsProvider.LIBSECRET.to_string()
- )
- );
+ try {
+ yield config.load(cancellable);
+ } catch (GLib.KeyFileError err) {
+ throw new ConfigError.SYNTAX(err.message);
+ } catch (GLib.Error err) {
+ throw new ConfigError.IO(err.message);
+ }
- string primary_email = config.get_string(PRIMARY_EMAIL_KEY);
+ Geary.ConfigFile.Group metadata_config =
+ config.get_group(GROUP_METADATA);
+ int version = metadata_config.get_int(METADATA_VERSION, 0);
+ Status status = Status.ENABLED;
+ try {
+ status = Status.for_value(
+ metadata_config.get_string(
+ METADATA_STATUS, status.to_value()
+ ));
+ } catch (Geary.EngineError err) {
+ throw new ConfigError.SYNTAX("%s: Invalid status value", id);
+ }
- Geary.AccountInformation? info = null;
- switch (provider) {
- case CredentialsProvider.LIBSECRET:
- info = new_libsecret_account(id, config, primary_email);
- break;
+ string? goa_id = metadata_config.get_string(METADATA_GOA, null);
+ bool is_goa = (goa_id != null);
+ GoaMediator? goa_mediator = null;
+ Geary.ServiceProvider? default_provider = null;
+ Geary.CredentialsMediator mediator = this.libsecret;
- case CredentialsProvider.GOA:
- if (this.goa_service != null) {
- Goa.Object? object = this.goa_service.lookup_by_id(to_goa_id(id));
- if (object != null) {
- info = new_goa_account(id, object);
- GoaMediator mediator = (GoaMediator) info.imap.mediator;
- try {
- yield mediator.update(info, cancellable);
- } catch (GLib.Error err) {
- report_problem(
- new Geary.ProblemReport(
- Geary.ProblemType.GENERIC_ERROR,
- err
- ));
- }
- } else {
- // Could not find the GOA object for this account,
- // but have a working GOA connection, so it must
- // have been removed. Not much else that we can do
- // except remove it.
- throw new Error.GOA_REMOVED("GOA account not found");
- }
+ if (is_goa) {
+ if (this.goa_service == null) {
+ throw new ConfigError.UNAVAILABLE("GOA service not available");
}
- if (info == null) {
- // We have a GOA account, but either GOA is
- // unavailable or the account has changed. Keep it
- // around in case GOA comes back.
- throw new Error.INVALID("GOA not available");
+ Goa.Object? goa_handle = this.goa_service.lookup_by_id(goa_id);
+ if (goa_handle != null) {
+ mediator = goa_mediator = new GoaMediator(goa_handle);
+ default_provider = goa_mediator.get_service_provider();
+ } else {
+ // The GOA account has gone away, so there's nothing
+ // we can do except to remove it locally as well
+ info(
+ "%s: GOA account %s has been removed, removing local data",
+ id, goa_id
+ );
+ status = Status.REMOVED;
+ // Use the default mediator since we can't create a
+ // GOA equiv, but set a dummy default provider so we
+ // don't get an error loading the config
+ default_provider = Geary.ServiceProvider.OTHER;
}
- break;
}
- info.set_account_directories(config_dir, data_dir);
-
- info.ordinal = config.get_int(ORDINAL_KEY, info.ordinal);
- if (info.ordinal >= Geary.AccountInformation.next_ordinal)
- Geary.AccountInformation.next_ordinal = info.ordinal + 1;
-
- info.append_sender(new Geary.RFC822.MailboxAddress(
- config.get_string(REAL_NAME_KEY), primary_email
- ));
+ AccountConfig? accounts = null;
+ ServiceConfig? services = null;
+ switch (version) {
+ case 0:
+ accounts = new AccountConfigLegacy();
+ services = new ServiceConfigLegacy();
+ break;
- info.nickname = config.get_string(NICKNAME_KEY);
+ case 1:
+ accounts = new AccountConfigV1(is_goa);
+ services = new ServiceConfigV1();
+ break;
- // Store alternate emails in a list of case-insensitive strings
- Gee.List<string> alt_email_list = config.get_string_list(
- ALTERNATE_EMAILS_KEY
- );
- if (alt_email_list.size != 0) {
- foreach (string alt_email in alt_email_list) {
- Geary.RFC822.MailboxAddresses mailboxes = new
Geary.RFC822.MailboxAddresses.from_rfc822_string(alt_email);
- foreach (Geary.RFC822.MailboxAddress mailbox in mailboxes.get_all())
- info.append_sender(mailbox);
- }
+ default:
+ throw new ConfigError.UNSUPPORTED_VERSION(
+ "Unsupported config version: %d", version
+ );
}
- 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.use_email_signature = config.get_bool(
- USE_EMAIL_SIGNATURE_KEY, info.use_email_signature
- );
- info.email_signature = config.get_escaped_string(
- EMAIL_SIGNATURE_KEY, info.email_signature
- );
+ Geary.AccountInformation? account = null;
+ try {
+ account = accounts.load(
+ config,
+ id,
+ default_provider,
+ get_account_name()
+ );
+ account.set_account_directories(config_dir, data_dir);
+ } catch (GLib.KeyFileError err) {
+ throw new ConfigError.SYNTAX(err.message);
+ }
- 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(
- config.get_string_list(SENT_MAIL_FOLDER_KEY)
- );
- info.spam_folder_path = Geary.AccountInformation.build_folder_path(
- config.get_string_list(SPAM_FOLDER_KEY)
- );
- info.trash_folder_path = Geary.AccountInformation.build_folder_path(
- config.get_string_list(TRASH_FOLDER_KEY)
- );
- info.archive_folder_path = Geary.AccountInformation.build_folder_path(
- config.get_string_list(ARCHIVE_FOLDER_KEY)
- );
+ // If the account has been marked as removed, now that we have
+ // an account object and its dirs have been set up we can add
+ // it to the removed list and just bail out.
+ if (status == Status.REMOVED) {
+ this.removed.add(account);
+ throw new ConfigError.REMOVED("Account marked for removal");
+ }
- info.save_drafts = config.get_bool(SAVE_DRAFTS_KEY, true);
+ if (!is_goa) {
+ try {
+ account.imap = services.load(
+ config, account, Geary.Protocol.IMAP, mediator
+ );
+ account.smtp = services.load(
+ config, account, Geary.Protocol.SMTP, mediator
+ );
+ } catch (GLib.KeyFileError err) {
+ throw new ConfigError.SYNTAX(err.message);
+ }
+ } else {
+ account.service_label = goa_mediator.get_service_label();
+ account.imap = new Geary.ServiceInformation(Geary.Protocol.IMAP, mediator);
+ account.smtp = new Geary.ServiceInformation(Geary.Protocol.SMTP, mediator);
- // If the account has been removed, add it to the removed list
- // and bail out
- Geary.ConfigFile.Group manager_config =
- config_file.get_group(ACCOUNT_MANAGER_GROUP);
- if (manager_config.exists &&
- manager_config.get_bool(REMOVED_KEY, false)) {
- this.removed.add(info);
- throw new Error.LOCAL_REMOVED("Account marked for removal");
+ try {
+ // This updates the service configs as well
+ yield goa_mediator.update(account, cancellable);
+ } catch (GLib.Error err) {
+ // If we get an error here, there might have been a
+ // problem loading the GOA data, or the OAuth token
+ // has expired. XXX Need to distinguish between the
+ // two.
+ set_available(account, false);
+ throw new ConfigError.UNAVAILABLE(err.message);
+ }
}
- return info;
+ return account;
}
- private async void save_account_locked(Geary.AccountInformation info,
+ private async void save_account_locked(Geary.AccountInformation account,
GLib.Cancellable? cancellable)
throws GLib.Error {
- File? file = info.settings_file;
+ File? file = account.settings_file;
if (file == null) {
- throw new Error.INVALID(
- "Account information does not have a settings file"
+ throw new GLib.IOError.NOT_SUPPORTED(
+ "Account %s does not have a settings file", account.id
);
}
- Geary.ConfigFile config_file = new Geary.ConfigFile(file);
+ Geary.ConfigFile config = new Geary.ConfigFile(file);
// Load the file first so we maintain old settings
try {
- yield config_file.load(cancellable);
+ yield config.load(cancellable);
} catch (GLib.Error err) {
// Oh well, just create a new one when saving
debug("Could not load existing config file: %s", err.message);
}
- // If the account has been removed, set it as such. Otherwise
- // ensure it is not set as such.
- Geary.ConfigFile.Group manager_config =
- config_file.get_group(ACCOUNT_MANAGER_GROUP);
- if (this.removed.contains(info)) {
- manager_config.set_bool(REMOVED_KEY, true);
- } else if (manager_config.exists) {
- manager_config.remove();
- }
-
- Geary.ConfigFile.Group config = config_file.get_group(ACCOUNT_CONFIG_GROUP);
- if (info.imap is LocalServiceInformation) {
- config.set_string(
- CREDENTIALS_PROVIDER_KEY,
- CredentialsProvider.LIBSECRET.to_string()
- );
- config.set_string(
- CREDENTIALS_METHOD_KEY,
- info.imap.credentials.supported_method.to_string()
- );
-
- if (info.service_provider == Geary.ServiceProvider.OTHER) {
- Geary.ConfigFile.Group imap_config = config_file.get_group(
- IMAP_CONFIG_GROUP
- );
- ((LocalServiceInformation) info.imap).save_settings(imap_config);
+ Geary.ConfigFile.Group metadata_config =
+ config.get_group(GROUP_METADATA);
+ metadata_config.set_int(
+ METADATA_VERSION, CONFIG_VERSION
+ );
+ metadata_config.set_string(
+ METADATA_STATUS, get_status(account).to_value()
+ );
- Geary.ConfigFile.Group smtp_config = config_file.get_group(
- SMTP_CONFIG_GROUP
- );
- ((LocalServiceInformation) info.smtp).save_settings(smtp_config);
- }
- } else if (info.imap is GoaServiceInformation) {
- config.set_string(
- CREDENTIALS_PROVIDER_KEY, CredentialsProvider.GOA.to_string()
- );
+ bool is_goa = is_goa_account(account);
+ if (is_goa) {
+ metadata_config.set_string(METADATA_GOA, to_goa_id(account.id));
}
- 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(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_escaped_string(EMAIL_SIGNATURE_KEY, info.email_signature);
- if (info.has_sender_aliases) {
- Gee.List<Geary.RFC822.MailboxAddress> alts = info.sender_mailboxes;
- alts.remove_at(0);
-
- Gee.List<string> values = new Gee.LinkedList<string>();
- foreach (Geary.RFC822.MailboxAddress alt in alts) {
- values.add(alt.to_rfc822_string());
- }
+ AccountConfig accounts = new AccountConfigV1(is_goa);
+ accounts.save(account, config);
- config.set_string_list(ALTERNATE_EMAILS_KEY, values);
+ if (!is_goa) {
+ ServiceConfig services = new ServiceConfigV1();
+ services.save(account, account.imap, config);
+ services.save(account, account.smtp, config);
}
- 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(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
- ? info.trash_folder_path.as_list() : empty));
- config.set_string_list(ARCHIVE_FOLDER_KEY, (info.archive_folder_path != null
- ? info.archive_folder_path.as_list() : empty));
-
- config.set_bool(SAVE_DRAFTS_KEY, info.save_drafts);
-
debug("Writing config to: %s", file.get_path());
- yield config_file.save(cancellable);
+ yield config.save(cancellable);
}
private async void delete_account(Geary.AccountInformation info,
@@ -811,99 +801,26 @@ public class Accounts.Manager : GLib.Object {
: id;
}
- private Geary.AccountInformation
- new_libsecret_account(string id,
- Geary.ConfigFile.Group config,
- string fallback_login)
- throws GLib.Error {
-
- Geary.ServiceProvider provider = Geary.ServiceProvider.for_value(
- config.get_string(SERVICE_PROVIDER_KEY,
- Geary.ServiceProvider.GMAIL.to_string())
- );
- Geary.Credentials.Method method = Geary.Credentials.Method.from_string(
- config.get_string(CREDENTIALS_METHOD_KEY,
- Geary.Credentials.Method.PASSWORD.to_string())
- );
-
- Geary.ConfigFile.Group imap_config =
- config.file.get_group(IMAP_CONFIG_GROUP);
- LocalServiceInformation imap = new_libsecret_service(
- Geary.Protocol.IMAP
- );
- imap_config.set_fallback(config.name, "imap_");
- imap.load_credentials(imap_config, method, fallback_login);
-
- Geary.ConfigFile.Group smtp_config =
- config.file.get_group(SMTP_CONFIG_GROUP);
- LocalServiceInformation smtp = new_libsecret_service(
- Geary.Protocol.SMTP
- );
- smtp_config.set_fallback(config.name, "smtp_");
- smtp.load_credentials(smtp_config, method, fallback_login);
-
- // Generic IMAP accounts must load their settings from their
- // config, GMail and others have it hard-coded hence don't
- // need to load it.
- if (provider == Geary.ServiceProvider.OTHER) {
- imap.load_settings(imap_config);
- smtp.load_settings(smtp_config);
- } else {
- provider.setup_service(imap);
- provider.setup_service(smtp);
- }
-
- return new Geary.AccountInformation(
- id, provider, imap, smtp
- );
- }
-
- private Geary.AccountInformation new_goa_account(string id,
- Goa.Object account) {
- GoaMediator mediator = new GoaMediator(account);
-
- Geary.ServiceProvider provider = Geary.ServiceProvider.OTHER;
- switch (account.get_account().provider_type) {
- case "google":
- provider = Geary.ServiceProvider.GMAIL;
- break;
-
- case "windows_live":
- provider = Geary.ServiceProvider.OUTLOOK;
- break;
- }
-
- Geary.AccountInformation info = new Geary.AccountInformation(
- id,
- provider,
- new GoaServiceInformation(Geary.Protocol.IMAP, mediator, account),
- new GoaServiceInformation(Geary.Protocol.SMTP, mediator, account)
- );
- info.service_label = account.get_account().provider_name;
-
- return info;
- }
-
private async void create_goa_account(Goa.Object account,
GLib.Cancellable? cancellable) {
- Geary.AccountInformation info = new_goa_account(
- to_geary_id(account), account
- );
-
- GoaMediator mediator = (GoaMediator) info.imap.mediator;
// Goa.Account.mail_disabled doesn't seem to reflect if we get
// get a valid mail object here, so just rely on that instead.
Goa.Mail? mail = account.get_mail();
if (mail != null) {
- info.ordinal = Geary.AccountInformation.next_ordinal++;
-
string? name = mail.name;
if (Geary.String.is_empty_or_whitespace(name)) {
name = get_account_name();
}
- info.append_sender(new Geary.RFC822.MailboxAddress(
- name, mail.email_address
- ));
+
+ GoaMediator mediator = new GoaMediator(account);
+ Geary.AccountInformation info = new Geary.AccountInformation(
+ to_geary_id(account),
+ mediator.get_service_provider(),
+ new Geary.RFC822.MailboxAddress(name, mail.email_address)
+ );
+
+ info.ordinal = Geary.AccountInformation.next_ordinal++;
+ info.service_label = mediator.get_service_label();
info.nickname = account.get_account().presentation_identity;
try {
@@ -1037,3 +954,577 @@ public class Accounts.Manager : GLib.Object {
}
}
+
+/**
+ * Manages persistence for version 1 config files.
+ */
+public class Accounts.AccountConfigV1 : AccountConfig, GLib.Object {
+
+
+ private const string GROUP_ACCOUNT = "Account";
+ private const string GROUP_FOLDERS = "Folders";
+
+ private const string ACCOUNT_LABEL = "label";
+ private const string ACCOUNT_ORDINAL = "ordinal";
+ private const string ACCOUNT_PREFETCH = "prefetch_days";
+ private const string ACCOUNT_PROVIDER = "service_provider";
+ private const string ACCOUNT_SAVE_DRAFTS = "save_drafts";
+ private const string ACCOUNT_SAVE_SENT = "save_sent";
+ private const string ACCOUNT_SENDERS = "sender_mailboxes";
+ private const string ACCOUNT_SIG = "signature";
+ private const string ACCOUNT_USE_SIG = "use_signature";
+
+ 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_SPAM = "spam_folder";
+ private const string FOLDER_TRASH = "trash_folder";
+
+
+ private bool is_managed;
+
+ public AccountConfigV1(bool is_managed) {
+ this.is_managed = is_managed;
+ }
+
+ public Geary.AccountInformation load(Geary.ConfigFile config,
+ string id,
+ Geary.ServiceProvider? default_provider,
+ string? default_name)
+ throws ConfigError, GLib.KeyFileError {
+ Geary.ConfigFile.Group account_config =
+ config.get_group(GROUP_ACCOUNT);
+
+ Gee.List<Geary.RFC822.MailboxAddress> senders =
+ new Gee.LinkedList<Geary.RFC822.MailboxAddress>();
+ foreach (string sender in
+ account_config.get_required_string_list(ACCOUNT_SENDERS)) {
+ try {
+ senders.add(
+ new Geary.RFC822.MailboxAddress.from_rfc822_string(sender)
+ );
+ } catch (Geary.RFC822Error err) {
+ throw new ConfigError.SYNTAX(
+ "%s: Invalid sender address: %s", id, sender
+ );
+ }
+ }
+
+ if (senders.is_empty) {
+ throw new ConfigError.SYNTAX("%s: No sender addresses found", id);
+ }
+
+ Geary.ServiceProvider? provider = null;
+ try {
+ provider = default_provider ??
+ Geary.ServiceProvider.for_value(
+ account_config.get_required_string(ACCOUNT_PROVIDER)
+ );
+ } catch (Geary.EngineError err) {
+ throw new ConfigError.SYNTAX("%s: No/bad service provider", id);
+ }
+
+ Geary.AccountInformation account = new Geary.AccountInformation(
+ id, provider, senders.remove_at(0)
+ );
+
+ account.ordinal = account_config.get_int(
+ ACCOUNT_ORDINAL, Geary.AccountInformation.next_ordinal++
+ );
+ account.nickname = account_config.get_string(
+ ACCOUNT_LABEL, account.nickname
+ );
+ account.prefetch_period_days = account_config.get_int(
+ ACCOUNT_PREFETCH, account.prefetch_period_days
+ );
+ 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.use_email_signature = account_config.get_bool(
+ ACCOUNT_USE_SIG, account.use_email_signature
+ );
+ account.email_signature = account_config.get_string(
+ ACCOUNT_SIG, account.email_signature
+ );
+ foreach (Geary.RFC822.MailboxAddress sender in senders) {
+ account.append_sender(sender);
+ }
+
+ Geary.ConfigFile.Group folder_config =
+ 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.spam_folder_path = load_folder(folder_config, FOLDER_SPAM);
+ account.trash_folder_path = load_folder(folder_config, FOLDER_TRASH);
+
+ return account;
+ }
+
+ /** Saves an account to a config file. */
+ public void save(Geary.AccountInformation account,
+ Geary.ConfigFile config) {
+ 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_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_string_list(
+ ACCOUNT_SENDERS,
+ Geary.traverse(account.sender_mailboxes)
+ .map<string>((sender) => sender.to_rfc822_string())
+ .to_array_list()
+ );
+
+ if (!is_managed) {
+ account_config.set_string(
+ ACCOUNT_PROVIDER, account.service_provider.to_value()
+ );
+ }
+
+ Geary.ConfigFile.Group folder_config =
+ 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_SPAM, account.spam_folder_path);
+ save_folder(folder_config, FOLDER_TRASH, account.trash_folder_path);
+ }
+
+ private void save_folder(Geary.ConfigFile.Group config,
+ string key,
+ Geary.FolderPath? path) {
+ if (path != null) {
+ config.set_string_list(key, path.as_list());
+ }
+ }
+
+ private Geary.FolderPath? load_folder(Geary.ConfigFile.Group config,
+ string key) {
+ Geary.FolderPath? path = null;
+ Gee.List<string> parts = config.get_string_list(key);
+ if (!parts.is_empty) {
+ path = Geary.AccountInformation.build_folder_path(parts);
+ }
+ return path;
+ }
+
+}
+
+
+/**
+ * Manages persistence for un-versioned account configuration.
+ */
+public class Accounts.AccountConfigLegacy : AccountConfig, GLib.Object {
+
+ internal const string GROUP = "AccountInformation";
+
+ private const string ALTERNATE_EMAILS_KEY = "alternate_emails";
+ private const string ARCHIVE_FOLDER_KEY = "archive_folder";
+ private const string CREDENTIALS_METHOD_KEY = "credentials_method";
+ private const string CREDENTIALS_PROVIDER_KEY = "credentials_provider";
+ private const string DRAFTS_FOLDER_KEY = "drafts_folder";
+ private const string EMAIL_SIGNATURE_KEY = "email_signature";
+ private const string NICKNAME_KEY = "nickname";
+ private const string ORDINAL_KEY = "ordinal";
+ private const string PREFETCH_PERIOD_DAYS_KEY = "prefetch_period_days";
+ private const string PRIMARY_EMAIL_KEY = "primary_email";
+ private const string REAL_NAME_KEY = "real_name";
+ private const string SAVE_DRAFTS_KEY = "save_drafts";
+ private const string SAVE_SENT_MAIL_KEY = "save_sent_mail";
+ private const string SENT_MAIL_FOLDER_KEY = "sent_mail_folder";
+ private const string SERVICE_PROVIDER_KEY = "service_provider";
+ private const string SPAM_FOLDER_KEY = "spam_folder";
+ private const string TRASH_FOLDER_KEY = "trash_folder";
+ private const string USE_EMAIL_SIGNATURE_KEY = "use_email_signature";
+
+
+ public Geary.AccountInformation
+ load(Geary.ConfigFile config_file,
+ string id,
+ Geary.ServiceProvider? default_provider,
+ string? default_name)
+ throws ConfigError, GLib.KeyFileError {
+ Geary.ConfigFile.Group config = config_file.get_group(GROUP);
+
+ string primary_email = config.get_required_string(PRIMARY_EMAIL_KEY);
+ string real_name = config.get_string(REAL_NAME_KEY, default_name);
+
+ Geary.ServiceProvider? provider = null;
+ try {
+ provider = default_provider ??
+ Geary.ServiceProvider.for_value(
+ config.get_required_string(SERVICE_PROVIDER_KEY)
+ );
+ } catch (Geary.EngineError err) {
+ throw new ConfigError.SYNTAX("%s: No/bad service provider", id);
+ }
+
+ Geary.AccountInformation info = new Geary.AccountInformation(
+ id, provider,
+ new Geary.RFC822.MailboxAddress(real_name, primary_email)
+ );
+
+ info.ordinal = config.get_int(ORDINAL_KEY, info.ordinal);
+ if (info.ordinal >= Geary.AccountInformation.next_ordinal) {
+ Geary.AccountInformation.next_ordinal = info.ordinal + 1;
+ }
+
+ info.append_sender(new Geary.RFC822.MailboxAddress(
+ config.get_string(REAL_NAME_KEY), primary_email
+ ));
+
+ info.nickname = 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(
+ ALTERNATE_EMAILS_KEY
+ );
+ foreach (string alt_email in alt_email_list) {
+ Geary.RFC822.MailboxAddresses mailboxes =
+ new Geary.RFC822.MailboxAddresses.from_rfc822_string(alt_email);
+ foreach (Geary.RFC822.MailboxAddress mailbox in mailboxes.get_all()) {
+ info.append_sender(mailbox);
+ }
+ }
+
+ 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.use_email_signature = config.get_bool(
+ USE_EMAIL_SIGNATURE_KEY, info.use_email_signature
+ );
+ info.email_signature = config.get_string(
+ EMAIL_SIGNATURE_KEY, info.email_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(
+ config.get_string_list(SENT_MAIL_FOLDER_KEY)
+ );
+ info.spam_folder_path = Geary.AccountInformation.build_folder_path(
+ config.get_string_list(SPAM_FOLDER_KEY)
+ );
+ info.trash_folder_path = Geary.AccountInformation.build_folder_path(
+ config.get_string_list(TRASH_FOLDER_KEY)
+ );
+ info.archive_folder_path = Geary.AccountInformation.build_folder_path(
+ config.get_string_list(ARCHIVE_FOLDER_KEY)
+ );
+
+ info.save_drafts = config.get_bool(SAVE_DRAFTS_KEY, true);
+
+ return info;
+ }
+
+ public void save(Geary.AccountInformation info,
+ Geary.ConfigFile config_file) {
+
+ Geary.ConfigFile.Group config = config_file.get_group(GROUP);
+
+ 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(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);
+ if (info.has_sender_aliases) {
+ Gee.List<Geary.RFC822.MailboxAddress> alts = info.sender_mailboxes;
+ // Don't include the primary in the list
+ alts.remove_at(0);
+
+ config.set_string_list(
+ ALTERNATE_EMAILS_KEY,
+ Geary.traverse(alts)
+ .map<string>((alt) => alt.to_rfc822_string())
+ .to_array_list()
+ );
+ }
+
+ 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(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
+ ? info.trash_folder_path.as_list() : empty));
+ config.set_string_list(ARCHIVE_FOLDER_KEY, (info.archive_folder_path != null
+ ? info.archive_folder_path.as_list() : empty));
+
+ config.set_bool(SAVE_DRAFTS_KEY, info.save_drafts);
+ }
+
+}
+
+
+/**
+ * Manages persistence for version 1 service configuration.
+ */
+public class Accounts.ServiceConfigV1 : ServiceConfig, GLib.Object {
+
+ private const string GROUP_INCOMING = "Incoming";
+ private const string GROUP_OUTGOING = "Outgoing";
+
+ private const string CREDENTIALS = "credentials";
+ private const string HOST = "host";
+ private const string LOGIN = "login";
+ private const string PORT = "port";
+ private const string REMEMBER_PASSWORD = "remember_password";
+ private const string SECURITY = "transport_security";
+
+
+ /** Loads a supported service from a config file. */
+ public Geary.ServiceInformation load(Geary.ConfigFile config,
+ Geary.AccountInformation account,
+ Geary.Protocol protocol,
+ Geary.CredentialsMediator mediator)
+ throws ConfigError, GLib.KeyFileError {
+ Geary.ConfigFile.Group service_config = config.get_group(
+ protocol == IMAP ? GROUP_INCOMING : GROUP_OUTGOING
+ );
+
+ Geary.ServiceInformation service = new Geary.ServiceInformation(
+ protocol, mediator
+ );
+
+ string? login = service_config.get_string(LOGIN, null);
+ if (login != null) {
+ service.credentials = new Geary.Credentials(
+ Credentials.PASSWORD, login
+ );
+ }
+ service.remember_password = service_config.get_bool(
+ REMEMBER_PASSWORD, service.remember_password
+ );
+
+
+ if (account.service_provider == Geary.ServiceProvider.OTHER) {
+ service.host = service_config.get_required_string(HOST);
+ service.port = (uint16) service_config.get_int(PORT, service.port);
+
+ try {
+ service.transport_security =
+ Geary.TlsNegotiationMethod.for_value(
+ service_config.get_string(SECURITY, null)
+ );
+ } catch (GLib.Error err) {
+ // Oh well
+ debug("%s: No/invalid transport security config for %s",
+ account.id, protocol.to_value());
+ }
+
+ if (service.protocol == Geary.Protocol.SMTP) {
+ try {
+ service.smtp_credentials_source =
+ Geary.SmtpCredentials.for_value(
+ service_config.get_required_string(CREDENTIALS)
+ );
+ } catch (Geary.EngineError err) {
+ debug("%s: No/invalid SMTP auth config", account.id);
+ }
+ }
+
+ if (service.port == 0) {
+ service.port = service.get_default_port();
+ }
+ }
+
+ return service;
+ }
+
+ /** Saves an service to a config file. */
+ public void save(Geary.AccountInformation account,
+ Geary.ServiceInformation service,
+ Geary.ConfigFile config) {
+ Geary.ConfigFile.Group service_config = config.get_group(
+ service.protocol == IMAP ? GROUP_INCOMING : GROUP_OUTGOING
+ );
+
+ if (service.credentials != null) {
+ service_config.set_string(LOGIN, service.credentials.user);
+ }
+ service_config.set_bool(REMEMBER_PASSWORD, service.remember_password);
+
+ if (account.service_provider == Geary.ServiceProvider.OTHER) {
+ service_config.set_string(HOST, service.host);
+ service_config.set_int(PORT, service.port);
+ service_config.set_string(
+ SECURITY, service.transport_security.to_value()
+ );
+
+ if (service.protocol == Geary.Protocol.SMTP) {
+ service_config.set_string(
+ CREDENTIALS, service.smtp_credentials_source.to_value()
+ );
+ }
+ }
+ }
+
+}
+
+
+/**
+ * Manages persistence for un-versioned service configuration.
+ */
+public class Accounts.ServiceConfigLegacy : ServiceConfig, GLib.Object {
+
+
+ private const string HOST = "host";
+ private const string PORT = "port";
+ private const string REMEMBER_PASSWORD = "remember_password";
+ private const string SSL = "ssl";
+ private const string STARTTLS = "starttls";
+ private const string USERNAME = "username";
+
+ private const string SMTP_NOAUTH = "smtp_noauth";
+ private const string SMTP_USE_IMAP_CREDENTIALS = "smtp_use_imap_credentials";
+
+
+ /** Loads a supported service from a config file. */
+ public Geary.ServiceInformation load(Geary.ConfigFile config,
+ Geary.AccountInformation account,
+ Geary.Protocol protocol,
+ Geary.CredentialsMediator mediator)
+ throws ConfigError, GLib.KeyFileError {
+ Geary.ServiceInformation service = new Geary.ServiceInformation(
+ protocol, mediator
+ );
+
+ Geary.ConfigFile.Group service_config =
+ config.get_group(AccountConfigLegacy.GROUP);
+
+ string prefix = service.protocol.to_value() + "_";
+
+ string? login = service_config.get_string(
+ prefix + USERNAME, account.primary_mailbox.address
+ );
+ if (login != null) {
+ service.credentials = new Geary.Credentials(
+ Credentials.PASSWORD, login
+ );
+ }
+ service.remember_password = service_config.get_bool(
+ prefix + REMEMBER_PASSWORD, service.remember_password
+ );
+
+ if (account.service_provider == Geary.ServiceProvider.OTHER) {
+ service.host = service_config.get_string(prefix + HOST, service.host);
+ service.port = (uint16) service_config.get_int(
+ prefix + PORT, service.port
+ );
+
+ bool use_tls = service_config.get_bool(
+ prefix + SSL, protocol == Geary.Protocol.IMAP
+ );
+ bool use_starttls = service_config.get_bool(
+ prefix + STARTTLS, true
+ );
+ if (use_tls) {
+ service.transport_security = Geary.TlsNegotiationMethod.TRANSPORT;
+ } else if (use_starttls) {
+ service.transport_security = Geary.TlsNegotiationMethod.START_TLS;
+ } else {
+ service.transport_security = Geary.TlsNegotiationMethod.NONE;
+ }
+
+ if (service.protocol == Geary.Protocol.SMTP) {
+ bool use_imap = service_config.get_bool(
+ SMTP_USE_IMAP_CREDENTIALS, service.credentials != null
+ );
+ bool no_auth = service_config.get_bool(
+ SMTP_NOAUTH, false
+ );
+ if (use_imap) {
+ service.smtp_credentials_source =
+ Geary.SmtpCredentials.IMAP;
+ } else if (!no_auth) {
+ service.smtp_credentials_source =
+ Geary.SmtpCredentials.CUSTOM;
+ } else {
+ service.smtp_credentials_source =
+ Geary.SmtpCredentials.NONE;
+ }
+ }
+ }
+
+ return service;
+ }
+
+ /** Saves an service to a config file. */
+ public void save(Geary.AccountInformation account,
+ Geary.ServiceInformation service,
+ Geary.ConfigFile config) {
+ Geary.ConfigFile.Group service_config =
+ config.get_group(AccountConfigLegacy.GROUP);
+
+ string prefix = service.protocol.to_value() + "_";
+
+ if (service.credentials != null) {
+ service_config.set_string(
+ prefix + USERNAME, service.credentials.user
+ );
+ }
+ service_config.set_bool(
+ prefix + REMEMBER_PASSWORD, service.remember_password
+ );
+
+ if (account.service_provider == Geary.ServiceProvider.OTHER) {
+ service_config.set_string(prefix + HOST, service.host);
+ service_config.set_int(prefix + PORT, service.port);
+
+ switch (service.transport_security) {
+ case NONE:
+ service_config.set_bool(prefix + SSL, false);
+ service_config.set_bool(prefix + STARTTLS, false);
+ break;
+
+ case START_TLS:
+ service_config.set_bool(prefix + SSL, false);
+ service_config.set_bool(prefix + STARTTLS, true);
+ break;
+
+ case TRANSPORT:
+ service_config.set_bool(prefix + SSL, true);
+ service_config.set_bool(prefix + STARTTLS, false);
+ break;
+ }
+
+ if (service.protocol == Geary.Protocol.SMTP) {
+ switch (service.smtp_credentials_source) {
+ case NONE:
+ service_config.set_bool(SMTP_USE_IMAP_CREDENTIALS, false);
+ service_config.set_bool(SMTP_NOAUTH, true);
+ break;
+
+ case IMAP:
+ service_config.set_bool(SMTP_USE_IMAP_CREDENTIALS, true);
+ service_config.set_bool(SMTP_NOAUTH, false);
+ break;
+
+ case CUSTOM:
+ service_config.set_bool(SMTP_USE_IMAP_CREDENTIALS, false);
+ service_config.set_bool(SMTP_NOAUTH, false);
+ break;
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/client/accounts/add-edit-page.vala b/src/client/accounts/add-edit-page.vala
index a022c9fe..790871ab 100644
--- a/src/client/accounts/add-edit-page.vala
+++ b/src/client/accounts/add-edit-page.vala
@@ -690,20 +690,23 @@ public class AddEditPage : Gtk.Box {
}
}
+ Geary.ServiceInformation? imap = null;
+ Geary.ServiceInformation? smtp = null;
if (info == null) {
// New account
- Geary.ServiceInformation imap =
- this.application.controller.account_manager.new_libsecret_service(
- Geary.Protocol.IMAP
- );
- Geary.ServiceInformation smtp =
- this.application.controller.account_manager.new_libsecret_service(
- Geary.Protocol.SMTP
- );
+ imap = this.application.controller.account_manager.new_libsecret_service(
+ Geary.Protocol.IMAP
+ );
+ smtp = this.application.controller.account_manager.new_libsecret_service(
+ Geary.Protocol.SMTP
+ );
try {
info = this.application.controller.account_manager.new_orphan_account(
- this.get_service_provider(), imap, smtp
+ this.get_service_provider(),
+ new Geary.RFC822.MailboxAddress(
+ this.real_name.strip(), this.email_address.strip()
+ )
);
} catch (Error err) {
debug("Unable to create account %s for %s: %s",
@@ -712,13 +715,10 @@ public class AddEditPage : Gtk.Box {
} else {
// Existing account: create a copy so we don't mess up the
// original.
- info = new Geary.AccountInformation.temp_copy(info);
+ //info = new Geary.AccountInformation.temp_copy(info);
}
if (info != null) {
- //info.primary_mailbox = new Geary.RFC822.MailboxAddress(
- // this.real_name.strip(), this.email_address.strip()
- //);
info.nickname = this.nickname.strip();
info.imap.credentials = imap_credentials;
info.smtp.credentials = smtp_credentials;
@@ -740,6 +740,9 @@ public class AddEditPage : Gtk.Box {
info.use_email_signature = this.use_email_signature;
info.email_signature = this.email_signature;
+ info.imap = imap;
+ info.smtp = smtp;
+
on_changed();
}
diff --git a/src/client/application/goa-mediator.vala b/src/client/application/goa-mediator.vala
index b8c55357..79be20b1 100644
--- a/src/client/application/goa-mediator.vala
+++ b/src/client/application/goa-mediator.vala
@@ -43,6 +43,24 @@ public class GoaMediator : Geary.CredentialsMediator, Object {
this.account = account;
}
+ public Geary.ServiceProvider get_service_provider() {
+ Geary.ServiceProvider provider = Geary.ServiceProvider.OTHER;
+ switch (this.account.get_account().provider_type) {
+ case "google":
+ provider = Geary.ServiceProvider.GMAIL;
+ break;
+
+ case "windows_live":
+ provider = Geary.ServiceProvider.OUTLOOK;
+ break;
+ }
+ return provider;
+ }
+
+ public string get_service_label() {
+ return this.account.get_account().provider_name;
+ }
+
public async void update(Geary.AccountInformation geary_account,
GLib.Cancellable? cancellable)
throws GLib.Error {
@@ -54,11 +72,8 @@ public class GoaMediator : Geary.CredentialsMediator, Object {
this.oauth2 = this.account.get_oauth2_based();
this.password = this.account.get_password_based();
- GoaServiceInformation imap = (GoaServiceInformation) geary_account.imap;
- imap.update();
-
- GoaServiceInformation smtp = (GoaServiceInformation) geary_account.smtp;
- smtp.update();
+ update_imap_config(geary_account.imap);
+ update_smtp_config(geary_account.smtp);
}
public virtual async bool load_token(Geary.AccountInformation account,
@@ -118,4 +133,84 @@ public class GoaMediator : Geary.CredentialsMediator, Object {
return this.is_valid;
}
+ private void update_imap_config(Geary.ServiceInformation service) {
+ Goa.Mail? mail = this.account.get_mail();
+ if (mail != null) {
+ parse_host_name(service, mail.imap_host);
+
+ if (mail.imap_use_ssl) {
+ service.transport_security = Geary.TlsNegotiationMethod.TRANSPORT;
+ } else if (mail.imap_use_tls) {
+ service.transport_security = Geary.TlsNegotiationMethod.START_TLS;
+ } else {
+ service.transport_security = Geary.TlsNegotiationMethod.NONE;
+ }
+
+ service.credentials = new Geary.Credentials(
+ this.method, mail.imap_user_name
+ );
+
+ if (service.port == 0) {
+ service.port = service.get_default_port();
+ }
+ }
+ }
+
+ private void update_smtp_config(Geary.ServiceInformation service) {
+ Goa.Mail? mail = this.account.get_mail();
+ if (mail != null) {
+ parse_host_name(service, mail.smtp_host);
+
+ if (mail.imap_use_ssl) {
+ service.transport_security = Geary.TlsNegotiationMethod.TRANSPORT;
+ } else if (mail.imap_use_tls) {
+ service.transport_security = Geary.TlsNegotiationMethod.START_TLS;
+ } else {
+ service.transport_security = Geary.TlsNegotiationMethod.NONE;
+ }
+
+ if (mail.smtp_use_auth) {
+ service.smtp_credentials_source = Geary.SmtpCredentials.CUSTOM;
+ } else {
+ service.smtp_credentials_source = Geary.SmtpCredentials.NONE;
+ }
+
+ if (mail.smtp_use_auth) {
+ service.credentials = new Geary.Credentials(
+ this.method, mail.smtp_user_name
+ );
+ }
+
+ if (service.port == 0) {
+ service.port = service.get_default_port();
+ }
+ }
+ }
+
+ private void parse_host_name(Geary.ServiceInformation service,
+ string host_name) {
+ // Fall back to trying to use the host name as-is.
+ // At least the user can see it in the settings if
+ // they look.
+ service.host = host_name;
+ service.port = 0;
+
+ try {
+ GLib.NetworkAddress address = GLib.NetworkAddress.parse(
+ host_name, service.port
+ );
+
+ service.host = address.hostname;
+ service.port = (uint16) address.port;
+ } catch (GLib.Error err) {
+ warning(
+ "GOA account \"%s\" %s hostname \"%s\": %",
+ this.account.get_account().id,
+ service.protocol.to_value(),
+ host_name,
+ err.message
+ );
+ }
+ }
+
}
diff --git a/src/client/meson.build b/src/client/meson.build
index 5fae0786..1e23be0c 100644
--- a/src/client/meson.build
+++ b/src/client/meson.build
@@ -28,8 +28,6 @@ geary_client_vala_sources = files(
'accounts/accounts-editor-servers-pane.vala',
'accounts/accounts-manager.vala',
'accounts/add-edit-page.vala',
- 'accounts/goa-service-information.vala',
- 'accounts/local-service-information.vala',
'accounts/login-dialog.vala',
'components/client-web-view.vala',
diff --git a/src/engine/api/geary-account-information.vala b/src/engine/api/geary-account-information.vala
index 793ad2dd..a0c924e4 100644
--- a/src/engine/api/geary-account-information.vala
+++ b/src/engine/api/geary-account-information.vala
@@ -55,10 +55,6 @@ public class Geary.AccountInformation : BaseObject {
*/
public File? data_dir { get; private set; default = null; }
- //
- // IMPORTANT: When adding new properties, be sure to add them to the copy method.
- //
-
/**
* A unique, immutable, machine-readable identifier for this account.
*
@@ -72,10 +68,31 @@ public class Geary.AccountInformation : BaseObject {
/** Specifies the email provider for this account. */
public Geary.ServiceProvider service_provider { get; private set; }
- /** A human-readable label describing the email service provider. */
+ /**
+ * A human-readable label describing the email service provider.
+ *
+ * Known providers such as Gmail will have a label specified by
+ * clients, but other accounts can only really be identified by
+ * their server names. This attempts to extract a 'nice' value for
+ * label based on the service's host names.
+ */
public string service_label {
- get; public set;
+ owned get {
+ string? value = this._service_label;
+ if (value == null) {
+ string[] host_parts = this.imap.host.split(".");
+ if (host_parts.length > 1) {
+ host_parts = host_parts[1:host_parts.length];
+ }
+ // don't stash this in _service_label since we want it
+ // updated if the service host names change
+ value = string.joinv(".", host_parts);
+ }
+ return value;
+ }
+ set { this._service_label = value; }
}
+ private string? _service_label = null;
/**
* A unique human-readable display name for this account.
@@ -148,10 +165,17 @@ public class Geary.AccountInformation : BaseObject {
get; set; default = AccountInformation.next_ordinal++;
}
- /* Information related to the account's server-side authentication
- * and configuration. */
- public ServiceInformation imap { get; private set; }
- public ServiceInformation smtp { get; private set; }
+ /* Incoming email service configuration. */
+ public ServiceInformation imap {
+ get; set;
+ default = new ServiceInformation(Protocol.IMAP, null);
+ }
+
+ /* Outgoing email service configuration. */
+ public ServiceInformation smtp {
+ get; set;
+ default = new ServiceInformation(Protocol.SMTP, null);
+ }
/** A lock that can be used to ensure saving is serialised. */
public Nonblocking.Mutex write_lock {
@@ -200,59 +224,10 @@ public class Geary.AccountInformation : BaseObject {
*/
public AccountInformation(string id,
ServiceProvider provider,
- ServiceInformation imap,
- ServiceInformation smtp) {
+ RFC822.MailboxAddress primary_mailbox) {
this.id = id;
this.service_provider = provider;
- this.imap = imap;
- this.smtp = smtp;
-
- // Known providers such as Gmail will have a label specified
- // by clients, but other accounts can only really be
- // identified by their server names. Try to extract a 'nice'
- // value for label based on service host names.
- string imap_host = imap.host;
- string[] host_parts = imap_host.split(".");
- if (host_parts.length > 1) {
- host_parts = host_parts[1:host_parts.length];
- }
- this.service_label = string.joinv(".", host_parts);
- }
-
- /**
- * Creates a copy of an instance.
- */
- public AccountInformation.temp_copy(AccountInformation from) {
- this(
- from.id,
- from.service_provider,
- from.imap.temp_copy(),
- from.smtp.temp_copy()
- );
- copy_from(from);
- this.is_copy = true;
- }
-
-
- /** Copies all properties from an instance into this one. */
- public void copy_from(AccountInformation from) {
- this.id = from.id;
- this.nickname = from.nickname;
- this.mailboxes.clear();
- this.mailboxes.add_all(from.sender_mailboxes);
- this.prefetch_period_days = from.prefetch_period_days;
- this.save_sent_mail = from.save_sent_mail;
- this.ordinal = from.ordinal;
- this.imap.copy_from(from.imap);
- this.smtp.copy_from(from.smtp);
- this.drafts_folder_path = from.drafts_folder_path;
- this.sent_mail_folder_path = from.sent_mail_folder_path;
- this.spam_folder_path = from.spam_folder_path;
- this.trash_folder_path = from.trash_folder_path;
- this.archive_folder_path = from.archive_folder_path;
- this.save_drafts = from.save_drafts;
- this.use_email_signature = from.use_email_signature;
- this.email_signature = from.email_signature;
+ append_sender(primary_mailbox);
}
/** Sets the location of the account's storage directories. */
@@ -405,10 +380,13 @@ public class Geary.AccountInformation : BaseObject {
*/
public Credentials? get_smtp_credentials() {
Credentials? smtp = null;
- if (!this.smtp.smtp_noauth) {
- smtp = this.smtp.smtp_use_imap_credentials
- ? this.imap.credentials
- : this.smtp.credentials;
+ switch (this.smtp.smtp_credentials_source) {
+ case IMAP:
+ smtp = this.imap.credentials;
+ break;
+ case CUSTOM:
+ smtp = this.smtp.credentials;
+ break;
}
return smtp;
}
@@ -497,4 +475,36 @@ public class Geary.AccountInformation : BaseObject {
return path;
}
+ public bool equal_to(AccountInformation other) {
+ return (
+ this == other || (
+ this.id == other.id &&
+ this.ordinal == other.ordinal &&
+ this.service_provider == other.service_provider &&
+ this.service_label == other.service_label &&
+ this.nickname == other.nickname &&
+ 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_drafts == other.save_drafts &&
+ this.drafts_folder_path == other.drafts_folder_path &&
+ this.sent_mail_folder_path == other.sent_mail_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 &&
+ this.config_dir == other.config_dir &&
+ this.data_dir == other.data_dir
+ )
+ );
+ }
+
}
diff --git a/src/engine/api/geary-engine.vala b/src/engine/api/geary-engine.vala
index 2617370f..f345b3e7 100644
--- a/src/engine/api/geary-engine.vala
+++ b/src/engine/api/geary-engine.vala
@@ -437,7 +437,7 @@ public class Geary.Engine : BaseObject {
* Changes the service configuration for an account.
*
* This updates an account's service configuration with the given
- * configuration, by copying it over the account's existing
+ * configuration, by replacing the account's existing
* configuration for that service. The corresponding {@link
* Account.incoming} or {@link Account.outgoing} client service
* will also be updated so that the new configuration will start
@@ -456,31 +456,31 @@ public class Geary.Engine : BaseObject {
);
}
- ServiceInformation? existing = null;
ClientService? service = null;
+ bool was_updated = false;
switch (updated.protocol) {
case Protocol.IMAP:
- existing = account.imap;
+ if (!account.imap.equal_to(updated)) {
+ was_updated = true;
+ account.imap = updated;
+ }
service = impl.incoming;
break;
case Protocol.SMTP:
- existing = account.smtp;
+ if (!account.smtp.equal_to(updated)) {
+ was_updated = true;
+ account.smtp = updated;
+ }
service = impl.outgoing;
break;
}
- bool was_updated = false;
- if (service != null) {
- if (!existing.equal_to(updated)) {
- existing.copy_from(updated);
- was_updated = true;
-
- Endpoint endpoint = get_shared_endpoint(
- account.service_provider, existing
- );
- impl.set_endpoint(service, endpoint);
- account.information_changed();
- }
+ if (was_updated) {
+ Endpoint endpoint = get_shared_endpoint(
+ account.service_provider, updated
+ );
+ impl.set_endpoint(service, endpoint);
+ account.information_changed();
}
return was_updated;
diff --git a/src/engine/api/geary-service-information.vala b/src/engine/api/geary-service-information.vala
index c7cdd221..dece1e0e 100644
--- a/src/engine/api/geary-service-information.vala
+++ b/src/engine/api/geary-service-information.vala
@@ -110,12 +110,9 @@ public enum Geary.SmtpCredentials {
/**
- * This class encloses all the information used when connecting with the server,
- * how to authenticate with it and which credentials to use. Derived classes
- * implement specific ways of doing that. For now, the only known implementation
- * resides in Geary.LocalServiceInformation.
+ * Encapsulates configuration information for a network service.
*/
-public abstract class Geary.ServiceInformation : GLib.Object {
+public class Geary.ServiceInformation : GLib.Object {
/** Specifies if this service is for IMAP or SMTP. */
@@ -125,7 +122,7 @@ public abstract class Geary.ServiceInformation : GLib.Object {
public string host { get; set; default = ""; }
/** The server's port. */
- public uint16 port { get; set; }
+ public uint16 port { get; set; default = 0; }
/** The transport security method to use */
public TlsNegotiationMethod transport_security {
@@ -169,7 +166,7 @@ public abstract class Geary.ServiceInformation : GLib.Object {
* The credentials mediator used with this service.
*
* It is responsible for fetching and storing the credentials if
- * applicable.
+ * as needed.
*/
public CredentialsMediator mediator { get; private set; }
@@ -227,14 +224,32 @@ public abstract class Geary.ServiceInformation : GLib.Object {
public bool smtp_use_imap_credentials { get; set; default = true; }
- protected ServiceInformation(Protocol proto, CredentialsMediator mediator) {
+ /**
+ * Constructs a new configuration for a specific service.
+ */
+ public ServiceInformation(Protocol proto, CredentialsMediator mediator) {
this.protocol = proto;
this.mediator = mediator;
}
+ /**
+ * Constructs a copy of the given service configuration.
+ */
+ public ServiceInformation.copy(ServiceInformation other) {
+ this(other.protocol, other.mediator);
+ this.host = other.host;
+ this.port = other.port;
+ this.use_starttls = other.use_starttls;
+ this.use_ssl = other.use_ssl;
+ this.credentials = (
+ other.credentials != null ? other.credentials.copy() : null
+ );
+ this.mediator = other.mediator;
+ this.remember_password = other.remember_password;
+ this.smtp_noauth = other.smtp_noauth;
+ this.smtp_use_imap_credentials = other.smtp_use_imap_credentials;
+ }
- /** Returns a temporary copy of this service for editing. */
- public abstract ServiceInformation temp_copy();
/**
* Returns the default port for this service type and settings.
@@ -273,7 +288,7 @@ public abstract class Geary.ServiceInformation : GLib.Object {
this.port == other.port &&
this.use_starttls == other.use_starttls &&
this.use_ssl == other.use_ssl &&
- (this.credentials == null && other.credentials != null ||
+ (this.credentials == null && other.credentials == null ||
this.credentials != null && this.credentials.equal_to(other.credentials)) &&
this.mediator == other.mediator &&
this.remember_password == other.remember_password &&
@@ -282,18 +297,4 @@ public abstract class Geary.ServiceInformation : GLib.Object {
);
}
- public void copy_from(Geary.ServiceInformation from) {
- this.host = from.host;
- this.port = from.port;
- this.use_starttls = from.use_starttls;
- this.use_ssl = from.use_ssl;
- this.credentials = (
- from.credentials != null ? from.credentials.copy() : null
- );
- this.mediator = from.mediator;
- this.remember_password = from.remember_password;
- this.smtp_noauth = from.smtp_noauth;
- this.smtp_use_imap_credentials = from.smtp_use_imap_credentials;
- }
-
}
diff --git a/src/engine/util/util-config-file.vala b/src/engine/util/util-config-file.vala
index f6c57c20..92eac5c3 100644
--- a/src/engine/util/util-config-file.vala
+++ b/src/engine/util/util-config-file.vala
@@ -77,11 +77,11 @@ public class Geary.ConfigFile {
}
}
- public string get_string(string key, string def = "") {
- string ret = def;
+ public string? get_string(string key, string? def = null) {
+ string? ret = def;
foreach (GroupLookup lookup in this.lookups) {
try {
- ret = this.backing.get_value(
+ ret = this.backing.get_string(
lookup.group, lookup.prefix + key
);
break;
@@ -92,12 +92,10 @@ public class Geary.ConfigFile {
return ret;
}
- public void set_string(string key, string value) {
- this.backing.set_value(this.name, key, value);
- }
-
- public string get_escaped_string(string key, string def = "") {
- string ret = def;
+ public string get_required_string(string key)
+ throws GLib.KeyFileError {
+ string? ret = null;
+ GLib.KeyFileError? key_err = null;
foreach (GroupLookup lookup in this.lookups) {
try {
ret = this.backing.get_string(
@@ -105,13 +103,21 @@ public class Geary.ConfigFile {
);
break;
} catch (GLib.KeyFileError err) {
+ if (key_err == null) {
+ key_err = err;
+ }
// continue
}
}
+
+ if (key_err != null) {
+ throw key_err;
+ }
+
return ret;
}
- public void set_escaped_string(string key, string value) {
+ public void set_string(string key, string value) {
this.backing.set_string(this.name, key, value);
}
@@ -126,6 +132,12 @@ public class Geary.ConfigFile {
return new Gee.ArrayList<string>();
}
+ public Gee.List<string> get_required_string_list(string key)
+ throws GLib.KeyFileError {
+ string[] list = this.backing.get_string_list(this.name, key);
+ return Geary.Collection.array_list_wrap<string>(list);
+ }
+
public void set_string_list(string key, Gee.List<string> value) {
this.backing.set_string_list(this.name, key, value.to_array());
}
@@ -177,12 +189,12 @@ public class Geary.ConfigFile {
}
/** Removes a key from this group. */
- public void remove_key(string name) throws GLib.Error {
+ public void remove_key(string name) throws GLib.KeyFileError {
this.backing.remove_key(this.name, name);
}
/** Removes this group from the config file. */
- public void remove() throws GLib.Error {
+ public void remove() throws GLib.KeyFileError {
this.backing.remove_group(this.name);
}
@@ -208,7 +220,7 @@ public class Geary.ConfigFile {
* accessed from it before doing so. Use {@link Group.exists} to
* determine if the group has previously been created.
*/
- public Group get_group(string name) throws GLib.Error {
+ public Group get_group(string name) {
return new Group(this, name, this.backing);
}
diff --git a/src/engine/util/util-object.vala b/src/engine/util/util-object.vala
index e47aa5a3..c45b9abd 100644
--- a/src/engine/util/util-object.vala
+++ b/src/engine/util/util-object.vala
@@ -43,13 +43,13 @@ public void unmirror_properties(Gee.List<Binding> bindings) {
}
/** Convenience method for getting an enum value's nick name. */
-internal string to_enum_nick<E>(GLib.Type type, E value) {
+public string to_enum_nick<E>(GLib.Type type, E value) {
GLib.EnumClass enum_type = (GLib.EnumClass) type.class_ref();
return enum_type.get_value((int) value).value_nick;
}
/** Convenience method for getting an enum value's from its nick name. */
-internal E from_enum_nick<E>(GLib.Type type, string nick) throws EngineError {
+public E from_enum_nick<E>(GLib.Type type, string nick) throws EngineError {
GLib.EnumClass enum_type = (GLib.EnumClass) type.class_ref();
unowned GLib.EnumValue? e_value = enum_type.get_value_by_nick(nick);
if (e_value == null) {
diff --git a/test/client/accounts/accounts-manager-test.vala b/test/client/accounts/accounts-manager-test.vala
index c27d0b69..ffcf6cb9 100644
--- a/test/client/accounts/accounts-manager-test.vala
+++ b/test/client/accounts/accounts-manager-test.vala
@@ -8,7 +8,11 @@
class Accounts.ManagerTest : TestCase {
+ private const string TEST_ID = "test";
+
private Manager? test = null;
+ private Geary.AccountInformation? account = null;
+ private Geary.ServiceInformation? service = null;
private File? tmp = null;
@@ -17,6 +21,10 @@ class Accounts.ManagerTest : TestCase {
add_test("create_account", create_account);
add_test("create_orphan_account", create_orphan_account);
add_test("create_orphan_account_with_legacy", create_orphan_account_with_legacy);
+ add_test("account_config_v1", account_config_v1);
+ add_test("account_config_legacy", account_config_legacy);
+ add_test("service_config_v1", service_config_v1);
+ add_test("service_config_legacy", service_config_legacy);
}
public override void set_up() throws GLib.Error {
@@ -34,21 +42,24 @@ class Accounts.ManagerTest : TestCase {
data.make_directory();
this.test = new Manager(new GearyApplication(), config, data);
+
+ this.account = new Geary.AccountInformation(
+ TEST_ID,
+ Geary.ServiceProvider.OTHER,
+ new Geary.RFC822.MailboxAddress(null, "test1 example com")
+ );
+
+ this.service = new Geary.ServiceInformation(Geary.Protocol.SMTP, null);
}
public override void tear_down() throws GLib.Error {
this.test = null;
+ this.account = null;
+ this.service = null;
@delete(this.tmp);
}
public void create_account() throws GLib.Error {
- const string ID = "test";
- Geary.AccountInformation account = new Geary.AccountInformation(
- ID,
- Geary.ServiceProvider.OTHER,
- new Geary.MockServiceInformation(),
- new Geary.MockServiceInformation()
- );
bool was_added = false;
bool was_enabled = false;
@@ -64,7 +75,7 @@ class Accounts.ManagerTest : TestCase {
this.test.create_account.end(async_result());
assert_int(1, this.test.size, "Account manager size");
- assert_equal(account, this.test.get_account(ID), "Is not contained");
+ assert_equal(account, this.test.get_account(TEST_ID), "Is not contained");
assert_true(was_added, "Was not added");
assert_true(was_enabled, "Was not enabled");
}
@@ -72,8 +83,7 @@ class Accounts.ManagerTest : TestCase {
public void create_orphan_account() throws GLib.Error {
Geary.AccountInformation account1 = this.test.new_orphan_account(
Geary.ServiceProvider.OTHER,
- new Geary.MockServiceInformation(),
- new Geary.MockServiceInformation()
+ new Geary.RFC822.MailboxAddress(null, "test1 example com")
);
assert(account1.id == "account_01");
@@ -85,21 +95,12 @@ class Accounts.ManagerTest : TestCase {
Geary.AccountInformation account2 = this.test.new_orphan_account(
Geary.ServiceProvider.OTHER,
- new Geary.MockServiceInformation(),
- new Geary.MockServiceInformation()
+ new Geary.RFC822.MailboxAddress(null, "test1 example com")
);
assert(account2.id == "account_02");
}
public void create_orphan_account_with_legacy() throws GLib.Error {
- const string ID = "test";
- Geary.AccountInformation account = new Geary.AccountInformation(
- ID,
- Geary.ServiceProvider.OTHER,
- new Geary.MockServiceInformation(),
- new Geary.MockServiceInformation()
- );
-
this.test.create_account.begin(
account, new GLib.Cancellable(),
(obj, res) => { async_complete(res); }
@@ -108,8 +109,7 @@ class Accounts.ManagerTest : TestCase {
Geary.AccountInformation account1 = this.test.new_orphan_account(
Geary.ServiceProvider.OTHER,
- new Geary.MockServiceInformation(),
- new Geary.MockServiceInformation()
+ new Geary.RFC822.MailboxAddress(null, "test1 example com")
);
assert(account1.id == "account_01");
@@ -121,12 +121,90 @@ class Accounts.ManagerTest : TestCase {
Geary.AccountInformation account2 = this.test.new_orphan_account(
Geary.ServiceProvider.OTHER,
- new Geary.MockServiceInformation(),
- new Geary.MockServiceInformation()
+ new Geary.RFC822.MailboxAddress(null, "test1 example com")
);
assert(account2.id == "account_02");
}
+ public void account_config_v1() throws GLib.Error {
+ this.account.email_signature = "blarg";
+ this.account.nickname = "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;
+ Accounts.AccountConfigV1 config = new Accounts.AccountConfigV1(false);
+
+ Geary.ConfigFile file =
+ new Geary.ConfigFile(this.tmp.get_child("config"));
+
+ config.save(this.account, file);
+ Geary.AccountInformation copy = config.load(file, TEST_ID, null, null);
+
+ assert_true(this.account.equal_to(copy));
+ }
+
+ public void account_config_legacy() throws GLib.Error {
+ this.account.email_signature = "blarg";
+ this.account.nickname = "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;
+ Accounts.AccountConfigLegacy config =
+ new Accounts.AccountConfigLegacy();
+
+ Geary.ConfigFile file =
+ new Geary.ConfigFile(this.tmp.get_child("config"));
+
+ config.save(this.account, file);
+ Geary.AccountInformation copy = config.load(file, TEST_ID, null, null);
+
+ assert_true(this.account.equal_to(copy));
+ }
+
+ public void service_config_v1() throws GLib.Error {
+ this.service.host = "blarg";
+ this.service.port = 1234;
+ this.service.transport_security = Geary.TlsNegotiationMethod.NONE;
+ this.service.smtp_credentials_source = Geary.SmtpCredentials.CUSTOM;
+ this.service.credentials = new Geary.Credentials(
+ Geary.Credentials.Method.PASSWORD, "testerson"
+ );
+ Accounts.ServiceConfigV1 config = new Accounts.ServiceConfigV1();
+ Geary.ConfigFile file =
+ new Geary.ConfigFile(this.tmp.get_child("config"));
+
+ config.save(this.account, this.service, file);
+ Geary.ServiceInformation copy = config.load(
+ file, this.account, this.service.protocol, null
+ );
+
+ assert_true(this.service.equal_to(copy));
+ }
+
+ public void service_config_legacy() throws GLib.Error {
+ this.service.host = "blarg";
+ this.service.port = 1234;
+ this.service.transport_security = Geary.TlsNegotiationMethod.NONE;
+ this.service.smtp_credentials_source = Geary.SmtpCredentials.CUSTOM;
+ this.service.credentials = new Geary.Credentials(
+ Geary.Credentials.Method.PASSWORD, "testerson"
+ );
+ Accounts.ServiceConfigLegacy config = new Accounts.ServiceConfigLegacy();
+ Geary.ConfigFile file =
+ new Geary.ConfigFile(this.tmp.get_child("config"));
+
+ config.save(this.account, this.service, file);
+ Geary.ServiceInformation copy = config.load(
+ file, this.account, this.service.protocol, null
+ );
+
+ assert_true(this.service.equal_to(copy));
+ }
+
private void delete(File parent) throws GLib.Error {
FileInfo info = parent.query_info(
"standard::*",
diff --git a/test/engine/api/geary-account-information-test.vala
b/test/engine/api/geary-account-information-test.vala
index 42e97879..08d51b17 100644
--- a/test/engine/api/geary-account-information-test.vala
+++ b/test/engine/api/geary-account-information-test.vala
@@ -17,19 +17,19 @@ class Geary.AccountInformationTest : TestCase {
AccountInformation test = new AccountInformation(
"test",
ServiceProvider.OTHER,
- new MockServiceInformation(),
- new MockServiceInformation()
+ new RFC822.MailboxAddress(null, "test1 example com")
);
- test.append_sender(new RFC822.MailboxAddress(null, "test1 example com"));
+ assert_true(test.primary_mailbox.equal_to(
+ new RFC822.MailboxAddress(null, "test1 example com")));
assert_false(test.has_sender_aliases);
test.append_sender(new RFC822.MailboxAddress(null, "test2 example com"));
+ assert_true(test.has_sender_aliases);
+
test.append_sender(new RFC822.MailboxAddress(null, "test3 example com"));
assert_true(test.has_sender_aliases);
- assert_true(test.primary_mailbox.equal_to(
- new RFC822.MailboxAddress(null, "test1 example com")));
assert_true(
test.has_sender_mailbox(new RFC822.MailboxAddress(null, "test1 example com")),
"Primary address not found"
diff --git a/test/engine/api/geary-engine-test.vala b/test/engine/api/geary-engine-test.vala
index 8a6f4bbd..99206fd4 100644
--- a/test/engine/api/geary-engine-test.vala
+++ b/test/engine/api/geary-engine-test.vala
@@ -66,8 +66,7 @@ class Geary.EngineTest : TestCase {
AccountInformation info = new AccountInformation(
"test",
ServiceProvider.OTHER,
- new MockServiceInformation(),
- new MockServiceInformation()
+ new RFC822.MailboxAddress(null, "test1 example com")
);
assert_false(this.engine.has_account(info.id));
@@ -86,8 +85,7 @@ class Geary.EngineTest : TestCase {
AccountInformation info = new AccountInformation(
"test",
ServiceProvider.OTHER,
- new MockServiceInformation(),
- new MockServiceInformation()
+ new RFC822.MailboxAddress(null, "test1 example com")
);
this.engine.add_account(info);
assert_true(this.engine.has_account(info.id));
@@ -103,8 +101,7 @@ class Geary.EngineTest : TestCase {
AccountInformation info = new AccountInformation(
"test",
ServiceProvider.OTHER,
- new MockServiceInformation(),
- new MockServiceInformation()
+ new RFC822.MailboxAddress(null, "test1 example com")
);
assert_false(this.engine.has_account(info.id));
diff --git a/test/engine/app/app-conversation-monitor-test.vala
b/test/engine/app/app-conversation-monitor-test.vala
index f99037fb..f3715170 100644
--- a/test/engine/app/app-conversation-monitor-test.vala
+++ b/test/engine/app/app-conversation-monitor-test.vala
@@ -31,8 +31,7 @@ class Geary.App.ConversationMonitorTest : TestCase {
this.account_info = new AccountInformation(
"account_01",
ServiceProvider.OTHER,
- new MockServiceInformation(),
- new MockServiceInformation()
+ new RFC822.MailboxAddress(null, "test1 example com")
);
this.account = new MockAccount(this.account_info);
this.base_folder = new MockFolder(
diff --git a/test/engine/imap-engine/account-processor-test.vala
b/test/engine/imap-engine/account-processor-test.vala
index 8c6f649c..e80865eb 100644
--- a/test/engine/imap-engine/account-processor-test.vala
+++ b/test/engine/imap-engine/account-processor-test.vala
@@ -72,8 +72,7 @@ public class Geary.ImapEngine.AccountProcessorTest : TestCase {
this.info = new Geary.AccountInformation(
"test-info",
ServiceProvider.OTHER,
- new MockServiceInformation(),
- new MockServiceInformation()
+ new RFC822.MailboxAddress(null, "test1 example com")
);
this.account = new Geary.MockAccount(this.info);
diff --git a/test/engine/util-config-file-test.vala b/test/engine/util-config-file-test.vala
index ed79841f..7cf3e849 100644
--- a/test/engine/util-config-file-test.vala
+++ b/test/engine/util-config-file-test.vala
@@ -19,7 +19,6 @@ class Geary.ConfigFileTest : TestCase {
base("Geary.ConfigFileTest");
add_test("test_string", test_string);
add_test("test_string_fallback", test_string_fallback);
- add_test("test_escaped_string", test_escaped_string);
add_test("test_string_list", test_string_list);
add_test("test_string_list", test_string_list);
add_test("test_bool", test_bool);
@@ -55,12 +54,6 @@ class Geary.ConfigFileTest : TestCase {
assert_string("a string", this.test_group.get_string(TEST_KEY));
}
- public void test_escaped_string() throws Error {
- this.test_group.set_escaped_string(TEST_KEY, "a\nstring");
- assert_string("a\nstring", this.test_group.get_escaped_string(TEST_KEY));
- assert_string("=default", this.test_group.get_escaped_string(TEST_KEY_MISSING, "=default"));
- }
-
public void test_string_list() throws Error {
this.test_group.set_string_list(
TEST_KEY, new Gee.ArrayList<string>.wrap({ "a", "b"})
diff --git a/test/meson.build b/test/meson.build
index dda43e35..26e588ba 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -19,7 +19,6 @@ geary_test_engine_sources = [
'engine/api/geary-email-properties-mock.vala',
'engine/api/geary-folder-mock.vala',
'engine/api/geary-folder-path-mock.vala',
- 'engine/api/geary-service-information-mock.vala',
'engine/api/geary-account-information-test.vala',
'engine/api/geary-attachment-test.vala',
@@ -68,7 +67,6 @@ geary_test_client_sources = [
# geary-engine_internal.vapi, which leads to duplicate symbols when
# linking
'engine/api/geary-credentials-mediator-mock.vala',
- 'engine/api/geary-service-information-mock.vala',
'client/accounts/accounts-manager-test.vala',
'client/application/geary-configuration-test.vala',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]