Implement GOA support for password-based accounts

This commit is contained in:
Oskar Viljasaar 2017-10-27 16:19:35 +02:00 committed by Michael James Gratton
parent 4e0950f9bc
commit 5108a21def
11 changed files with 387 additions and 129 deletions

View file

@ -17,12 +17,14 @@ src/client/accounts/account-dialog.vala
src/client/accounts/account-manager.vala
src/client/accounts/account-spinner-page.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/autostart-manager.vala
src/client/application/geary-application.vala
src/client/application/geary-args.vala
src/client/application/geary-controller.vala
src/client/application/goa-mediator.vala
src/client/application/main.vala
src/client/application/secret-mediator.vala
src/client/components/client-web-view.vala

View file

@ -330,6 +330,7 @@ client/application/geary-application.vala
client/application/geary-args.vala
client/application/geary-config.vala
client/application/geary-controller.vala
client/application/goa-mediator.vala
client/application/secret-mediator.vala
client/accounts/account-dialog.vala
@ -344,6 +345,7 @@ client/accounts/account-manager.vala
client/accounts/account-spinner-page.vala
client/accounts/add-edit-page.vala
client/accounts/local-service-information.vala
client/accounts/goa-service-information.vala
client/accounts/login-dialog.vala
client/components/client-web-view.vala
@ -523,6 +525,7 @@ pkg_check_modules(DEPS REQUIRED
javascriptcoregtk-4.0>=${TARGET_WEBKIT}
enchant>=1.6
libunwind-generic>=1.1
goa-1.0
${EXTRA_CLIENT_PKG_CONFIG}
)
@ -558,6 +561,7 @@ set(CLIENT_PACKAGES
libsecret-1
libsoup-2.4
webkit2gtk-4.0
goa-1.0
${EXTRA_CLIENT_PACKAGES}
)
@ -594,6 +598,7 @@ set(CFLAGS
# code. Suppress them so we can actually see more useful warnings.
-Wno-incompatible-pointer-types
-Wno-discarded-qualifiers
-DGOA_API_IS_SUBJECT_TO_CHANGE
)
if (REF_TRACKING)

View file

@ -10,23 +10,32 @@
*/
public enum CredentialsProvider {
/** Credentials are provided and stored by libsecret. */
LIBSECRET;
LIBSECRET,
/** Credentials are provided and stored by gnome-online-accounts. */
GOA;
public string to_string() {
switch (this) {
case LIBSECRET:
return "libsecret";
case GOA:
return "goa";
default:
assert_not_reached();
}
}
public static CredentialsProvider from_string(string str) throws Error {
switch (str) {
switch (str.ascii_down()) {
case "libsecret":
return LIBSECRET;
case "goa":
return GOA;
default:
throw new KeyFileError.INVALID_VALUE(
"Unknown credentials provider type: %s", str
@ -36,7 +45,9 @@ public enum CredentialsProvider {
}
errordomain AccountError {
INVALID;
INVALID,
GOA_UNAVAILABLE,
GOA_REMOVED;
}
public class AccountManager : GLib.Object {
@ -65,11 +76,18 @@ public class AccountManager : GLib.Object {
private const string TRASH_FOLDER_KEY = "trash_folder";
private const string USE_EMAIL_SIGNATURE_KEY = "use_email_signature";
private const string GOA_ID_PREFIX = "goa_";
private Gee.Map<string,Geary.AccountInformation> enabled_accounts =
new Gee.HashMap<string,Geary.AccountInformation>();
private Geary.Engine engine;
private GLib.File user_config_dir;
private GLib.File user_data_dir;
private Geary.CredentialsMediator libsecret;
private Geary.CredentialsMediator? libsecret = null;
private Goa.Client? goa_service = null;
public AccountManager(Geary.Engine engine,
@ -78,18 +96,26 @@ public class AccountManager : GLib.Object {
this.engine = engine;
this.user_config_dir = user_config_dir;
this.user_data_dir = user_data_dir;
}
public async void connect_libsecret(GLib.Cancellable? cancellable)
throws GLib.Error {
this.libsecret = new SecretMediator();
}
public Geary.ServiceInformation new_libsecret_service(Geary.Service service,
Geary.CredentialsMethod method) {
public async void connect_goa(GLib.Cancellable? cancellable)
throws GLib.Error {
this.goa_service = yield new Goa.Client(cancellable);
}
public LocalServiceInformation
new_libsecret_service(Geary.Service service,
Geary.CredentialsMethod method) {
return new LocalServiceInformation(service, method, libsecret);
}
public async void create_account_dirs(Geary.AccountInformation info,
Cancellable? cancellable = null)
Cancellable? cancellable)
throws GLib.Error {
GLib.File config = this.user_config_dir.get_child(info.id);
GLib.File data = this.user_data_dir.get_child(info.id);
@ -100,8 +126,9 @@ public class AccountManager : GLib.Object {
info.set_account_directories(config, data);
}
public async void add_existing_accounts_async(GLib.Cancellable? cancellable = null)
public async void load_accounts(GLib.Cancellable? cancellable)
throws GLib.Error {
// Step 1. Load existing accounts from the user config dir
GLib.FileEnumerator? enumerator = null;
try {
enumerator = yield this.user_config_dir.enumerate_children_async(
@ -123,17 +150,19 @@ public class AccountManager : GLib.Object {
uint len = info_list.length();
for (uint i = 0; i < len && !cancellable.is_cancelled(); i++) {
GLib.FileInfo info = info_list.nth_data(i);
if (info.get_file_type() == FileType.DIRECTORY) {
GLib.FileInfo file = info_list.nth_data(i);
if (file.get_file_type() == FileType.DIRECTORY) {
try {
string id = info.get_name();
this.engine.add_account(yield load_account(id, cancellable));
Geary.AccountInformation info = yield load_account(
file.get_name(), cancellable
);
enable_account(info);
} catch (GLib.Error err) {
// XXX want to report this problem to the user
// somehow, but at this point in the app's
// lifecycle we don't even have a main window.
warning("Ignoring empty/bad config in %s: %s",
info.get_name(), err.message);
file.get_name(), err.message);
}
}
}
@ -143,7 +172,31 @@ public class AccountManager : GLib.Object {
enumerator = null;
}
}
}
// Step 2. Load previously unseen accounts from GOA, if available.
if (this.goa_service != null) {
GLib.List<Goa.Object> list = this.goa_service.get_accounts();
for (int i=0; i < list.length() && !cancellable.is_cancelled(); i++) {
Goa.Object account = list.nth_data(i);
string id = to_geary_id(account.get_account());
if (!this.enabled_accounts.has_key(id)) {
Geary.AccountInformation? info = null;
try {
info = yield create_goa_account(account, cancellable);
} catch (GLib.Error err) {
// XXX want to report this problem to the user
// somehow, but at this point in the app's
// lifecycle we don't even have a main window.
warning("Error creating GOA account %s: %s",
account.get_account().id, err.message);
}
if (info != null) {
enable_account(info);
}
}
}
}
}
/**
* Loads an account info from a config directory.
@ -151,7 +204,7 @@ public class AccountManager : GLib.Object {
* Throws an error if the config file was not found, could not be
* parsed, or doesn't have all required fields.
*/
public async Geary.AccountInformation?
private async Geary.AccountInformation
load_account(string id, GLib.Cancellable? cancellable)
throws Error {
GLib.File config_dir = this.user_config_dir.get_child(id);
@ -164,13 +217,6 @@ public class AccountManager : GLib.Object {
yield config_file.load(cancellable);
Geary.ConfigFile.Group config = config_file.get_group(ACCOUNT_CONFIG_GROUP);
Geary.ConfigFile.Group imap_config = config_file.get_group(IMAP_CONFIG_GROUP);
imap_config.set_fallback(ACCOUNT_CONFIG_GROUP, "imap_");
Geary.ConfigFile.Group smtp_config = config_file.get_group(SMTP_CONFIG_GROUP);
smtp_config.set_fallback(ACCOUNT_CONFIG_GROUP, "smtp_");
CredentialsProvider provider = CredentialsProvider.from_string(
config.get_string(
CREDENTIALS_PROVIDER_KEY,
@ -178,35 +224,49 @@ public class AccountManager : GLib.Object {
)
);
Geary.CredentialsMethod method = Geary.CredentialsMethod.from_string(
config.get_string(CREDENTIALS_METHOD_KEY,
Geary.CredentialsMethod.PASSWORD.to_string())
);
string primary_email = config.get_string(PRIMARY_EMAIL_KEY);
Geary.ServiceInformation imap_info;
Geary.ServiceInformation smtp_info;
Geary.AccountInformation? info = null;
switch (provider) {
case CredentialsProvider.LIBSECRET:
imap_info = new_libsecret_service(Geary.Service.IMAP, method);
smtp_info = new_libsecret_service(Geary.Service.SMTP, method);
info = new_libsecret_account(id, config, primary_email);
break;
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);
} else {
// Could not find the GOA object for this account,
// but have a working GOA connection, so it must
// have been removed.
throw new AccountError.GOA_REMOVED("Account not found");
}
}
if (info == null) {
// XXX We have a GOA account locally, but GOA is
// unavailable or the GOA account type is no longer
// supported. Create a dummy, disabled account and let
// the user deal with it?
}
break;
default:
throw new AccountError.INVALID("Unhandled credentials provider");
}
Geary.AccountInformation info = new Geary.AccountInformation(
id, imap_info, smtp_info
);
info.set_account_directories(config_dir, data_dir);
// This is the only required value at the moment?
string primary_email = config.get_string(PRIMARY_EMAIL_KEY);
string real_name = config.get_string(REAL_NAME_KEY);
info.ordinal = config.get_int(ORDINAL_KEY, info.ordinal);
if (info.ordinal >= Geary.AccountInformation.next_ordinal)
Geary.AccountInformation.next_ordinal = info.ordinal + 1;
info.primary_mailbox = new Geary.RFC822.MailboxAddress(
real_name, primary_email
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
@ -221,22 +281,12 @@ public class AccountManager : GLib.Object {
}
}
info.imap.load_credentials(imap_config, primary_email);
info.smtp.load_credentials(smtp_config, primary_email);
info.service_provider = Geary.ServiceProvider.from_string(
config.get_string(SERVICE_PROVIDER_KEY,
Geary.ServiceProvider.GMAIL.to_string())
);
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.ordinal = config.get_int(
ORDINAL_KEY, info.ordinal
);
info.use_email_signature = config.get_bool(
USE_EMAIL_SIGNATURE_KEY, info.use_email_signature
);
@ -244,19 +294,6 @@ public class AccountManager : GLib.Object {
EMAIL_SIGNATURE_KEY, info.email_signature
);
if (info.ordinal >= Geary.AccountInformation.next_ordinal)
Geary.AccountInformation.next_ordinal = info.ordinal + 1;
if (info.service_provider == Geary.ServiceProvider.OTHER) {
info.imap.load_settings(imap_config);
info.smtp.load_settings(smtp_config);
if (info.smtp.smtp_use_imap_credentials) {
info.smtp.credentials.user = info.imap.credentials.user;
info.smtp.credentials.pass = info.imap.credentials.pass;
}
}
info.drafts_folder_path = Geary.AccountInformation.build_folder_path(
config.get_string_list(DRAFTS_FOLDER_KEY)
);
@ -279,7 +316,7 @@ public class AccountManager : GLib.Object {
}
public async void save_account(Geary.AccountInformation info,
GLib.Cancellable? cancellable = null)
GLib.Cancellable? cancellable)
throws GLib.Error {
// Ensure only one async task is saving an info at once, since
// at least the Engine can cause multiple saves to be called
@ -301,7 +338,7 @@ public class AccountManager : GLib.Object {
}
private async void save_account_locked(Geary.AccountInformation info,
GLib.Cancellable? cancellable = null)
GLib.Cancellable? cancellable)
throws GLib.Error {
File? file = info.settings_file;
if (file == null) {
@ -321,15 +358,31 @@ public class AccountManager : GLib.Object {
}
Geary.ConfigFile.Group config = config_file.get_group(ACCOUNT_CONFIG_GROUP);
Geary.ConfigFile.Group imap_config = config_file.get_group(IMAP_CONFIG_GROUP);
Geary.ConfigFile.Group smtp_config = config_file.get_group(SMTP_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_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 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()
);
}
config.set_string(
CREDENTIALS_PROVIDER_KEY, CredentialsProvider.LIBSECRET.to_string()
);
config.set_string(
CREDENTIALS_METHOD_KEY, info.imap.credentials_method.to_string()
);
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);
@ -349,11 +402,6 @@ public class AccountManager : GLib.Object {
);
}
if (info.service_provider == Geary.ServiceProvider.OTHER) {
info.imap.save_settings(imap_config);
info.smtp.save_settings(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));
@ -368,6 +416,7 @@ public class AccountManager : GLib.Object {
config.set_bool(SAVE_DRAFTS_KEY, info.save_drafts);
debug("Writing config to: %s", file.get_path());
yield config_file.save(cancellable);
}
@ -375,7 +424,8 @@ public class AccountManager : GLib.Object {
* Deletes an account from disk. This is used by Geary.Engine and should not
* normally be invoked directly.
*/
public async void remove_async(Geary.AccountInformation info, Cancellable? cancellable = null) {
public async void remove_async(Geary.AccountInformation info,
GLib.Cancellable? cancellable) {
if (info.data_dir == null) {
warning("Cannot remove account storage directory; nothing to remove");
} else {
@ -393,6 +443,119 @@ public class AccountManager : GLib.Object {
} catch (Error e) {
debug("Error clearing passwords: %s", e.message);
}
this.enabled_accounts.unset(info.id);
}
private void enable_account(Geary.AccountInformation account)
throws GLib.Error {
this.enabled_accounts.set(account.id, account);
this.engine.add_account(account);
}
private inline string to_geary_id(Goa.Account account) {
return GOA_ID_PREFIX + account.id;
}
private inline string to_goa_id(string id) {
return id.has_prefix(GOA_ID_PREFIX)
? id.substring(GOA_ID_PREFIX.length)
: id;
}
private Geary.AccountInformation
new_libsecret_account(string id,
Geary.ConfigFile.Group config,
string fallback_login)
throws GLib.Error {
Geary.ServiceProvider provider = Geary.ServiceProvider.from_string(
config.get_string(SERVICE_PROVIDER_KEY,
Geary.ServiceProvider.GMAIL.to_string())
);
Geary.CredentialsMethod method = Geary.CredentialsMethod.from_string(
config.get_string(CREDENTIALS_METHOD_KEY,
Geary.CredentialsMethod.PASSWORD.to_string())
);
Geary.ConfigFile.Group imap_config =
config.file.get_group(IMAP_CONFIG_GROUP);
LocalServiceInformation imap = new_libsecret_service(
Geary.Service.IMAP, method
);
imap_config.set_fallback(config.name, "imap_");
imap.load_credentials(imap_config, fallback_login);
Geary.ConfigFile.Group smtp_config =
config.file.get_group(SMTP_CONFIG_GROUP);
LocalServiceInformation smtp = new_libsecret_service(
Geary.Service.SMTP, method
);
smtp_config.set_fallback(config.name, "smtp_");
smtp.load_credentials(smtp_config, 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(imap_config);
if (smtp.smtp_use_imap_credentials) {
smtp.credentials.user = imap.credentials.user;
smtp.credentials.pass = imap.credentials.pass;
}
}
Geary.AccountInformation info = new Geary.AccountInformation(
id, imap, smtp
);
info.service_provider = provider;
return info;
}
private Geary.AccountInformation? new_goa_account(string id,
Goa.Object account) {
Geary.AccountInformation info = null;
Goa.Mail? mail = account.get_mail();
Goa.PasswordBased? password = account.get_password_based();
if (mail != null && password != null) {
Geary.CredentialsMediator mediator = new GoaMediator(password);
info = new Geary.AccountInformation(
id,
new GoaServiceInformation(Geary.Service.IMAP, mediator, mail),
new GoaServiceInformation(Geary.Service.SMTP, mediator, mail)
);
info.service_provider = Geary.ServiceProvider.OTHER;
}
return info;
}
private async Geary.AccountInformation?
create_goa_account(Goa.Object account,
GLib.Cancellable? cancellable)
throws GLib.Error {
Geary.AccountInformation? info = new_goa_account(
to_geary_id(account.get_account()), account
);
if (info != null) {
debug("GOA id: %s", info.id);
Goa.Mail? mail = account.get_mail();
info.ordinal = Geary.AccountInformation.next_ordinal++;
info.primary_mailbox = new Geary.RFC822.MailboxAddress(
mail.name, mail.email_address
);
info.nickname = account.get_account().identity;
yield create_account_dirs(info, cancellable);
debug("Created dirs: %s", info.id);
yield save_account(info, cancellable);
debug("Saved: %s", info.id);
}
return info;
}
}

View file

@ -0,0 +1,41 @@
/* Copyright 2017 Software Freedom Conservancy Inc.
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
*/
/* A service implementation using GNOME Online Accounts.
* This loads IMAP and SMTP settings from GOA.
*/
public class GoaServiceInformation : Geary.ServiceInformation {
private Goa.Mail mail_object;
public GoaServiceInformation(Geary.Service service,
Geary.CredentialsMediator? mediator,
Goa.Mail mail_object) {
this.service = service;
this.mediator = mediator;
this.mail_object = mail_object;
switch (service) {
case Geary.Service.IMAP:
this.credentials.user = mail_object.imap_user_name;
this.host = mail_object.imap_host;
this.port = Geary.Imap.ClientConnection.DEFAULT_PORT_SSL;
this.use_ssl = mail_object.imap_use_ssl;
this.use_starttls = mail_object.imap_use_tls;
break;
case Geary.Service.SMTP:
this.credentials.user = mail_object.smtp_user_name;
this.host = mail_object.smtp_host;
this.port = Geary.Smtp.ClientConnection.DEFAULT_PORT_SSL;
this.use_ssl = mail_object.smtp_use_ssl;
this.use_starttls = mail_object.smtp_use_tls;
this.smtp_noauth = !(mail_object.smtp_use_auth);
if (smtp_noauth)
this.credentials = null;
break;
}
}
}

View file

@ -27,8 +27,7 @@ public class LocalServiceInformation : Geary.ServiceInformation {
this.mediator = mediator;
}
public override void load_settings(Geary.ConfigFile.Group config)
throws GLib.Error {
public void load_settings(Geary.ConfigFile.Group config) {
this.host = config.get_string(HOST, this.host);
this.port = config.get_uint16(PORT, this.port);
this.use_ssl = config.get_bool(SSL, this.use_ssl);
@ -46,18 +45,17 @@ public class LocalServiceInformation : Geary.ServiceInformation {
}
public override void load_credentials(Geary.ConfigFile.Group config,
string? email_address = null)
throws GLib.Error {
public void load_credentials(Geary.ConfigFile.Group config,
string? default_login = null) {
this.credentials.user = config.get_string(
USERNAME_KEY, email_address
USERNAME_KEY, default_login
);
this.remember_password = config.get_bool(
REMEMBER_PASSWORD_KEY, this.remember_password
);
}
public override void save_settings(Geary.ConfigFile.Group config) {
public void save_settings(Geary.ConfigFile.Group config) {
config.set_string(HOST, this.host);
config.set_int(PORT, this.port);
config.set_bool(SSL, this.use_ssl);

View file

@ -245,7 +245,7 @@ public class GearyApplication : Gtk.Application {
exec_dir.get_path(), is_installed().to_string());
config = new Configuration(APP_ID);
yield controller.open_async();
yield controller.open_async(null);
release();
}

View file

@ -183,7 +183,7 @@ public class GearyController : Geary.BaseObject {
/**
* Starts the controller and brings up Geary.
*/
public async void open_async() {
public async void open_async(GLib.Cancellable? cancellable) {
Geary.Engine engine = this.application.engine;
// This initializes the IconFactory, important to do before
@ -298,9 +298,24 @@ public class GearyController : Geary.BaseObject {
this.application.get_user_config_directory(),
this.application.get_user_data_directory()
);
try {
yield engine.open_async(this.application.get_resource_directory());
yield this.account_manager.add_existing_accounts_async(null);
yield this.account_manager.connect_libsecret(cancellable);
} catch (GLib.Error err) {
warning("Error opening libsecret: %s", err.message);
}
try {
yield this.account_manager.connect_goa(cancellable);
} catch (GLib.Error err) {
warning("Error opening GOA: %s", err.message);
}
try {
yield engine.open_async(
this.application.get_resource_directory(), cancellable
);
yield this.account_manager.load_accounts(cancellable);
if (engine.get_accounts().size == 0) {
create_account();
}
@ -864,10 +879,12 @@ public class GearyController : Geary.BaseObject {
try {
if (real_account_information.settings_file == null) {
yield this.account_manager.create_account_dirs(
real_account_information
real_account_information, cancellable
);
}
yield this.account_manager.save_account(real_account_information);
yield this.account_manager.save_account(
real_account_information, cancellable
);
yield do_update_stored_passwords_async(
Geary.ServiceFlag.IMAP | Geary.ServiceFlag.SMTP,
real_account_information

View file

@ -0,0 +1,64 @@
/* Copyright 2017 Software Freedom Conservancy Inc.
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
*/
/* GNOME Online Accounts password adapter. */
public class GoaMediator : Geary.CredentialsMediator, Object {
private Goa.PasswordBased password;
public GoaMediator(Goa.PasswordBased password) {
this.password = password;
}
public virtual async string? get_password_async(Geary.Service service,
Geary.AccountInformation account,
Cancellable? cancellable = null)
throws Error {
string pass;
switch (service) {
case Geary.Service.IMAP:
if (!password.call_get_password_sync("imap-password", out pass, cancellable))
return null;
break;
case Geary.Service.SMTP:
if (!password.call_get_password_sync("smtp-password", out pass, cancellable))
return null;
break;
default:
return null;
}
return pass;
}
public virtual async void set_password_async(Geary.Service service,
Geary.AccountInformation account,
Cancellable? cancellable = null)
throws Error {
return;
}
public virtual async void clear_password_async(Geary.Service service,
Geary.AccountInformation account,
Cancellable? cancellable = null)
throws Error {
return;
}
public virtual async bool prompt_passwords_async(Geary.ServiceFlag services,
Geary.AccountInformation account_information,
out string? imap_password, out string? smtp_password,
out bool imap_remember_password, out bool smtp_remember_password) throws Error {
imap_password = yield get_password_async(Geary.Service.IMAP, account_information, null);
smtp_password = yield get_password_async(Geary.Service.SMTP, account_information, null);
imap_remember_password = false;
smtp_remember_password = false;
return false;
}
}

View file

@ -34,6 +34,7 @@ public enum Geary.CredentialsMethod {
}
}
/**
* This class encloses all the information used when connecting with the server,
* how to authenticate with it and which credentials to use. Derived classes
@ -91,23 +92,6 @@ public abstract class Geary.ServiceInformation : GLib.Object {
*/
public bool smtp_use_imap_credentials { get; set; default = false; }
/**
* Loads the settings pertaining to this class's instance.
*
* This method depends on the concrete implementation used.
*/
public abstract void load_settings(ConfigFile.Group config) throws Error;
/**
* Loads the credentials pertaining to this class's instance.
*
* This method depends on the concrete implementation used.
*/
public abstract void load_credentials(ConfigFile.Group config, string? email_address = null) throws Error;
/** Saves settings pertaining to this class's instance to a key file. */
public abstract void save_settings(ConfigFile.Group config);
public void copy_from(Geary.ServiceInformation from) {
this.host = from.host;
this.port = from.port;

View file

@ -26,6 +26,9 @@ public class Geary.ConfigFile {
}
/** The config file this group was obtained from. */
public ConfigFile file { get; private set; }
/** The name of this group, as specified by a [Name] heading. */
public string name { get; private set; }
@ -33,7 +36,8 @@ public class Geary.ConfigFile {
private GroupLookup[] lookups;
internal Group(string name, GLib.KeyFile backing) {
internal Group(ConfigFile file, string name, GLib.KeyFile backing) {
this.file = file;
this.name = name;
this.backing = backing;
@ -172,7 +176,7 @@ public class Geary.ConfigFile {
* Returns the config group under the given named heading.
*/
public Group get_group(string name) {
return new Group(name, this.backing);
return new Group(this, name, this.backing);
}
/**

View file

@ -12,24 +12,4 @@ public class Geary.MockServiceInformation : ServiceInformation, MockObject {
get; set; default = new Gee.LinkedList<ExpectedCall>();
}
public override void load_settings(Geary.ConfigFile.Group config)
throws Error {
void_call("load_settings", { box_arg(config) });
}
public override void load_credentials(Geary.ConfigFile.Group config,
string? email_address = null)
throws Error {
void_call("load_credentials", { box_arg(config), box_arg(email_address) });
}
public override void save_settings(Geary.ConfigFile.Group config) {
try {
void_call("save_settings", { box_arg(config) });
} catch (Error err) {
assert_not_reached();
}
}
}