Add basic pluggable keyring support; fix #6219
Squashed commit of the following:
commit 9167aeb56be6789d49a3e7cdba2a21d2b015e40d
Author: Charles Lindsay <chaz@yorba.org>
Date: Fri Jan 25 16:11:20 2013 -0800
Fix for code guidelines
commit 7612a7ddc3df14ef207b9e74ee32fa23710e1ce9
Author: Charles Lindsay <chaz@yorba.org>
Date: Fri Jan 25 15:26:48 2013 -0800
Fix code review issues
commit 46635544c98df7a8b6c76f028715814907274389
Merge: 30b611e 6de36ae
Author: Charles Lindsay <chaz@yorba.org>
Date: Fri Jan 25 12:54:03 2013 -0800
Merge branch 'master' into pluggable-auth
commit 30b611ed415fe7a2c1d62746f94620132ec86623
Author: Charles Lindsay <chaz@yorba.org>
Date: Thu Jan 24 17:12:24 2013 -0800
Only prompt for IMAP password on startup
commit ca2953b4b33cb367c060164df9f2258217e94046
Author: Charles Lindsay <chaz@yorba.org>
Date: Thu Jan 24 16:34:39 2013 -0800
Fix compile errors; cleanup
commit 545764a6a914ff36a1ca187444d0830a28502bab
Merge: 0460a68 e498354
Author: Charles Lindsay <chaz@yorba.org>
Date: Thu Jan 24 16:31:43 2013 -0800
Merge branch 'master' into pluggable-auth
Conflicts:
src/client/geary-application.vala
commit 0460a68af4de3e762522fd641c16675cfc7d2241
Author: Charles Lindsay <chaz@yorba.org>
Date: Thu Jan 24 16:20:31 2013 -0800
Use Engine's mediator implicitly
commit 22cbb8740e711ca3151b0389aef9cbb8c21928c7
Author: Charles Lindsay <chaz@yorba.org>
Date: Thu Jan 24 16:19:55 2013 -0800
Use flags on things that are supposed to be flags
commit 4dc0eb15d2fe23c92d8cc6cff8a3138b6cb1baf4
Author: Charles Lindsay <chaz@yorba.org>
Date: Thu Jan 24 15:49:50 2013 -0800
Fix prompting in certain cases
commit 56bb2265a6635a754b9a00b469ec457105390896
Author: Charles Lindsay <chaz@yorba.org>
Date: Thu Jan 24 14:37:12 2013 -0800
Fix typo
commit 926f47024f1280271bc36cd8c60eb948bed4a432
Author: Charles Lindsay <chaz@yorba.org>
Date: Thu Jan 24 11:43:05 2013 -0800
Cleanup, compile, smoke test
commit 9ff4257d125e67828f0c813e0806d3d34c114550
Author: Charles Lindsay <chaz@yorba.org>
Date: Fri Jan 18 10:41:17 2013 -0800
First stab at new pluggable auth API
This commit is contained in:
parent
6de36ae3eb
commit
e971275375
13 changed files with 484 additions and 314 deletions
|
|
@ -23,6 +23,7 @@ engine/api/geary-contact-store.vala
|
|||
engine/api/geary-conversation.vala
|
||||
engine/api/geary-conversation-monitor.vala
|
||||
engine/api/geary-credentials.vala
|
||||
engine/api/geary-credentials-mediator.vala
|
||||
engine/api/geary-email-flag.vala
|
||||
engine/api/geary-email-flags.vala
|
||||
engine/api/geary-email-identifier.vala
|
||||
|
|
@ -200,6 +201,7 @@ client/geary-application.vala
|
|||
client/geary-args.vala
|
||||
client/geary-config.vala
|
||||
client/geary-controller.vala
|
||||
client/gnome-keyring-mediator.vala
|
||||
client/main.vala
|
||||
|
||||
client/accounts/account-dialog.vala
|
||||
|
|
@ -244,7 +246,6 @@ client/util/util-email.vala
|
|||
client/util/util-files.vala
|
||||
client/util/util-gravatar.vala
|
||||
client/util/util-gtk.vala
|
||||
client/util/util-keyring.vala
|
||||
client/util/util-webkit.vala
|
||||
|
||||
client/views/formatted-conversation-data.vala
|
||||
|
|
|
|||
|
|
@ -23,14 +23,14 @@ public class PasswordDialog {
|
|||
private Gtk.Button ok_button;
|
||||
private Gtk.Grid grid_imap;
|
||||
private Gtk.Grid grid_smtp;
|
||||
private PasswordTypeFlag password_flags;
|
||||
private Geary.CredentialsMediator.ServiceFlag password_flags;
|
||||
|
||||
public string imap_password { get; private set; default = ""; }
|
||||
public string smtp_password { get; private set; default = ""; }
|
||||
public bool remember_password { get; private set; }
|
||||
|
||||
public PasswordDialog(Geary.AccountInformation account_information, bool first_try,
|
||||
PasswordTypeFlag password_flags) {
|
||||
Geary.CredentialsMediator.ServiceFlag password_flags) {
|
||||
this.password_flags = password_flags;
|
||||
Gtk.Builder builder = GearyApplication.instance.create_builder("password-dialog.glade");
|
||||
|
||||
|
|
@ -67,12 +67,8 @@ public class PasswordDialog {
|
|||
// Find server configuration information
|
||||
Geary.Endpoint imap_endpoint;
|
||||
Geary.Endpoint smtp_endpoint;
|
||||
try {
|
||||
imap_endpoint = account_information.get_imap_endpoint();
|
||||
smtp_endpoint = account_information.get_smtp_endpoint();
|
||||
} catch (Geary.EngineError err) {
|
||||
error("Error getting endpoints: %s", err.message);
|
||||
}
|
||||
imap_endpoint = account_information.get_imap_endpoint();
|
||||
smtp_endpoint = account_information.get_smtp_endpoint();
|
||||
|
||||
string imap_server_host = imap_endpoint.host_specifier;
|
||||
uint16 imap_server_port = imap_endpoint.default_port;
|
||||
|
|
|
|||
|
|
@ -132,7 +132,8 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
// Start Geary.
|
||||
try {
|
||||
yield Geary.Engine.instance.open_async(get_user_data_directory(), get_resource_directory());
|
||||
yield Geary.Engine.instance.open_async(get_user_data_directory(), get_resource_directory(),
|
||||
new GnomeKeyringMediator());
|
||||
} catch (Error e) {
|
||||
error("Error opening Geary.Engine instance: %s", e.message);
|
||||
}
|
||||
|
|
@ -168,10 +169,12 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
private void initialize_account() {
|
||||
Geary.AccountInformation? account_information = get_account();
|
||||
if (account_information == null)
|
||||
if (account_information == null) {
|
||||
create_account(null);
|
||||
else
|
||||
open_account(account_information.email, null, null, PasswordTypeFlag.IMAP | PasswordTypeFlag.SMTP, null);
|
||||
} else {
|
||||
open_account(account_information.email,
|
||||
Geary.CredentialsMediator.ServiceFlag.IMAP, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void create_account(string? email) {
|
||||
|
|
@ -229,33 +232,29 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
// Attempts to validate and add an account. Returns true on success, else false.
|
||||
public async bool validate_async(Geary.AccountInformation account_information,
|
||||
Cancellable? cancellable = null) {
|
||||
bool success = false;
|
||||
try {
|
||||
success = yield account_information.validate_async(cancellable);
|
||||
} catch (Geary.EngineError err) {
|
||||
if (!yield Geary.Engine.instance.validate_account_information_async(
|
||||
account_information, cancellable))
|
||||
return false;
|
||||
} catch (Error err) {
|
||||
debug("Error validating account: %s", err.message);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
account_information.store_async.begin(cancellable);
|
||||
|
||||
try {
|
||||
set_account(account_information.get_account());
|
||||
debug("Successfully validated account information");
|
||||
|
||||
return true;
|
||||
} catch (Geary.EngineError err) {
|
||||
debug("Unable to retrieve email account: %s", err.message);
|
||||
}
|
||||
}
|
||||
account_information.store_async.begin(cancellable);
|
||||
|
||||
return false;
|
||||
try {
|
||||
set_account(Geary.Engine.instance.get_account_instance(account_information));
|
||||
debug("Successfully validated account information");
|
||||
return true;
|
||||
} catch (Error err) {
|
||||
debug("Unable to retrieve email account: %s", err.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void open_account(string email, string? old_imap_password, string? old_smtp_password,
|
||||
PasswordTypeFlag password_flags, Cancellable? cancellable) {
|
||||
private void open_account(string email, Geary.CredentialsMediator.ServiceFlag password_flags,
|
||||
Cancellable? cancellable) {
|
||||
Geary.AccountInformation account_information;
|
||||
try {
|
||||
account_information = Geary.Engine.instance.get_accounts().get(email);
|
||||
|
|
@ -265,26 +264,24 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
error("Unable to open account information for label %s: %s", email, err.message);
|
||||
}
|
||||
|
||||
bool imap_remember_password = account_information.imap_remember_password;
|
||||
bool smtp_remember_password = account_information.smtp_remember_password;
|
||||
string? imap_password, smtp_password;
|
||||
get_passwords(account_information, password_flags, ref imap_remember_password,
|
||||
ref smtp_remember_password, out imap_password, out smtp_password);
|
||||
if (imap_password == null || smtp_password == null) {
|
||||
set_account(null);
|
||||
return;
|
||||
}
|
||||
|
||||
account_information.imap_remember_password = imap_remember_password;
|
||||
account_information.smtp_remember_password = smtp_remember_password;
|
||||
account_information.store_async.begin(cancellable);
|
||||
|
||||
account_information.imap_credentials.pass = imap_password;
|
||||
account_information.smtp_credentials.pass = smtp_password;
|
||||
account_information.fetch_passwords_async.begin(password_flags,
|
||||
on_open_account_fetch_passwords_finished);
|
||||
}
|
||||
|
||||
private void on_open_account_fetch_passwords_finished(Object? object, AsyncResult result) {
|
||||
Geary.AccountInformation? account_information = object as Geary.AccountInformation;
|
||||
assert(account_information != null);
|
||||
|
||||
try {
|
||||
set_account(account_information.get_account());
|
||||
} catch (Geary.EngineError err) {
|
||||
if (!account_information.fetch_passwords_async.end(result))
|
||||
exit(1);
|
||||
} catch (Error e) {
|
||||
error("Error fetching stored passwords: %s", e.message);
|
||||
}
|
||||
|
||||
try {
|
||||
set_account(Geary.Engine.instance.get_account_instance(account_information));
|
||||
} catch (Error err) {
|
||||
// Our service provider is wrong. But we can't change it, because we don't want to
|
||||
// change the service provider for an existing account.
|
||||
debug("Unable to retrieve email account: %s", err.message);
|
||||
|
|
@ -304,83 +301,11 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
return null;
|
||||
}
|
||||
|
||||
private void get_passwords(Geary.AccountInformation old_account_information,
|
||||
PasswordTypeFlag password_flags, ref bool imap_remember_password,
|
||||
ref bool smtp_remember_password, out string? imap_password, out string? smtp_password) {
|
||||
imap_password = null;
|
||||
if (!old_account_information.imap_credentials.is_complete() && imap_remember_password)
|
||||
imap_password = keyring_get_password(old_account_information.imap_credentials.user, PasswordType.IMAP);
|
||||
|
||||
smtp_password = null;
|
||||
if (!old_account_information.smtp_credentials.is_complete() && smtp_remember_password)
|
||||
smtp_password = keyring_get_password(old_account_information.smtp_credentials.user, PasswordType.SMTP);
|
||||
|
||||
if (Geary.String.is_empty_or_whitespace(imap_password) ||
|
||||
Geary.String.is_empty_or_whitespace(smtp_password)) {
|
||||
request_passwords(old_account_information, password_flags, out imap_password,
|
||||
out smtp_password, out imap_remember_password, out smtp_remember_password);
|
||||
}
|
||||
}
|
||||
|
||||
private string get_default_real_name() {
|
||||
string real_name = Environment.get_real_name();
|
||||
return real_name == "Unknown" ? "" : real_name;
|
||||
}
|
||||
|
||||
private void request_passwords(Geary.AccountInformation old_account_information,
|
||||
PasswordTypeFlag password_flags, out string? imap_password, out string? smtp_password,
|
||||
out bool imap_remember_password, out bool smtp_remember_password) {
|
||||
Geary.AccountInformation temp_account_information;
|
||||
try {
|
||||
temp_account_information = Geary.Engine.instance.get_accounts().get(old_account_information.email);
|
||||
if (temp_account_information == null)
|
||||
temp_account_information = Geary.Engine.instance.create_orphan_account(old_account_information.email);
|
||||
} catch (Error err) {
|
||||
error("Unable to open account information for %s: %s", old_account_information.email,
|
||||
err.message);
|
||||
}
|
||||
|
||||
temp_account_information.imap_credentials = old_account_information.imap_credentials.copy();
|
||||
temp_account_information.smtp_credentials = old_account_information.smtp_credentials.copy();
|
||||
|
||||
bool first_try = !temp_account_information.imap_credentials.is_complete() ||
|
||||
!temp_account_information.smtp_credentials.is_complete();
|
||||
PasswordDialog password_dialog = new PasswordDialog(temp_account_information, first_try,
|
||||
password_flags);
|
||||
if (!password_dialog.run()) {
|
||||
exit(1);
|
||||
imap_password = null;
|
||||
smtp_password = null;
|
||||
imap_remember_password = false;
|
||||
smtp_remember_password = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// password_dialog.password should never be null at this point. It will only be null when
|
||||
// password_dialog.run() returns false, in which case we have already exited/returned.
|
||||
imap_password = password_dialog.imap_password;
|
||||
smtp_password = password_dialog.smtp_password;
|
||||
imap_remember_password = smtp_remember_password = password_dialog.remember_password;
|
||||
|
||||
if (password_flags.has_imap()) {
|
||||
if (imap_remember_password) {
|
||||
keyring_save_password(new Geary.Credentials(temp_account_information.imap_credentials.user,
|
||||
imap_password), PasswordType.IMAP);
|
||||
} else {
|
||||
keyring_delete_password(temp_account_information.imap_credentials.user, PasswordType.IMAP);
|
||||
}
|
||||
}
|
||||
|
||||
if (password_flags.has_smtp()) {
|
||||
if (smtp_remember_password) {
|
||||
keyring_save_password(new Geary.Credentials(temp_account_information.smtp_credentials.user,
|
||||
smtp_password), PasswordType.SMTP);
|
||||
} else {
|
||||
keyring_delete_password(temp_account_information.smtp_credentials.user, PasswordType.SMTP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prompt the user for a service, real name, username, and password, and try to start Geary.
|
||||
private Geary.AccountInformation? request_account_information(Geary.AccountInformation? old_info) {
|
||||
Geary.AccountInformation? new_info = old_info;
|
||||
|
|
@ -416,23 +341,33 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
break;
|
||||
}
|
||||
|
||||
if (new_info.imap_remember_password)
|
||||
keyring_save_password(new_info.imap_credentials, PasswordType.IMAP);
|
||||
else
|
||||
keyring_delete_password(new_info.imap_credentials.user, PasswordType.IMAP);
|
||||
|
||||
if (new_info.smtp_remember_password)
|
||||
keyring_save_password(new_info.smtp_credentials, PasswordType.SMTP);
|
||||
else
|
||||
keyring_delete_password(new_info.smtp_credentials.user, PasswordType.SMTP);
|
||||
do_update_stored_passwords_async.begin(Geary.CredentialsMediator.ServiceFlag.IMAP |
|
||||
Geary.CredentialsMediator.ServiceFlag.SMTP, new_info);
|
||||
|
||||
return new_info;
|
||||
}
|
||||
|
||||
private async void do_update_stored_passwords_async(Geary.CredentialsMediator.ServiceFlag services,
|
||||
Geary.AccountInformation account_information) {
|
||||
try {
|
||||
yield account_information.update_stored_passwords_async(services);
|
||||
} catch (Error e) {
|
||||
debug("Error updating stored passwords: %s", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
private void on_report_problem(Geary.Account.Problem problem, Geary.AccountSettings settings,
|
||||
Error? err) {
|
||||
debug("Reported problem: %s Error: %s", problem.to_string(), err != null ? err.message : "(N/A)");
|
||||
|
||||
Geary.AccountInformation account_information;
|
||||
try {
|
||||
account_information = Geary.Engine.instance.get_accounts().get(settings.email.address);
|
||||
} catch (Error e) {
|
||||
error("Couldn't find previously-opened account %s", settings.email.address);
|
||||
}
|
||||
|
||||
switch (problem) {
|
||||
case Geary.Account.Problem.DATABASE_FAILURE:
|
||||
case Geary.Account.Problem.HOST_UNREACHABLE:
|
||||
|
|
@ -443,17 +378,15 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
// TODO: Different password dialog prompt for SMTP or IMAP login.
|
||||
case Geary.Account.Problem.RECV_EMAIL_LOGIN_FAILED:
|
||||
account.report_problem.disconnect(on_report_problem);
|
||||
keyring_clear_password(account.settings.imap_credentials.user, PasswordType.IMAP);
|
||||
open_account(account.settings.email.address, account.settings.imap_credentials.pass,
|
||||
account.settings.smtp_credentials.pass, PasswordTypeFlag.IMAP, null);
|
||||
do_password_failed_async.begin(Geary.CredentialsMediator.ServiceFlag.IMAP,
|
||||
account_information);
|
||||
break;
|
||||
|
||||
// TODO: Different password dialog prompt for SMTP or IMAP login.
|
||||
case Geary.Account.Problem.SEND_EMAIL_LOGIN_FAILED:
|
||||
account.report_problem.disconnect(on_report_problem);
|
||||
keyring_clear_password(account.settings.smtp_credentials.user, PasswordType.SMTP);
|
||||
open_account(account.settings.email.address, account.settings.imap_credentials.pass,
|
||||
account.settings.smtp_credentials.pass, PasswordTypeFlag.SMTP, null);
|
||||
do_password_failed_async.begin(Geary.CredentialsMediator.ServiceFlag.SMTP,
|
||||
account_information);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -461,6 +394,17 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
}
|
||||
}
|
||||
|
||||
private async void do_password_failed_async(Geary.CredentialsMediator.ServiceFlag services,
|
||||
Geary.AccountInformation account_information) {
|
||||
try {
|
||||
yield account_information.clear_stored_passwords_async(services);
|
||||
} catch (Error e) {
|
||||
debug("Error clearing stored passwords: %s", e.message);
|
||||
}
|
||||
|
||||
open_account(account_information.email, services, null);
|
||||
}
|
||||
|
||||
public File get_user_data_directory() {
|
||||
return File.new_for_path(Environment.get_user_data_dir()).get_child("geary");
|
||||
}
|
||||
|
|
|
|||
87
src/client/gnome-keyring-mediator.vala
Normal file
87
src/client/gnome-keyring-mediator.vala
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/* Copyright 2011-2012 Yorba Foundation
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
public class GnomeKeyringMediator : Geary.CredentialsMediator, Object {
|
||||
private const string OLD_GEARY_USERNAME_PREFIX = "org.yorba.geary username:";
|
||||
|
||||
private string get_key_name(Geary.CredentialsMediator.Service service, string user) {
|
||||
switch (service) {
|
||||
case Service.IMAP:
|
||||
return "org.yorba.geary imap_username:" + user;
|
||||
|
||||
case Service.SMTP:
|
||||
return "org.yorba.geary smtp_username:" + user;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async string? get_password_async(
|
||||
Geary.CredentialsMediator.Service service, string username) throws Error {
|
||||
string password;
|
||||
GnomeKeyring.Result result = GnomeKeyring.find_password_sync(GnomeKeyring.NETWORK_PASSWORD,
|
||||
out password, "user", get_key_name(service, username));
|
||||
|
||||
if (result != GnomeKeyring.Result.OK) {
|
||||
// fallback to the old keyring key string for upgrading users
|
||||
result = GnomeKeyring.find_password_sync(GnomeKeyring.NETWORK_PASSWORD, out password,
|
||||
"user", OLD_GEARY_USERNAME_PREFIX + username);
|
||||
}
|
||||
|
||||
if (result != GnomeKeyring.Result.OK)
|
||||
debug("Unable to fetch password in GNOME keyring: %s", result.to_string());
|
||||
|
||||
return (result == GnomeKeyring.Result.OK) ? password : null;
|
||||
}
|
||||
|
||||
public virtual async void set_password_async(
|
||||
Geary.CredentialsMediator.Service service, Geary.Credentials credentials) throws Error {
|
||||
string key_name = get_key_name(service, credentials.user);
|
||||
|
||||
GnomeKeyring.Result result = GnomeKeyring.store_password_sync(GnomeKeyring.NETWORK_PASSWORD,
|
||||
null, key_name, credentials.pass, "user", key_name);
|
||||
|
||||
if (result != GnomeKeyring.Result.OK)
|
||||
debug("Unable to store password in GNOME keyring: %s", result.to_string());
|
||||
}
|
||||
|
||||
public virtual async void clear_password_async(
|
||||
Geary.CredentialsMediator.Service service, string username) throws Error {
|
||||
// delete new-style and old-style locations
|
||||
GnomeKeyring.delete_password_sync(GnomeKeyring.NETWORK_PASSWORD, "user",
|
||||
get_key_name(service, username));
|
||||
GnomeKeyring.delete_password_sync(GnomeKeyring.NETWORK_PASSWORD, "user",
|
||||
OLD_GEARY_USERNAME_PREFIX + username);
|
||||
}
|
||||
|
||||
public virtual async bool prompt_passwords_async(Geary.CredentialsMediator.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 {
|
||||
bool first_try = !account_information.imap_credentials.is_complete() ||
|
||||
!account_information.smtp_credentials.is_complete();
|
||||
|
||||
PasswordDialog password_dialog = new PasswordDialog(account_information, first_try,
|
||||
services);
|
||||
|
||||
if (!password_dialog.run()) {
|
||||
imap_password = null;
|
||||
smtp_password = null;
|
||||
imap_remember_password = false;
|
||||
smtp_remember_password = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// password_dialog.password should never be null at this point. It will only be null when
|
||||
// password_dialog.run() returns false, in which case we have already returned.
|
||||
imap_password = password_dialog.imap_password;
|
||||
smtp_password = password_dialog.smtp_password;
|
||||
imap_remember_password = password_dialog.remember_password;
|
||||
smtp_remember_password = password_dialog.remember_password;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
/* Copyright 2011-2012 Yorba Foundation
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
const string OLD_GEARY_USERNAME_PREFIX = "org.yorba.geary username:";
|
||||
|
||||
public enum PasswordType {
|
||||
IMAP,
|
||||
SMTP;
|
||||
|
||||
public string get_prefix() {
|
||||
switch (this) {
|
||||
case IMAP:
|
||||
return "org.yorba.geary imap_username:";
|
||||
|
||||
case SMTP:
|
||||
return "org.yorba.geary smtp_username:";
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum PasswordTypeFlag {
|
||||
IMAP,
|
||||
SMTP;
|
||||
|
||||
public bool has_imap() {
|
||||
return (this & IMAP) == IMAP;
|
||||
}
|
||||
|
||||
public bool has_smtp() {
|
||||
return (this & SMTP) == SMTP;
|
||||
}
|
||||
}
|
||||
|
||||
private static string keyring_get_key(PasswordType password_type, string username) {
|
||||
return password_type.get_prefix() + username;
|
||||
}
|
||||
|
||||
public static bool keyring_save_password(Geary.Credentials credentials, PasswordType password_type) {
|
||||
string key = keyring_get_key(password_type, credentials.user);
|
||||
|
||||
GnomeKeyring.Result result = GnomeKeyring.store_password_sync(GnomeKeyring.NETWORK_PASSWORD,
|
||||
null, key, credentials.pass, "user", key);
|
||||
|
||||
if (result != GnomeKeyring.Result.OK)
|
||||
debug("Unable to store password in GNOME keyring: %s", result.to_string());
|
||||
|
||||
return (result == GnomeKeyring.Result.OK);
|
||||
}
|
||||
|
||||
public bool keyring_clear_password(string username, PasswordType password_type) {
|
||||
string key = keyring_get_key(password_type, username);
|
||||
|
||||
GnomeKeyring.Result result = GnomeKeyring.store_password_sync(GnomeKeyring.NETWORK_PASSWORD,
|
||||
null, key, "", "user", key);
|
||||
|
||||
if (result != GnomeKeyring.Result.OK)
|
||||
debug("Unable to clear password in GNOME keyring: %s", result.to_string());
|
||||
|
||||
return (result == GnomeKeyring.Result.OK);
|
||||
}
|
||||
|
||||
public static void keyring_delete_password(string username, PasswordType password_type) {
|
||||
// delete new-style and old-style locations
|
||||
GnomeKeyring.delete_password_sync(GnomeKeyring.NETWORK_PASSWORD, "user",
|
||||
keyring_get_key(password_type, username));
|
||||
GnomeKeyring.delete_password_sync(GnomeKeyring.NETWORK_PASSWORD, "user",
|
||||
OLD_GEARY_USERNAME_PREFIX + username);
|
||||
}
|
||||
|
||||
// Returns the password for the given username, or null if not set.
|
||||
public static string? keyring_get_password(string username, PasswordType password_type) {
|
||||
string password;
|
||||
GnomeKeyring.Result result = GnomeKeyring.find_password_sync(GnomeKeyring.NETWORK_PASSWORD,
|
||||
out password, "user", keyring_get_key(password_type, username));
|
||||
|
||||
if (result != GnomeKeyring.Result.OK) {
|
||||
// fallback to the old keyring key string for upgrading users
|
||||
result = GnomeKeyring.find_password_sync(GnomeKeyring.NETWORK_PASSWORD, out password,
|
||||
"user", OLD_GEARY_USERNAME_PREFIX + username);
|
||||
}
|
||||
|
||||
if (result != GnomeKeyring.Result.OK)
|
||||
debug("Unable to fetch password in GNOME keyring: %s", result.to_string());
|
||||
|
||||
return (result == GnomeKeyring.Result.OK) ? password : null;
|
||||
}
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ public class Geary.DBus.Controller {
|
|||
|
||||
public async void start() {
|
||||
try {
|
||||
yield Geary.Engine.instance.open_async(get_user_data_directory(), get_resource_directory());
|
||||
yield Geary.Engine.instance.open_async(get_user_data_directory(), get_resource_directory(), null);
|
||||
|
||||
connection = yield Bus.get(GLib.BusType.SESSION);
|
||||
|
||||
|
|
@ -41,8 +41,8 @@ public class Geary.DBus.Controller {
|
|||
|
||||
// convert AccountInformation into an Account
|
||||
try {
|
||||
account = account_information.get_account();
|
||||
} catch (EngineError err) {
|
||||
account = Geary.Engine.instance.get_account_instance(account_information);
|
||||
} catch (Error err) {
|
||||
error("Problem loading account from account information: %s", err.message);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,61 +91,154 @@ public class Geary.AccountInformation : Object {
|
|||
imap_server_pipeline = false;
|
||||
}
|
||||
|
||||
public async bool validate_async(Cancellable? cancellable = null) throws EngineError {
|
||||
AccountSettings settings = new AccountSettings(this);
|
||||
/**
|
||||
* Juggles get_passwords_async() and prompt_passwords_async() to fetch the
|
||||
* passwords for the given services. Return true if all passwords were in
|
||||
* the key store or the user proceeded normally, false if the user tried to
|
||||
* cancel.
|
||||
*/
|
||||
public async bool fetch_passwords_async(CredentialsMediator.ServiceFlag services) throws Error {
|
||||
CredentialsMediator.ServiceFlag unset_services =
|
||||
yield get_passwords_async(services);
|
||||
|
||||
// validate IMAP, which requires logging in and establishing an AUTHORIZED cx state
|
||||
bool imap_valid = false;
|
||||
Geary.Imap.ClientSession? imap_session = new Imap.ClientSession(settings.imap_endpoint, true);
|
||||
try {
|
||||
yield imap_session.connect_async(cancellable);
|
||||
yield imap_session.initiate_session_async(settings.imap_credentials, cancellable);
|
||||
if (unset_services == 0)
|
||||
return true;
|
||||
|
||||
return yield prompt_passwords_async(unset_services);
|
||||
}
|
||||
|
||||
private void check_mediator_instance() throws EngineError {
|
||||
if (Geary.Engine.instance.authentication_mediator == null)
|
||||
throw new EngineError.OPEN_REQUIRED(
|
||||
"Geary.Engine instance needs to be open with a valid Geary.CredentialsMediator");
|
||||
}
|
||||
|
||||
/**
|
||||
* Use Engine's authentication mediator to retrieve the passwords for the
|
||||
* given services. The passwords will be stored in the appropriate
|
||||
* credentials in this instance. Return any services that could *not* be
|
||||
* retrieved from the key store (in which case you may want to call
|
||||
* prompt_passwords_async() on the return value), or 0 if all were
|
||||
* retrieved.
|
||||
*/
|
||||
public async CredentialsMediator.ServiceFlag get_passwords_async(
|
||||
CredentialsMediator.ServiceFlag services) throws Error {
|
||||
check_mediator_instance();
|
||||
|
||||
CredentialsMediator mediator = Geary.Engine.instance.authentication_mediator;
|
||||
CredentialsMediator.ServiceFlag failed_services = 0;
|
||||
|
||||
if (services.has_imap()) {
|
||||
string? imap_password = yield mediator.get_password_async(
|
||||
CredentialsMediator.Service.IMAP, imap_credentials.user);
|
||||
|
||||
// Connected and initiated, still need to be sure connection authorized
|
||||
string current_mailbox;
|
||||
if (imap_session.get_context(out current_mailbox) == Imap.ClientSession.Context.AUTHORIZED)
|
||||
imap_valid = true;
|
||||
} catch (Error err) {
|
||||
debug("Error validating IMAP account info: %s", err.message);
|
||||
|
||||
// fall through so session can be disconnected
|
||||
if (imap_password != null)
|
||||
imap_credentials.pass = imap_password;
|
||||
else
|
||||
failed_services |= CredentialsMediator.ServiceFlag.IMAP;
|
||||
}
|
||||
|
||||
try {
|
||||
yield imap_session.disconnect_async(cancellable);
|
||||
} catch (Error err) {
|
||||
// ignored
|
||||
} finally {
|
||||
imap_session = null;
|
||||
if (services.has_smtp()) {
|
||||
string? smtp_password = yield mediator.get_password_async(
|
||||
CredentialsMediator.Service.SMTP, smtp_credentials.user);
|
||||
|
||||
if (smtp_password != null)
|
||||
smtp_credentials.pass = smtp_password;
|
||||
else
|
||||
failed_services |= CredentialsMediator.ServiceFlag.SMTP;
|
||||
}
|
||||
|
||||
if (!imap_valid)
|
||||
return failed_services;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the Engine's authentication mediator to prompt for the passwords for
|
||||
* the given services. The passwords will be stored in the appropriate
|
||||
* credentials in this instance. After the prompt, the passwords will be
|
||||
* updated in the key store using update_stored_passwords_async(). Return
|
||||
* whether the user proceeded normally (false if they tried to cancel the
|
||||
* prompt).
|
||||
*/
|
||||
public async bool prompt_passwords_async(
|
||||
CredentialsMediator.ServiceFlag services) throws Error {
|
||||
check_mediator_instance();
|
||||
|
||||
string? imap_password, smtp_password;
|
||||
bool imap_remember_password, smtp_remember_password;
|
||||
|
||||
if (!yield Geary.Engine.instance.authentication_mediator.prompt_passwords_async(
|
||||
services, this, out imap_password, out smtp_password,
|
||||
out imap_remember_password, out smtp_remember_password))
|
||||
return false;
|
||||
|
||||
// SMTP is simpler, merely see if login works and done (throws an SmtpError if not)
|
||||
bool smtp_valid = false;
|
||||
Geary.Smtp.ClientSession? smtp_session = new Geary.Smtp.ClientSession(settings.smtp_endpoint);
|
||||
try {
|
||||
yield smtp_session.login_async(settings.smtp_credentials, cancellable);
|
||||
smtp_valid = true;
|
||||
} catch (Error err) {
|
||||
debug("Error validating SMTP account info: %s", err.message);
|
||||
|
||||
// fall through so session can be disconnected
|
||||
if (services.has_imap()) {
|
||||
imap_credentials.pass = imap_password;
|
||||
this.imap_remember_password = imap_remember_password;
|
||||
}
|
||||
|
||||
try {
|
||||
yield smtp_session.logout_async(cancellable);
|
||||
} catch (Error err) {
|
||||
// ignored
|
||||
} finally {
|
||||
smtp_session = null;
|
||||
if (services.has_smtp()) {
|
||||
smtp_credentials.pass = smtp_password;
|
||||
this.smtp_remember_password = smtp_remember_password;
|
||||
}
|
||||
|
||||
return smtp_valid;
|
||||
}
|
||||
|
||||
public Endpoint get_imap_endpoint() throws EngineError {
|
||||
yield update_stored_passwords_async(services);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the Engine's authentication mediator to set or clear the passwords
|
||||
* for the given services in the key store.
|
||||
*/
|
||||
public async void update_stored_passwords_async(
|
||||
CredentialsMediator.ServiceFlag services) throws Error {
|
||||
check_mediator_instance();
|
||||
|
||||
CredentialsMediator mediator = Geary.Engine.instance.authentication_mediator;
|
||||
|
||||
if (services.has_imap()) {
|
||||
if (imap_remember_password) {
|
||||
yield mediator.set_password_async(
|
||||
CredentialsMediator.Service.IMAP, imap_credentials);
|
||||
} else {
|
||||
yield mediator.clear_password_async(
|
||||
CredentialsMediator.Service.IMAP, imap_credentials.user);
|
||||
}
|
||||
}
|
||||
|
||||
if (services.has_smtp()) {
|
||||
if (smtp_remember_password) {
|
||||
yield mediator.set_password_async(
|
||||
CredentialsMediator.Service.SMTP, smtp_credentials);
|
||||
} else {
|
||||
yield mediator.clear_password_async(
|
||||
CredentialsMediator.Service.SMTP, smtp_credentials.user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the Engine's authentication mediator to clear the passwords for the
|
||||
* given services in the key store.
|
||||
*/
|
||||
public async void clear_stored_passwords_async(
|
||||
CredentialsMediator.ServiceFlag services) throws Error {
|
||||
check_mediator_instance();
|
||||
|
||||
CredentialsMediator mediator = Geary.Engine.instance.authentication_mediator;
|
||||
|
||||
if (services.has_imap()) {
|
||||
yield mediator.clear_password_async(
|
||||
CredentialsMediator.Service.IMAP, imap_credentials.user);
|
||||
}
|
||||
|
||||
if (services.has_smtp()) {
|
||||
yield mediator.clear_password_async(
|
||||
CredentialsMediator.Service.SMTP, smtp_credentials.user);
|
||||
}
|
||||
}
|
||||
|
||||
public Endpoint get_imap_endpoint() {
|
||||
switch (service_provider) {
|
||||
case ServiceProvider.GMAIL:
|
||||
return ImapEngine.GmailAccount.IMAP_ENDPOINT;
|
||||
|
|
@ -164,12 +257,11 @@ public class Geary.AccountInformation : Object {
|
|||
imap_flags, Imap.ClientConnection.RECOMMENDED_TIMEOUT_SEC);
|
||||
|
||||
default:
|
||||
throw new EngineError.NOT_FOUND("Service provider of type %s not known",
|
||||
service_provider.to_string());
|
||||
assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
public Endpoint get_smtp_endpoint() throws EngineError {
|
||||
public Endpoint get_smtp_endpoint() {
|
||||
switch (service_provider) {
|
||||
case ServiceProvider.GMAIL:
|
||||
return ImapEngine.GmailAccount.SMTP_ENDPOINT;
|
||||
|
|
@ -188,33 +280,7 @@ public class Geary.AccountInformation : Object {
|
|||
smtp_flags, Smtp.ClientConnection.DEFAULT_TIMEOUT_SEC);
|
||||
|
||||
default:
|
||||
throw new EngineError.NOT_FOUND("Service provider of type %s not known",
|
||||
service_provider.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
public Geary.Account get_account() throws EngineError {
|
||||
AccountSettings settings = new AccountSettings(this);
|
||||
|
||||
ImapDB.Account local_account = new ImapDB.Account(settings);
|
||||
Imap.Account remote_account = new Imap.Account(settings);
|
||||
|
||||
switch (service_provider) {
|
||||
case ServiceProvider.GMAIL:
|
||||
return new ImapEngine.GmailAccount("Gmail account %s".printf(email),
|
||||
settings, remote_account, local_account);
|
||||
|
||||
case ServiceProvider.YAHOO:
|
||||
return new ImapEngine.YahooAccount("Yahoo account %s".printf(email),
|
||||
settings, remote_account, local_account);
|
||||
|
||||
case ServiceProvider.OTHER:
|
||||
return new ImapEngine.OtherAccount("Other account %s".printf(email),
|
||||
settings, remote_account, local_account);
|
||||
|
||||
default:
|
||||
throw new EngineError.NOT_FOUND("Service provider of type %s not known",
|
||||
service_provider.to_string());
|
||||
assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -736,7 +736,7 @@ public class Geary.ConversationMonitor : Object {
|
|||
// reset
|
||||
retry_connection = false;
|
||||
|
||||
debug("Folder %s closed due to error, restablishing connection to continue monitoring conversations",
|
||||
debug("Folder %s closed due to error, reestablishing connection to continue monitoring conversations",
|
||||
folder.to_string());
|
||||
|
||||
// First retry is immediate; thereafter, a delay
|
||||
|
|
@ -763,7 +763,7 @@ public class Geary.ConversationMonitor : Object {
|
|||
debug("Reestablished connection to %s, continuing to monitor conversations",
|
||||
folder.to_string());
|
||||
} catch (Error start_err) {
|
||||
debug("Unable to restablish connection to %s, retrying in %d seconds: %s", folder.to_string(),
|
||||
debug("Unable to reestablish connection to %s, retrying in %d seconds: %s", folder.to_string(),
|
||||
RETRY_CONNECTION_SEC, start_err.message);
|
||||
|
||||
schedule_retry(true);
|
||||
|
|
|
|||
59
src/engine/api/geary-credentials-mediator.vala
Normal file
59
src/engine/api/geary-credentials-mediator.vala
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* Copyright 2011-2012 Yorba Foundation
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
public interface Geary.CredentialsMediator : Object {
|
||||
public enum Service {
|
||||
IMAP,
|
||||
SMTP;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ServiceFlag {
|
||||
IMAP,
|
||||
SMTP;
|
||||
|
||||
public bool has_imap() {
|
||||
return (this & IMAP) == IMAP;
|
||||
}
|
||||
|
||||
public bool has_smtp() {
|
||||
return (this & SMTP) == SMTP;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the key store for the password of the given username for the given
|
||||
* service. Return null if the password wasn't in the key store, or the
|
||||
* password if it was.
|
||||
*/
|
||||
public abstract async string? get_password_async(Service service, string username) throws Error;
|
||||
|
||||
/**
|
||||
* Add or update the key store's password entry for the given credentials
|
||||
* for the given service.
|
||||
*/
|
||||
public abstract async void set_password_async(Service service,
|
||||
Geary.Credentials credentials) throws Error;
|
||||
|
||||
/**
|
||||
* Deletes the key store's password entry for the given credentials for the
|
||||
* given service. Do nothing (and do *not* throw an error) if the
|
||||
* credentials weren't in the key store.
|
||||
*/
|
||||
public abstract async void clear_password_async(Service service, string username) throws Error;
|
||||
|
||||
/**
|
||||
* Prompt the user to enter passwords for the given services in the given
|
||||
* account. Set the out parameters for the services to the values entered
|
||||
* by the user (out parameters for services not being prompted for are
|
||||
* ignored). Return false if the user tried to cancel the interaction, or
|
||||
* true if they tried to proceed.
|
||||
*/
|
||||
public abstract async bool prompt_passwords_async(ServiceFlag services,
|
||||
AccountInformation account_information,
|
||||
out string? imap_password, out string? smtp_password,
|
||||
out bool imap_remember_password, out bool smtp_remember_password) throws Error;
|
||||
}
|
||||
|
|
@ -17,9 +17,11 @@ public class Geary.Engine {
|
|||
|
||||
public File? user_data_dir { get; private set; default = null; }
|
||||
public File? resource_dir { get; private set; default = null; }
|
||||
public Geary.CredentialsMediator? authentication_mediator { get; private set; default = null; }
|
||||
|
||||
private bool is_open = false;
|
||||
private Gee.HashMap<string, AccountInformation>? accounts = null;
|
||||
private Gee.HashMap<string, Account>? account_instances = null;
|
||||
|
||||
/**
|
||||
* Fired when the engine is opened.
|
||||
|
|
@ -66,17 +68,22 @@ public class Geary.Engine {
|
|||
}
|
||||
|
||||
/**
|
||||
* Initializes the engine, and makes all existing accounts available.
|
||||
* Initializes the engine, and makes all existing accounts available. The
|
||||
* given authentication mediator will be used to retrieve all passwords
|
||||
* when necessary.
|
||||
*/
|
||||
public async void open_async(File user_data_dir, File resource_dir,
|
||||
Geary.CredentialsMediator? authentication_mediator,
|
||||
Cancellable? cancellable = null) throws Error {
|
||||
if (is_open)
|
||||
throw new EngineError.ALREADY_OPEN("Geary.Engine instance already open");
|
||||
|
||||
this.user_data_dir = user_data_dir;
|
||||
this.resource_dir = resource_dir;
|
||||
this.authentication_mediator = authentication_mediator;
|
||||
|
||||
accounts = new Gee.HashMap<string, AccountInformation>();
|
||||
account_instances = new Gee.HashMap<string, Account>();
|
||||
|
||||
is_open = true;
|
||||
opened();
|
||||
|
|
@ -128,7 +135,9 @@ public class Geary.Engine {
|
|||
|
||||
user_data_dir = null;
|
||||
resource_dir = null;
|
||||
authentication_mediator = null;
|
||||
accounts = null;
|
||||
account_instances = null;
|
||||
|
||||
is_open = false;
|
||||
closed();
|
||||
|
|
@ -154,7 +163,107 @@ public class Geary.Engine {
|
|||
|
||||
return new AccountInformation(user_data_dir.get_child(email));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether the account information "validates", which means here
|
||||
* that we can connect to the endpoints and authenticate using the supplied
|
||||
* credentials.
|
||||
*/
|
||||
public async bool validate_account_information_async(AccountInformation account,
|
||||
Cancellable? cancellable = null) throws Error {
|
||||
check_opened();
|
||||
|
||||
// validate IMAP, which requires logging in and establishing an AUTHORIZED cx state
|
||||
bool imap_valid = false;
|
||||
Geary.Imap.ClientSession? imap_session = new Imap.ClientSession(account.get_imap_endpoint(), true);
|
||||
try {
|
||||
yield imap_session.connect_async(cancellable);
|
||||
yield imap_session.initiate_session_async(account.imap_credentials, cancellable);
|
||||
|
||||
// Connected and initiated, still need to be sure connection authorized
|
||||
string current_mailbox;
|
||||
if (imap_session.get_context(out current_mailbox) == Imap.ClientSession.Context.AUTHORIZED)
|
||||
imap_valid = true;
|
||||
} catch (Error err) {
|
||||
debug("Error validating IMAP account info: %s", err.message);
|
||||
|
||||
// fall through so session can be disconnected
|
||||
}
|
||||
|
||||
try {
|
||||
yield imap_session.disconnect_async(cancellable);
|
||||
} catch (Error err) {
|
||||
// ignored
|
||||
} finally {
|
||||
imap_session = null;
|
||||
}
|
||||
|
||||
if (!imap_valid)
|
||||
return false;
|
||||
|
||||
// SMTP is simpler, merely see if login works and done (throws an SmtpError if not)
|
||||
bool smtp_valid = false;
|
||||
Geary.Smtp.ClientSession? smtp_session = new Geary.Smtp.ClientSession(account.get_smtp_endpoint());
|
||||
try {
|
||||
yield smtp_session.login_async(account.smtp_credentials, cancellable);
|
||||
smtp_valid = true;
|
||||
} catch (Error err) {
|
||||
debug("Error validating SMTP account info: %s", err.message);
|
||||
|
||||
// fall through so session can be disconnected
|
||||
}
|
||||
|
||||
try {
|
||||
yield smtp_session.logout_async(cancellable);
|
||||
} catch (Error err) {
|
||||
// ignored
|
||||
} finally {
|
||||
smtp_session = null;
|
||||
}
|
||||
|
||||
return smtp_valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Geary.Account from a Geary.AccountInformation (which is what
|
||||
* other methods in this interface deal in).
|
||||
*/
|
||||
public Geary.Account get_account_instance(AccountInformation account_information)
|
||||
throws Error {
|
||||
check_opened();
|
||||
|
||||
if (account_instances.has_key(account_information.email))
|
||||
return account_instances.get(account_information.email);
|
||||
|
||||
AccountSettings settings = new AccountSettings(account_information);
|
||||
ImapDB.Account local_account = new ImapDB.Account(settings);
|
||||
Imap.Account remote_account = new Imap.Account(settings);
|
||||
|
||||
Geary.Account account;
|
||||
switch (account_information.service_provider) {
|
||||
case ServiceProvider.GMAIL:
|
||||
account = new ImapEngine.GmailAccount("Gmail account %s".printf(account_information.email),
|
||||
settings, remote_account, local_account);
|
||||
break;
|
||||
|
||||
case ServiceProvider.YAHOO:
|
||||
account = new ImapEngine.YahooAccount("Yahoo account %s".printf(account_information.email),
|
||||
settings, remote_account, local_account);
|
||||
break;
|
||||
|
||||
case ServiceProvider.OTHER:
|
||||
account = new ImapEngine.OtherAccount("Other account %s".printf(account_information.email),
|
||||
settings, remote_account, local_account);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
account_instances.set(account_information.email, account);
|
||||
return account;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the account to be tracked by the engine. Should only be called from
|
||||
* AccountInformation.store_async() and this class.
|
||||
|
|
@ -185,6 +294,8 @@ public class Geary.Engine {
|
|||
|
||||
// TODO: delete the account from disk.
|
||||
account_removed(account);
|
||||
|
||||
account_instances.unset(account.email);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -556,7 +556,7 @@ public class Geary.Imap.ClientSession {
|
|||
*/
|
||||
public async CommandResponse login_async(Geary.Credentials credentials, Cancellable? cancellable = null)
|
||||
throws Error {
|
||||
LoginParams params = new LoginParams(credentials.user, credentials.pass, cancellable,
|
||||
LoginParams params = new LoginParams(credentials.user, credentials.pass ?? "", cancellable,
|
||||
login_async.callback);
|
||||
fsm.issue(Event.LOGIN, null, params);
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ public class Geary.Smtp.LoginAuthenticator : Geary.Smtp.AbstractAuthenticator {
|
|||
return Base64.encode(credentials.user.data).data;
|
||||
|
||||
case 1:
|
||||
return Base64.encode(credentials.pass.data).data;
|
||||
return Base64.encode((credentials.pass ?? "").data).data;
|
||||
|
||||
default:
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public class Geary.Smtp.PlainAuthenticator : Geary.Smtp.AbstractAuthenticator {
|
|||
growable.append(nul);
|
||||
growable.append(credentials.user.data);
|
||||
growable.append(nul);
|
||||
growable.append(credentials.pass.data);
|
||||
growable.append((credentials.pass ?? "").data);
|
||||
|
||||
return Base64.encode(growable.get_array()).data;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue