Implement GOA support for password-based accounts
This commit is contained in:
parent
4e0950f9bc
commit
5108a21def
11 changed files with 387 additions and 129 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
41
src/client/accounts/goa-service-information.vala
Normal file
41
src/client/accounts/goa-service-information.vala
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
64
src/client/application/goa-mediator.vala
Normal file
64
src/client/application/goa-mediator.vala
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue