Load and display multiple accounts; fix #6230
Lots has been changed here. See the bug report <http://redmine.yorba.org/issues/6230> for some of the discussion about it. This also fixes #6274. I'll cut the list of revisions off after a while, because this branch has been outstanding for a couple weeks. Squashed commit of the following: commit ae505d89e87e63e0d8949bfd901913706a9d3b73 Merge: 81ef002e18bef9Author: Charles Lindsay <chaz@yorba.org> Date: Thu Jan 31 15:16:17 2013 -0800 Merge branch 'master' into multiple-accounts commit 81ef002f5ff486b9c28f5663a0ba1e7392b8489c Author: Charles Lindsay <chaz@yorba.org> Date: Thu Jan 31 15:15:51 2013 -0800 Fix final round of code review commit 6935b1e7892b9b356bf5006b89e0b2a4e6a8ad16 Merge: c9ed434a9dc52bAuthor: Charles Lindsay <chaz@yorba.org> Date: Thu Jan 31 14:45:46 2013 -0800 Merge branch 'master' into multiple-accounts commit c9ed434fe936e6aed735baef222ae615364c2513 Author: Charles Lindsay <chaz@yorba.org> Date: Thu Jan 31 14:31:02 2013 -0800 Simplify folder comparator commit 28ac020cfd9135c6eb4ed05574c82b92f99c4a40 Author: Charles Lindsay <chaz@yorba.org> Date: Thu Jan 31 14:06:55 2013 -0800 Bump up declaration to conform to guidelines commit 0a8167bdaebd5fac1c3ca791de5f2cc233c13cb9 Author: Charles Lindsay <chaz@yorba.org> Date: Thu Jan 31 13:54:03 2013 -0800 Rename back to list_*folders commit 31457f60298052bdddba8e426db27f93d7c72529 Author: Charles Lindsay <chaz@yorba.org> Date: Thu Jan 31 12:36:15 2013 -0800 Fix spacing, brevity issues commit ecd30c203d80c21c1ca1234b8911b57efcb68294 Author: Charles Lindsay <chaz@yorba.org> Date: Wed Jan 30 17:56:29 2013 -0800 Fix nits before review commit 85b51d71e83115991cd9a54d491b4d45b71f2f9b Merge: b29abced538bf0Author: Charles Lindsay <chaz@yorba.org> Date: Wed Jan 30 17:46:19 2013 -0800 Merge branch 'master' into multiple-accounts commit b29abceeaea84f226ab9bcd22266a511691d8005 Author: Charles Lindsay <chaz@yorba.org> Date: Wed Jan 30 17:22:28 2013 -0800 Fix notifications commit c26d975fb0859d807ddb7f7c10632605c3b6fb1c Author: Charles Lindsay <chaz@yorba.org> Date: Wed Jan 30 13:01:03 2013 -0800 Only show current acct. folders in copy/move menus commit 9a5b57db1229a079f11f518c53f5762a3670b83f Author: Charles Lindsay <chaz@yorba.org> Date: Wed Jan 30 11:48:05 2013 -0800 Fix issue where wrong mail would show in folders commit 3b05d18843584c2aff7472708eea30ce24068043 Author: Charles Lindsay <chaz@yorba.org> Date: Wed Jan 30 11:18:38 2013 -0800 Fix ordering of folders in side bar commit b228967b6a74c16698d593e53e65d66c69ffb974 Author: Charles Lindsay <chaz@yorba.org> Date: Wed Jan 30 11:07:32 2013 -0800 Add icon to accounts in sidebar commit dd05d2c987a46f0b6699d743c339297e06829e4f Author: Charles Lindsay <chaz@yorba.org> Date: Tue Jan 29 19:04:52 2013 -0800 Fix Labels icon commit b5254fe8f6ef37df48d41167d0f52f3cd88d1966 Author: Charles Lindsay <chaz@yorba.org> Date: Tue Jan 29 18:43:45 2013 -0800 Initial stab at new FolderList; fix compile errors commit ff591810ee4312acce208dfa36d993069bc4c7d2 Merge: 2b9dbb9ff5f9faAuthor: Charles Lindsay <chaz@yorba.org> Date: Mon Jan 28 17:42:34 2013 -0800 Merge branch 'master' into multiple-accounts commit 2b9dbb9b6963b1d52b2b90300bcea277b01d2094 Merge: 7583241fcfb460Author: Charles Lindsay <chaz@yorba.org> Date: Mon Jan 28 17:21:49 2013 -0800 Merge branch 'master' into multiple-accounts Conflicts: src/client/geary-controller.vala commit 75832412cc806c956848e32ef20052af36d4f64d Author: Charles Lindsay <chaz@yorba.org> Date: Mon Jan 28 16:37:15 2013 -0800 Fix IMAP sess. mgr. to recover from bad passwords commit 8868b4be5c3f5c97246d35c6170531c6f543abe1 Author: Charles Lindsay <chaz@yorba.org> Date: Mon Jan 28 12:06:21 2013 -0800 Typo commit 3f909054502d31ca48e11f7948fd22118afe7514 Author: Charles Lindsay <chaz@yorba.org> Date: Mon Jan 28 10:54:51 2013 -0800 Clean up interface a little commit 3bfb526fe8801f8234127944be8594a960ccf7e7 Merge: 5e84e93e971275Author: Charles Lindsay <chaz@yorba.org> Date: Fri Jan 25 16:23:52 2013 -0800 Merge branch 'master' into multiple-accounts Conflicts: src/client/geary-application.vala src/engine/api/geary-engine.vala commit 5e84e9375a655567a3bc4eb7ebaacab2d218be40 Merge: 35cc46b 9167aeb Author: Charles Lindsay <chaz@yorba.org> Date: Fri Jan 25 16:17:00 2013 -0800 Merge branch 'pluggable-auth' into multiple-accounts Conflicts: src/engine/api/geary-engine.vala commit 9167aeb56be6789d49a3e7cdba2a21d2b015e40d Author: Charles Lindsay <chaz@yorba.org> Date: Fri Jan 25 16:11:20 2013 -0800 Fix for code guidelines commit 35cc46bc99f44f1597c609bfeaa72dd503333a17 Merge: 9675f47 7612a7d Author: Charles Lindsay <chaz@yorba.org> Date: Fri Jan 25 15:44:18 2013 -0800 Merge branch 'pluggable-auth' into multiple-accounts Conflicts: src/client/geary-application.vala commit 7612a7ddc3df14ef207b9e74ee32fa23710e1ce9 Author: Charles Lindsay <chaz@yorba.org> Date: Fri Jan 25 15:26:48 2013 -0800 Fix code review issues commit 46635544c98df7a8b6c76f028715814907274389 Merge: 30b611e6de36aeAuthor: Charles Lindsay <chaz@yorba.org> Date: Fri Jan 25 12:54:03 2013 -0800 Merge branch 'master' into pluggable-auth commit 9675f473e77d0d581cf73a33012981e6a4f44943 Author: Charles Lindsay <chaz@yorba.org> Date: Fri Jan 25 12:53:18 2013 -0800 Try to make Folder know about its Account commit 5d9af43e53199a616490cf6ff98bd3c613b4e5f2 Merge: 335480e6de36aeAuthor: Charles Lindsay <chaz@yorba.org> Date: Fri Jan 25 12:12:21 2013 -0800 Merge branch 'master' into multiple-accounts commit 335480e2dd0261c8fb82f1c6296f5b8c76f3ac02 Author: Charles Lindsay <chaz@yorba.org> Date: Fri Jan 25 12:11:18 2013 -0800 Work on multiple accounts; fix compilation errors commit 808e65d55798e3f08b4c70992718cc11befbb45c Author: Charles Lindsay <chaz@yorba.org> Date: Thu Jan 24 19:28:12 2013 -0800 Fix application logic for multiple accounts You get the idea.
This commit is contained in:
parent
e18bef9638
commit
3308189ece
24 changed files with 437 additions and 473 deletions
|
|
@ -14,7 +14,6 @@ engine/abstract/geary-abstract-folder.vala
|
|||
|
||||
engine/api/geary-account.vala
|
||||
engine/api/geary-account-information.vala
|
||||
engine/api/geary-account-settings.vala
|
||||
engine/api/geary-attachment.vala
|
||||
engine/api/geary-composed-email.vala
|
||||
engine/api/geary-contact.vala
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
private static GearyApplication _instance = null;
|
||||
|
||||
private GearyController? controller = null;
|
||||
private Geary.Account? account = null;
|
||||
|
||||
private LoginDialog? login_dialog = null;
|
||||
|
||||
|
|
@ -108,8 +107,6 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
if (controller.main_window != null)
|
||||
controller.main_window.destroy();
|
||||
|
||||
controller.disconnect_account_async.begin(null);
|
||||
|
||||
Date.terminate();
|
||||
|
||||
return true;
|
||||
|
|
@ -130,17 +127,22 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
return;
|
||||
}
|
||||
|
||||
Geary.Engine.instance.account_available.connect(on_account_available);
|
||||
Geary.Engine.instance.account_unavailable.connect(on_account_unavailable);
|
||||
|
||||
config = new Configuration();
|
||||
controller = new GearyController();
|
||||
|
||||
// Start Geary.
|
||||
try {
|
||||
yield Geary.Engine.instance.open_async(get_user_data_directory(), get_resource_directory(),
|
||||
new GnomeKeyringMediator());
|
||||
if (Geary.Engine.instance.get_accounts().size == 0)
|
||||
create_account();
|
||||
} catch (Error e) {
|
||||
error("Error opening Geary.Engine instance: %s", e.message);
|
||||
}
|
||||
|
||||
config = new Configuration();
|
||||
controller = new GearyController();
|
||||
initialize_account();
|
||||
handle_args(args);
|
||||
}
|
||||
|
||||
|
|
@ -152,44 +154,34 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
return action;
|
||||
}
|
||||
|
||||
private void set_account(Geary.Account? account) {
|
||||
if (this.account == account)
|
||||
return;
|
||||
|
||||
if (this.account != null)
|
||||
this.account.report_problem.disconnect(on_report_problem);
|
||||
|
||||
this.account = account;
|
||||
|
||||
if (this.account != null)
|
||||
this.account.report_problem.connect(on_report_problem);
|
||||
|
||||
controller.connect_account_async.begin(this.account, null);
|
||||
private void open_account(Geary.Account account) {
|
||||
account.report_problem.connect(on_report_problem);
|
||||
controller.connect_account_async.begin(account);
|
||||
}
|
||||
|
||||
private void initialize_account() {
|
||||
Geary.AccountInformation? account_information = get_account();
|
||||
if (account_information == null) {
|
||||
create_account(null);
|
||||
} else {
|
||||
open_account(account_information.email,
|
||||
Geary.CredentialsMediator.ServiceFlag.IMAP, null);
|
||||
private void close_account(Geary.Account account) {
|
||||
account.report_problem.disconnect(on_report_problem);
|
||||
controller.disconnect_account_async.begin(account);
|
||||
}
|
||||
|
||||
private Geary.Account get_account_instance(Geary.AccountInformation account_information) {
|
||||
try {
|
||||
return Geary.Engine.instance.get_account_instance(account_information);
|
||||
} catch (Error e) {
|
||||
error("Error creating account instance: %s", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
private void create_account(string? email) {
|
||||
Geary.AccountInformation? old_account_information = null;
|
||||
if (email != null) {
|
||||
try {
|
||||
old_account_information = Geary.Engine.instance.get_accounts().get(email);
|
||||
} catch (Error err) {
|
||||
debug("Unable to open account information for %s, creating instead: %s", email,
|
||||
err.message);
|
||||
}
|
||||
}
|
||||
|
||||
Geary.AccountInformation? account_information =
|
||||
request_account_information(old_account_information);
|
||||
private void on_account_available(Geary.AccountInformation account_information) {
|
||||
open_account(get_account_instance(account_information));
|
||||
}
|
||||
|
||||
private void on_account_unavailable(Geary.AccountInformation account_information) {
|
||||
close_account(get_account_instance(account_information));
|
||||
}
|
||||
|
||||
private void create_account() {
|
||||
Geary.AccountInformation? account_information = request_account_information(null);
|
||||
if (account_information != null)
|
||||
do_validate_until_successful_async.begin(account_information);
|
||||
}
|
||||
|
|
@ -220,10 +212,8 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
// exit could be canceled is if there are unsaved composer windows open (which won't
|
||||
// happen before an account is created). However, best to include this check for the
|
||||
// future.
|
||||
if (new_account_information == null) {
|
||||
set_account(null);
|
||||
if (new_account_information == null)
|
||||
return null;
|
||||
}
|
||||
|
||||
debug("User entered revised account information, retrying validation");
|
||||
return new_account_information;
|
||||
|
|
@ -243,62 +233,8 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
account_information.store_async.begin(cancellable);
|
||||
|
||||
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, Geary.CredentialsMediator.ServiceFlag password_flags,
|
||||
Cancellable? cancellable) {
|
||||
Geary.AccountInformation account_information;
|
||||
try {
|
||||
account_information = Geary.Engine.instance.get_accounts().get(email);
|
||||
if (account_information == null)
|
||||
account_information = Geary.Engine.instance.create_orphan_account(email);
|
||||
} catch (Error err) {
|
||||
error("Unable to open account information for label %s: %s", email, err.message);
|
||||
}
|
||||
|
||||
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 {
|
||||
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);
|
||||
set_account(null);
|
||||
}
|
||||
}
|
||||
|
||||
private Geary.AccountInformation? get_account() {
|
||||
try {
|
||||
Geary.AccountInformation[] accounts = Geary.Engine.instance.get_accounts().values.to_array();
|
||||
if (accounts.length > 0)
|
||||
return accounts[0];
|
||||
} catch (Error e) {
|
||||
debug("Unable to fetch account labels: %s", e.message);
|
||||
}
|
||||
|
||||
return null;
|
||||
debug("Successfully validated account information");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Prompt the user for a service, real name, username, and password, and try to start Geary.
|
||||
|
|
@ -350,17 +286,9 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
}
|
||||
}
|
||||
|
||||
private void on_report_problem(Geary.Account.Problem problem, Geary.AccountSettings settings,
|
||||
Error? err) {
|
||||
private void on_report_problem(Geary.Account account, Geary.Account.Problem problem, 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:
|
||||
|
|
@ -368,18 +296,11 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
|
|||
// TODO
|
||||
break;
|
||||
|
||||
// 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);
|
||||
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);
|
||||
do_password_failed_async.begin(Geary.CredentialsMediator.ServiceFlag.SMTP,
|
||||
account_information);
|
||||
// At this point, we've prompted them for the password and
|
||||
// they've hit cancel, so there's not much for us to do here.
|
||||
close_account(account);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -387,17 +308,6 @@ 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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,14 +40,16 @@ public class GearyController {
|
|||
|
||||
public MainWindow main_window { get; private set; }
|
||||
|
||||
private Geary.Account? account = null;
|
||||
private Geary.Account? current_account = null;
|
||||
private Gee.HashMap<Geary.Account, Geary.Folder> inboxes
|
||||
= new Gee.HashMap<Geary.Account, Geary.Folder>();
|
||||
private Geary.Folder? current_folder = null;
|
||||
private Geary.ConversationMonitor? current_conversations = null;
|
||||
private Gee.HashMap<Geary.Account, Geary.ConversationMonitor> inbox_conversations
|
||||
= new Gee.HashMap<Geary.Account, Geary.ConversationMonitor>();
|
||||
private Cancellable cancellable_folder = new Cancellable();
|
||||
private Cancellable cancellable_inbox = new Cancellable();
|
||||
private Cancellable cancellable_message = new Cancellable();
|
||||
private Geary.Folder? current_folder = null;
|
||||
private Geary.Folder? inbox_folder = null;
|
||||
private Geary.ConversationMonitor? current_conversations = null;
|
||||
private Geary.ConversationMonitor? inbox_conversations = null;
|
||||
private int busy_count = 0;
|
||||
private Gee.Set<Geary.Conversation> selected_conversations = new Gee.HashSet<Geary.Conversation>();
|
||||
private Geary.Conversation? last_deleted_conversation = null;
|
||||
|
|
@ -107,7 +109,7 @@ public class GearyController {
|
|||
}
|
||||
|
||||
~GearyController() {
|
||||
assert(account == null);
|
||||
assert(current_account == null);
|
||||
}
|
||||
|
||||
private void add_accelerator(string accelerator, string action) {
|
||||
|
|
@ -242,78 +244,59 @@ public class GearyController {
|
|||
GearyApplication.instance.get_action(ACTION_DELETE_MESSAGE).is_important = true;
|
||||
}
|
||||
|
||||
public async void connect_account_async(Geary.Account? new_account, Cancellable? cancellable) {
|
||||
if (account == new_account)
|
||||
return;
|
||||
|
||||
// Disconnect the old account, if any.
|
||||
if (account != null) {
|
||||
cancel_folder();
|
||||
cancel_inbox();
|
||||
cancel_message();
|
||||
|
||||
account.folders_available_unavailable.disconnect(on_folders_available_unavailable);
|
||||
|
||||
main_window.title = GearyApplication.NAME;
|
||||
main_window.conversation_list_store.account_owner_email = null;
|
||||
main_window.folder_list.remove_all_branches();
|
||||
|
||||
if (inbox_conversations != null) {
|
||||
try {
|
||||
yield inbox_conversations.stop_monitoring_async(true, cancellable);
|
||||
} catch (Error close_conversations_err) {
|
||||
debug("Unable to stop monitoring inbox: %s", close_conversations_err.message);
|
||||
}
|
||||
|
||||
inbox_conversations = null;
|
||||
}
|
||||
|
||||
if (inbox_folder != null) {
|
||||
try {
|
||||
yield inbox_folder.close_async(cancellable);
|
||||
} catch (Error close_inbox_err) {
|
||||
debug("Unable to close monitored inbox: %s", close_inbox_err.message);
|
||||
}
|
||||
|
||||
inbox_folder = null;
|
||||
}
|
||||
|
||||
try {
|
||||
yield account.close_async(cancellable);
|
||||
} catch (Error close_err) {
|
||||
debug("Unable to close account %s: %s", account.to_string(), close_err.message);
|
||||
}
|
||||
}
|
||||
|
||||
account = new_account;
|
||||
|
||||
// Connect the new account, if any.
|
||||
if (account != null) {
|
||||
account.folders_available_unavailable.connect(on_folders_available_unavailable);
|
||||
public async void connect_account_async(Geary.Account account, Cancellable? cancellable = null) {
|
||||
account.folders_available_unavailable.connect(on_folders_available_unavailable);
|
||||
|
||||
try {
|
||||
yield account.open_async(cancellable);
|
||||
} catch (Error open_err) {
|
||||
// TODO: Better error reporting to user
|
||||
debug("Unable to open account %s: %s", account.to_string(), open_err.message);
|
||||
|
||||
account = null;
|
||||
|
||||
GearyApplication.instance.panic();
|
||||
}
|
||||
try {
|
||||
yield account.open_async(cancellable);
|
||||
} catch (Error open_err) {
|
||||
// TODO: Better error reporting to user
|
||||
debug("Unable to open account %s: %s", account.to_string(), open_err.message);
|
||||
|
||||
account.email_sent.connect(on_sent);
|
||||
|
||||
if (account.settings.service_provider == Geary.ServiceProvider.YAHOO)
|
||||
main_window.title = GearyApplication.NAME + "!";
|
||||
main_window.conversation_list_store.account_owner_email = account.settings.email.address;
|
||||
|
||||
main_window.folder_list.set_user_folders_root_name(_("Labels"));
|
||||
GearyApplication.instance.panic();
|
||||
}
|
||||
|
||||
account.email_sent.connect(on_sent);
|
||||
|
||||
main_window.folder_list.set_user_folders_root_name(account, _("Labels"));
|
||||
}
|
||||
|
||||
public async void disconnect_account_async(Cancellable? cancellable) throws Error {
|
||||
yield connect_account_async(null, cancellable);
|
||||
public async void disconnect_account_async(Geary.Account account, Cancellable? cancellable = null) {
|
||||
cancel_folder();
|
||||
cancel_inbox();
|
||||
cancel_message();
|
||||
|
||||
account.folders_available_unavailable.disconnect(on_folders_available_unavailable);
|
||||
|
||||
if (main_window.conversation_list_store.account_owner_email == account.information.email)
|
||||
main_window.conversation_list_store.account_owner_email = null;
|
||||
main_window.folder_list.remove_account(account);
|
||||
|
||||
if (inbox_conversations.has_key(account)) {
|
||||
try {
|
||||
yield inbox_conversations.get(account).stop_monitoring_async(true, cancellable);
|
||||
} catch (Error close_conversations_err) {
|
||||
debug("Unable to stop monitoring inbox: %s", close_conversations_err.message);
|
||||
}
|
||||
|
||||
inbox_conversations.unset(account);
|
||||
}
|
||||
|
||||
if (inboxes.has_key(account)) {
|
||||
try {
|
||||
yield inboxes.get(account).close_async(cancellable);
|
||||
} catch (Error close_inbox_err) {
|
||||
debug("Unable to close monitored inbox: %s", close_inbox_err.message);
|
||||
}
|
||||
|
||||
inboxes.unset(account);
|
||||
}
|
||||
|
||||
try {
|
||||
yield account.close_async(cancellable);
|
||||
} catch (Error close_err) {
|
||||
debug("Unable to close account %s: %s", account.to_string(), close_err.message);
|
||||
}
|
||||
}
|
||||
|
||||
private bool is_viewed_conversation(Geary.Conversation? conversation) {
|
||||
|
|
@ -352,15 +335,16 @@ public class GearyController {
|
|||
private async void do_select_folder(Geary.Folder folder) throws Error {
|
||||
cancel_folder();
|
||||
|
||||
Cancellable? conversation_cancellable = (current_folder != inbox_folder)
|
||||
? cancellable_folder : cancellable_inbox;
|
||||
bool current_is_inbox = inboxes.values.contains(current_folder);
|
||||
|
||||
// stop monitoring for conversations and close the folder (but only if not the inbox_folder,
|
||||
Cancellable? conversation_cancellable = (current_is_inbox ? cancellable_inbox : cancellable_folder);
|
||||
|
||||
// stop monitoring for conversations and close the folder (but only if not an inbox,
|
||||
// which we leave open for notifications)
|
||||
if (current_conversations != null) {
|
||||
yield current_conversations.stop_monitoring_async((current_folder != inbox_folder), null);
|
||||
yield current_conversations.stop_monitoring_async(!current_is_inbox, null);
|
||||
current_conversations = null;
|
||||
} else if (current_folder != null && current_folder != inbox_folder) {
|
||||
} else if (current_folder != null && !current_is_inbox) {
|
||||
yield current_folder.close_async();
|
||||
}
|
||||
|
||||
|
|
@ -368,7 +352,17 @@ public class GearyController {
|
|||
debug("switching to %s", folder.to_string());
|
||||
|
||||
current_folder = folder;
|
||||
current_account = folder.account;
|
||||
|
||||
main_window.conversation_list_store.set_current_folder(current_folder, conversation_cancellable);
|
||||
main_window.conversation_list_store.account_owner_email = current_account.information.email;
|
||||
|
||||
main_window.main_toolbar.copy_folder_menu.clear();
|
||||
main_window.main_toolbar.move_folder_menu.clear();
|
||||
foreach(Geary.Folder f in current_folder.account.list_folders()) {
|
||||
main_window.main_toolbar.copy_folder_menu.add_folder(f);
|
||||
main_window.main_toolbar.move_folder_menu.add_folder(f);
|
||||
}
|
||||
|
||||
// The current folder may be null if the user rapidly switches between folders. If they have
|
||||
// done that then this folder selection is invalid anyways, so just return.
|
||||
|
|
@ -379,16 +373,16 @@ public class GearyController {
|
|||
|
||||
update_ui();
|
||||
|
||||
if (current_folder != inbox_folder) {
|
||||
if (!inboxes.values.contains(current_folder)) {
|
||||
current_conversations = new Geary.ConversationMonitor(current_folder, false,
|
||||
ConversationListStore.REQUIRED_FIELDS);
|
||||
} else {
|
||||
if (inbox_conversations == null) {
|
||||
inbox_conversations = new Geary.ConversationMonitor(inbox_folder, false,
|
||||
ConversationListStore.REQUIRED_FIELDS);
|
||||
if (!inbox_conversations.has_key(folder.account)) {
|
||||
inbox_conversations.set(folder.account, new Geary.ConversationMonitor(
|
||||
current_folder, false, ConversationListStore.REQUIRED_FIELDS));
|
||||
}
|
||||
|
||||
current_conversations = inbox_conversations;
|
||||
current_conversations = inbox_conversations.get(folder.account);
|
||||
|
||||
// Inbox selected, clear new messages if visible
|
||||
clear_new_messages("do_select_folder (inbox)", null);
|
||||
|
|
@ -420,11 +414,11 @@ public class GearyController {
|
|||
set_busy(false);
|
||||
}
|
||||
|
||||
private void on_notification_bubble_invoked(Geary.Email? email) {
|
||||
if (email == null || inbox_folder == null)
|
||||
private void on_notification_bubble_invoked(Geary.Folder folder, Geary.Email? email) {
|
||||
if (email == null)
|
||||
return;
|
||||
|
||||
main_window.folder_list.select_path(inbox_folder.get_path());
|
||||
main_window.folder_list.select_folder(folder);
|
||||
Geary.Conversation? conversation = current_conversations.get_conversation_for_email(email.id);
|
||||
if (conversation != null)
|
||||
main_window.conversation_list_view.select_conversation(conversation);
|
||||
|
|
@ -444,10 +438,6 @@ public class GearyController {
|
|||
|
||||
// user activated notification, reset new messages no matter other conditions
|
||||
new_messages_monitor.clear_new_messages();
|
||||
|
||||
// attempt to select Inbox
|
||||
if (inbox_folder != null)
|
||||
main_window.folder_list.select_path(inbox_folder.get_path());
|
||||
}
|
||||
|
||||
private void on_conversation_appended(Geary.Conversation conversation,
|
||||
|
|
@ -527,7 +517,7 @@ public class GearyController {
|
|||
|
||||
// Clear view before we yield, to make sure it happens
|
||||
if (clear_view) {
|
||||
main_window.conversation_viewer.clear(current_folder, account.settings);
|
||||
main_window.conversation_viewer.clear(current_folder, current_account.information);
|
||||
main_window.conversation_viewer.scroll_reset();
|
||||
main_window.conversation_viewer.external_images_info_bar.hide();
|
||||
}
|
||||
|
|
@ -586,18 +576,24 @@ public class GearyController {
|
|||
if (available != null && available.size > 0) {
|
||||
foreach (Geary.Folder folder in available) {
|
||||
main_window.folder_list.add_folder(folder);
|
||||
main_window.main_toolbar.copy_folder_menu.add_folder(folder);
|
||||
main_window.main_toolbar.move_folder_menu.add_folder(folder);
|
||||
if (folder.account == current_account) {
|
||||
if (!main_window.main_toolbar.copy_folder_menu.has_folder(folder))
|
||||
main_window.main_toolbar.copy_folder_menu.add_folder(folder);
|
||||
if (!main_window.main_toolbar.move_folder_menu.has_folder(folder))
|
||||
main_window.main_toolbar.move_folder_menu.add_folder(folder);
|
||||
}
|
||||
|
||||
// monitor the Inbox for notifications
|
||||
if (folder.get_special_folder_type() == Geary.SpecialFolderType.INBOX && inbox_folder == null) {
|
||||
inbox_folder = folder;
|
||||
if (folder.get_special_folder_type() == Geary.SpecialFolderType.INBOX &&
|
||||
!inboxes.has_key(folder.account)) {
|
||||
inboxes.set(folder.account, folder);
|
||||
|
||||
// select the inbox and get the show started
|
||||
main_window.folder_list.select_path(folder.get_path());
|
||||
inbox_folder.open_async.begin(false, cancellable_inbox);
|
||||
if (inboxes.size == 1)
|
||||
main_window.folder_list.select_folder(folder);
|
||||
folder.open_async.begin(false, cancellable_inbox);
|
||||
|
||||
new_messages_monitor = new NewMessagesMonitor(inbox_folder, should_notify_new_messages,
|
||||
new_messages_monitor = new NewMessagesMonitor(folder, should_notify_new_messages,
|
||||
cancellable_inbox);
|
||||
|
||||
// Unity launcher count (Ubuntuism)
|
||||
|
|
@ -1037,7 +1033,8 @@ public class GearyController {
|
|||
}
|
||||
|
||||
private void create_compose_window(Geary.ComposedEmail? prefill = null) {
|
||||
Geary.ContactStore? contact_store = account == null ? null : account.get_contact_store();
|
||||
Geary.ContactStore? contact_store = (current_account == null ? null
|
||||
: current_account.get_contact_store());
|
||||
ComposerWindow window = new ComposerWindow(contact_store, prefill);
|
||||
window.set_position(Gtk.WindowPosition.CENTER);
|
||||
window.send.connect(on_send);
|
||||
|
|
@ -1163,7 +1160,8 @@ public class GearyController {
|
|||
}
|
||||
|
||||
private Geary.RFC822.MailboxAddress get_sender() {
|
||||
return account.settings.email;
|
||||
return new Geary.RFC822.MailboxAddress(current_account.information.real_name,
|
||||
current_account.information.email);
|
||||
}
|
||||
|
||||
private Geary.RFC822.MailboxAddresses get_from() {
|
||||
|
|
@ -1171,7 +1169,7 @@ public class GearyController {
|
|||
}
|
||||
|
||||
private void on_send(ComposerWindow composer_window) {
|
||||
account.send_email_async.begin(composer_window.get_composed_email(get_from()));
|
||||
current_account.send_email_async.begin(composer_window.get_composed_email(get_from()));
|
||||
composer_window.destroy();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,11 +10,84 @@ public class FolderList : Sidebar.Tree {
|
|||
{ "application/x-geary-mail", Gtk.TargetFlags.SAME_APP, 0 }
|
||||
};
|
||||
|
||||
private class SpecialFolderBranch : Sidebar.RootOnlyBranch {
|
||||
public SpecialFolderBranch(Geary.Folder folder) {
|
||||
base(new FolderEntry(folder));
|
||||
private class AccountBranch : Sidebar.Branch {
|
||||
public Geary.Account account { get; private set; }
|
||||
public Sidebar.Grouping user_folder_group { get; private set; }
|
||||
public Gee.HashMap<Geary.FolderPath, FolderEntry> folder_entries { get; private set; }
|
||||
|
||||
public AccountBranch(Geary.Account account) {
|
||||
base(new Sidebar.Grouping(account.information.email, new ThemedIcon("emblem-mail")),
|
||||
Sidebar.Branch.Options.NONE, special_folder_comparator);
|
||||
|
||||
assert(folder.get_special_folder_type() != Geary.SpecialFolderType.NONE);
|
||||
this.account = account;
|
||||
user_folder_group = new Sidebar.Grouping("",
|
||||
IconFactory.instance.get_custom_icon("tags", IconFactory.ICON_SIDEBAR));
|
||||
folder_entries = new Gee.HashMap<Geary.FolderPath, FolderEntry>();
|
||||
|
||||
graft(get_root(), user_folder_group, normal_folder_comparator);
|
||||
}
|
||||
|
||||
private static int special_folder_comparator(Sidebar.Entry a, Sidebar.Entry b) {
|
||||
// Our user folder grouping always comes dead last.
|
||||
if (a is Sidebar.Grouping)
|
||||
return 1;
|
||||
if (b is Sidebar.Grouping)
|
||||
return -1;
|
||||
|
||||
assert(a is FolderEntry);
|
||||
assert(b is FolderEntry);
|
||||
|
||||
FolderEntry entry_a = (FolderEntry) a;
|
||||
FolderEntry entry_b = (FolderEntry) b;
|
||||
Geary.SpecialFolderType type_a = entry_a.folder.get_special_folder_type();
|
||||
Geary.SpecialFolderType type_b = entry_b.folder.get_special_folder_type();
|
||||
|
||||
assert(type_a != Geary.SpecialFolderType.NONE);
|
||||
assert(type_b != Geary.SpecialFolderType.NONE);
|
||||
|
||||
// Special folders are ordered by their enum value.
|
||||
return (int) type_a - (int) type_b;
|
||||
}
|
||||
|
||||
private static int normal_folder_comparator(Sidebar.Entry a, Sidebar.Entry b) {
|
||||
// Non-special folders are compared based on name.
|
||||
return a.get_sidebar_name().collate(b.get_sidebar_name());
|
||||
}
|
||||
|
||||
public Sidebar.Entry? get_entry_for_path(Geary.FolderPath folder_path) {
|
||||
return folder_entries.get(folder_path);
|
||||
}
|
||||
|
||||
public void add_folder(Geary.Folder folder) {
|
||||
FolderEntry folder_entry = new FolderEntry(folder);
|
||||
Geary.SpecialFolderType special_folder_type = folder.get_special_folder_type();
|
||||
if (special_folder_type != Geary.SpecialFolderType.NONE) {
|
||||
graft(get_root(), folder_entry);
|
||||
} else if (folder.get_path().get_parent() == null) {
|
||||
// Top-level folders get put in our special user folders group.
|
||||
graft(user_folder_group, folder_entry);
|
||||
} else {
|
||||
Sidebar.Entry? entry = folder_entries.get(folder.get_path().get_parent());
|
||||
if (entry == null) {
|
||||
debug("Could not add folder %s of type %s to folder list", folder.to_string(),
|
||||
special_folder_type.to_string());
|
||||
return;
|
||||
}
|
||||
graft(entry, folder_entry);
|
||||
}
|
||||
|
||||
folder_entries.set(folder.get_path(), folder_entry);
|
||||
}
|
||||
|
||||
public void remove_folder(Geary.Folder folder) {
|
||||
Sidebar.Entry? entry = folder_entries.get(folder.get_path());
|
||||
if(entry == null) {
|
||||
debug("Could not remove folder %s", folder.to_string());
|
||||
return;
|
||||
}
|
||||
|
||||
prune(entry);
|
||||
folder_entries.unset(folder.get_path());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -95,30 +168,19 @@ public class FolderList : Sidebar.Tree {
|
|||
public signal void copy_conversation(Geary.Folder folder);
|
||||
public signal void move_conversation(Geary.Folder folder);
|
||||
|
||||
private Sidebar.Grouping user_folder_group;
|
||||
private Sidebar.Branch user_folder_branch;
|
||||
internal Gee.HashMap<Geary.FolderPath, Sidebar.Entry> entries = new Gee.HashMap<
|
||||
Geary.FolderPath, Sidebar.Entry>(Geary.Hashable.hash_func, Geary.Equalable.equal_func);
|
||||
internal Gee.HashMap<Geary.FolderPath, Sidebar.Branch> branches = new Gee.HashMap<
|
||||
Geary.FolderPath, Sidebar.Branch>(Geary.Hashable.hash_func, Geary.Equalable.equal_func);
|
||||
private Gee.HashMap<Geary.Account, AccountBranch> account_branches
|
||||
= new Gee.HashMap<Geary.Account, AccountBranch>();
|
||||
private int total_accounts = 0;
|
||||
|
||||
public FolderList() {
|
||||
base(new Gtk.TargetEntry[0], Gdk.DragAction.ASK, drop_handler);
|
||||
entry_selected.connect(on_entry_selected);
|
||||
|
||||
reset_user_folder_group();
|
||||
|
||||
// Set self as a drag destination.
|
||||
Gtk.drag_dest_set(this, Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT,
|
||||
TARGET_ENTRY_LIST, Gdk.DragAction.COPY | Gdk.DragAction.MOVE);
|
||||
}
|
||||
|
||||
private static int user_folder_comparator(Sidebar.Entry a, Sidebar.Entry b) {
|
||||
int result = a.get_sidebar_name().collate(b.get_sidebar_name());
|
||||
|
||||
return (result != 0) ? result : strcmp(a.get_sidebar_name(), b.get_sidebar_name());
|
||||
}
|
||||
|
||||
private void drop_handler(Gdk.DragContext context, Sidebar.Entry? entry,
|
||||
Gtk.SelectionData data, uint info, uint time) {
|
||||
}
|
||||
|
|
@ -129,88 +191,49 @@ public class FolderList : Sidebar.Tree {
|
|||
}
|
||||
}
|
||||
|
||||
public void set_user_folders_root_name(string name) {
|
||||
user_folder_group.rename(name);
|
||||
}
|
||||
|
||||
private void reset_user_folder_group() {
|
||||
user_folder_group = new Sidebar.Grouping("",
|
||||
IconFactory.instance.get_custom_icon("tags", IconFactory.ICON_SIDEBAR));
|
||||
user_folder_branch = new Sidebar.Branch(user_folder_group,
|
||||
Sidebar.Branch.Options.STARTUP_OPEN_GROUPING, user_folder_comparator);
|
||||
public void set_user_folders_root_name(Geary.Account account, string name) {
|
||||
if (account_branches.has_key(account))
|
||||
account_branches.get(account).user_folder_group.rename(name);
|
||||
}
|
||||
|
||||
public void add_folder(Geary.Folder folder) {
|
||||
bool added = false;
|
||||
if (!account_branches.has_key(folder.account))
|
||||
account_branches.set(folder.account, new AccountBranch(folder.account));
|
||||
|
||||
if (!has_branch(user_folder_branch))
|
||||
graft(user_folder_branch, int.MAX);
|
||||
AccountBranch account_branch = account_branches.get(folder.account);
|
||||
if (!has_branch(account_branch))
|
||||
graft(account_branch, total_accounts++);
|
||||
|
||||
Geary.SpecialFolderType special_folder_type = folder.get_special_folder_type();
|
||||
if (special_folder_type != Geary.SpecialFolderType.NONE) {
|
||||
SpecialFolderBranch branch = new SpecialFolderBranch(folder);
|
||||
graft(branch, (int) special_folder_type);
|
||||
entries.set(folder.get_path(), branch.get_root());
|
||||
branches.set(folder.get_path(), branch);
|
||||
added = true;
|
||||
} else if (folder.get_path().get_parent() == null) {
|
||||
// Top-level folder.
|
||||
FolderEntry folder_entry = new FolderEntry(folder);
|
||||
user_folder_branch.graft(user_folder_group, folder_entry);
|
||||
entries.set(folder.get_path(), folder_entry);
|
||||
branches.set(folder.get_path(), user_folder_branch);
|
||||
added = true;
|
||||
} else {
|
||||
FolderEntry folder_entry = new FolderEntry(folder);
|
||||
Sidebar.Entry? entry = get_entry_for_folder_path(folder.get_path().get_parent());
|
||||
if (entry != null) {
|
||||
user_folder_branch.graft(entry, folder_entry);
|
||||
entries.set(folder.get_path(), folder_entry);
|
||||
branches.set(folder.get_path(), user_folder_branch);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!added) {
|
||||
debug("Could not add folder %s of type %s to folder list", folder.to_string(),
|
||||
special_folder_type.to_string());
|
||||
}
|
||||
account_branch.add_folder(folder);
|
||||
}
|
||||
|
||||
public void remove_folder(Geary.Folder folder) {
|
||||
Sidebar.Entry? entry = get_entry_for_folder_path(folder.get_path());
|
||||
Sidebar.Branch? branch = get_branch_for_folder_path(folder.get_path());
|
||||
if(entry != null && branch != null) {
|
||||
if (branch is SpecialFolderBranch) {
|
||||
this.prune(branch);
|
||||
} else {
|
||||
branch.prune(entry);
|
||||
}
|
||||
} else {
|
||||
debug(@"Could not remove folder $(folder.get_path())");
|
||||
AccountBranch? account_branch = account_branches.get(folder.account);
|
||||
assert(account_branch != null);
|
||||
assert(has_branch(account_branch));
|
||||
|
||||
account_branch.remove_folder(folder);
|
||||
}
|
||||
|
||||
public void remove_account(Geary.Account account) {
|
||||
AccountBranch? account_branch = account_branches.get(account);
|
||||
if (account_branch != null) {
|
||||
if (has_branch(account_branch))
|
||||
prune(account_branch);
|
||||
account_branches.unset(account);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove_all_branches() {
|
||||
prune_all();
|
||||
entries.clear();
|
||||
reset_user_folder_group();
|
||||
}
|
||||
|
||||
public void select_path(Geary.FolderPath path) {
|
||||
Sidebar.Entry? entry = get_entry_for_folder_path(path);
|
||||
public void select_folder(Geary.Folder folder) {
|
||||
AccountBranch? account_branch = account_branches.get(folder.account);
|
||||
if (account_branch == null)
|
||||
return;
|
||||
|
||||
Sidebar.Entry? entry = account_branch.get_entry_for_path(folder.get_path());
|
||||
if (entry != null)
|
||||
place_cursor(entry, false);
|
||||
}
|
||||
|
||||
private Sidebar.Entry? get_entry_for_folder_path(Geary.FolderPath path) {
|
||||
return entries.get(path);
|
||||
}
|
||||
|
||||
private Sidebar.Branch? get_branch_for_folder_path(Geary.FolderPath path) {
|
||||
return branches.get(path);
|
||||
}
|
||||
|
||||
public override bool drag_motion(Gdk.DragContext context, int x, int y, uint time) {
|
||||
// Run the base version first.
|
||||
bool ret = base.drag_motion(context, x, y, time);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ public class NotificationBubble : GLib.Object {
|
|||
private Geary.Email? email = null;
|
||||
private unowned List<string> caps;
|
||||
|
||||
public signal void invoked(Geary.Email? email);
|
||||
public signal void invoked(Geary.Folder folder, Geary.Email? email);
|
||||
|
||||
public NotificationBubble(NewMessagesMonitor monitor) {
|
||||
this.monitor = monitor;
|
||||
|
|
@ -64,7 +64,7 @@ public class NotificationBubble : GLib.Object {
|
|||
}
|
||||
|
||||
private void on_default_action(Notify.Notification notification, string action) {
|
||||
invoked(email);
|
||||
invoked(monitor.folder, email);
|
||||
GearyApplication.instance.activate(new string[0]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ public class FolderMenu : GtkUtil.ToggleToolbarDropdown {
|
|||
// TODO Merge the move/copy menus and just have a move/copy buttons at bottom of this menu.
|
||||
}
|
||||
|
||||
public bool has_folder(Geary.Folder folder) {
|
||||
return folder_list.contains(folder);
|
||||
}
|
||||
|
||||
public void add_folder(Geary.Folder folder) {
|
||||
folder_list.add(folder);
|
||||
folder_list.sort((CompareFunc) folder_sort);
|
||||
|
|
@ -43,6 +47,14 @@ public class FolderMenu : GtkUtil.ToggleToolbarDropdown {
|
|||
proxy_menu.show_all();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
folder_list.clear();
|
||||
menu.foreach((w) => menu.remove(w));
|
||||
proxy_menu.foreach((w) => proxy_menu.remove(w));
|
||||
menu.show_all();
|
||||
proxy_menu.show_all();
|
||||
}
|
||||
|
||||
private Gtk.MenuItem build_menu_item(Geary.Folder folder) {
|
||||
Gtk.MenuItem menu_item = new Gtk.MenuItem.with_label(folder.get_path().to_string());
|
||||
menu_item.activate.connect(() => {
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public class ConversationViewer : Gtk.Box {
|
|||
private Gtk.Menu? message_menu = null;
|
||||
private Gtk.Menu? attachment_menu = null;
|
||||
private weak Geary.Folder? current_folder = null;
|
||||
private Geary.AccountSettings? current_settings = null;
|
||||
private Geary.AccountInformation? current_account_information = null;
|
||||
|
||||
public ConversationViewer() {
|
||||
Object(orientation: Gtk.Orientation.VERTICAL, spacing: 0);
|
||||
|
|
@ -122,7 +122,7 @@ public class ConversationViewer : Gtk.Box {
|
|||
}
|
||||
|
||||
// Removes all displayed e-mails from the view.
|
||||
public void clear(Geary.Folder? new_folder, Geary.AccountSettings? settings) {
|
||||
public void clear(Geary.Folder? new_folder, Geary.AccountInformation? account_information) {
|
||||
// Remove all messages from DOM.
|
||||
try {
|
||||
foreach (WebKit.DOM.HTMLElement element in email_to_element.values) {
|
||||
|
|
@ -136,7 +136,7 @@ public class ConversationViewer : Gtk.Box {
|
|||
messages.clear();
|
||||
|
||||
current_folder = new_folder;
|
||||
current_settings = settings;
|
||||
current_account_information = account_information;
|
||||
}
|
||||
|
||||
// Converts an email ID into HTML ID used by the <div> for the email.
|
||||
|
|
@ -146,7 +146,7 @@ public class ConversationViewer : Gtk.Box {
|
|||
|
||||
public void show_multiple_selected(uint selected_count) {
|
||||
// Remove any messages and hide the message container, then show the counter.
|
||||
clear(current_folder, current_settings);
|
||||
clear(current_folder, current_account_information);
|
||||
try {
|
||||
web_view.hide_element_by_id(MESSAGE_CONTAINER_ID);
|
||||
web_view.show_element_by_id(SELECTION_COUNTER_ID);
|
||||
|
|
@ -234,8 +234,8 @@ public class ConversationViewer : Gtk.Box {
|
|||
|
||||
// Only include to string if it's not just this account.
|
||||
// TODO: multiple accounts.
|
||||
if (email.to != null && current_settings != null) {
|
||||
if (!(email.to.get_all().size == 1 && email.to.get_all().get(0).address == current_settings.email.address))
|
||||
if (email.to != null && current_account_information != null) {
|
||||
if (!(email.to.get_all().size == 1 && email.to.get_all().get(0).address == current_account_information.email))
|
||||
insert_header_address(ref header, _("To:"), email.to);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public class Geary.DBus.Controller {
|
|||
|
||||
// Open the Inbox folder.
|
||||
Geary.Folder? folder = null;
|
||||
Gee.Collection<Geary.Folder> folders = yield account.list_folders_async(null, null);
|
||||
Gee.Collection<Geary.Folder> folders = account.list_matching_folders(null);
|
||||
foreach(Geary.Folder folder_to_check in folders) {
|
||||
if(folder_to_check.get_special_folder_type() == Geary.SpecialFolderType.INBOX) {
|
||||
folder = folder_to_check;
|
||||
|
|
@ -85,8 +85,7 @@ public class Geary.DBus.Controller {
|
|||
return File.new_for_path(Environment.get_current_dir());
|
||||
}
|
||||
|
||||
private void on_report_problem(Geary.Account.Problem problem, Geary.AccountSettings settings,
|
||||
Error? err) {
|
||||
private void on_report_problem(Geary.Account.Problem problem, Error? err) {
|
||||
debug("Reported problem: %s Error: %s", problem.to_string(), err != null ? err.message : "(N/A)");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
*/
|
||||
|
||||
public abstract class Geary.AbstractAccount : Object, Geary.Account {
|
||||
public Geary.AccountSettings settings { get; protected set; }
|
||||
public Geary.AccountInformation information { get; protected set; }
|
||||
|
||||
private string name;
|
||||
|
||||
public AbstractAccount(string name, AccountSettings settings) {
|
||||
public AbstractAccount(string name, AccountInformation information) {
|
||||
this.name = name;
|
||||
this.settings = settings;
|
||||
this.information = information;
|
||||
}
|
||||
|
||||
protected virtual void notify_folders_available_unavailable(Gee.Collection<Geary.Folder>? available,
|
||||
|
|
@ -36,17 +36,18 @@ public abstract class Geary.AbstractAccount : Object, Geary.Account {
|
|||
email_sent(message);
|
||||
}
|
||||
|
||||
protected virtual void notify_report_problem(Geary.Account.Problem problem,
|
||||
Geary.AccountSettings? settings, Error? err) {
|
||||
report_problem(problem, settings, err);
|
||||
protected virtual void notify_report_problem(Geary.Account.Problem problem, Error? err) {
|
||||
report_problem(problem, err);
|
||||
}
|
||||
|
||||
public abstract async void open_async(Cancellable? cancellable = null) throws Error;
|
||||
|
||||
public abstract async void close_async(Cancellable? cancellable = null) throws Error;
|
||||
|
||||
public abstract async Gee.Collection<Geary.Folder> list_folders_async(Geary.FolderPath? parent,
|
||||
Cancellable? cancellable = null) throws Error;
|
||||
public abstract Gee.Collection<Geary.Folder> list_matching_folders(
|
||||
Geary.FolderPath? parent) throws Error;
|
||||
|
||||
public abstract Gee.Collection<Geary.Folder> list_folders() throws Error;
|
||||
|
||||
public abstract Geary.ContactStore get_contact_store();
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ public abstract class Geary.AbstractFolder : Object, Geary.Folder {
|
|||
Geary.SpecialFolderType new_type) {
|
||||
special_folder_type_changed(old_type, new_type);
|
||||
}
|
||||
|
||||
public abstract Geary.Account account { get; }
|
||||
|
||||
public abstract Geary.FolderPath get_path();
|
||||
|
||||
|
|
|
|||
|
|
@ -96,14 +96,25 @@ public class Geary.AccountInformation : Object {
|
|||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Fetch the passwords for the given services. For each service, if the
|
||||
* password is unset, use get_passwords_async() first; if the password is
|
||||
* set or it's not in the key store, use prompt_passwords_async(). Return
|
||||
* true if all passwords were retrieved from the key store or the user
|
||||
* proceeded normally if/when prompted, false if the user tried to cancel
|
||||
* the prompt.
|
||||
*/
|
||||
public async bool fetch_passwords_async(CredentialsMediator.ServiceFlag services) throws Error {
|
||||
CredentialsMediator.ServiceFlag unset_services =
|
||||
yield get_passwords_async(services);
|
||||
// Only call get_passwords on anything that hasn't been set
|
||||
// (incorrectly) previously.
|
||||
CredentialsMediator.ServiceFlag get_services = 0;
|
||||
if (services.has_imap() && !imap_credentials.is_complete())
|
||||
get_services |= CredentialsMediator.ServiceFlag.IMAP;
|
||||
if (services.has_smtp() && !smtp_credentials.is_complete())
|
||||
get_services |= CredentialsMediator.ServiceFlag.SMTP;
|
||||
|
||||
CredentialsMediator.ServiceFlag unset_services = services;
|
||||
if (get_services != 0)
|
||||
unset_services = yield get_passwords_async(get_services);
|
||||
|
||||
if (unset_services == 0)
|
||||
return true;
|
||||
|
|
@ -117,6 +128,17 @@ public class Geary.AccountInformation : Object {
|
|||
"Geary.Engine instance needs to be open with a valid Geary.CredentialsMediator");
|
||||
}
|
||||
|
||||
private void set_imap_password(string imap_password) {
|
||||
// Don't just update the pass field, because we need imap_credentials
|
||||
// itself to change so callers can bind to its changed signal.
|
||||
imap_credentials = new Credentials(imap_credentials.user, imap_password);
|
||||
}
|
||||
|
||||
private void set_smtp_password(string smtp_password) {
|
||||
// See above. Same argument.
|
||||
smtp_credentials = new Credentials(smtp_credentials.user, smtp_password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use Engine's authentication mediator to retrieve the passwords for the
|
||||
* given services. The passwords will be stored in the appropriate
|
||||
|
|
@ -137,7 +159,7 @@ public class Geary.AccountInformation : Object {
|
|||
CredentialsMediator.Service.IMAP, imap_credentials.user);
|
||||
|
||||
if (imap_password != null)
|
||||
imap_credentials.pass = imap_password;
|
||||
set_imap_password(imap_password);
|
||||
else
|
||||
failed_services |= CredentialsMediator.ServiceFlag.IMAP;
|
||||
}
|
||||
|
|
@ -147,7 +169,7 @@ public class Geary.AccountInformation : Object {
|
|||
CredentialsMediator.Service.SMTP, smtp_credentials.user);
|
||||
|
||||
if (smtp_password != null)
|
||||
smtp_credentials.pass = smtp_password;
|
||||
set_smtp_password(smtp_password);
|
||||
else
|
||||
failed_services |= CredentialsMediator.ServiceFlag.SMTP;
|
||||
}
|
||||
|
|
@ -176,12 +198,12 @@ public class Geary.AccountInformation : Object {
|
|||
return false;
|
||||
|
||||
if (services.has_imap()) {
|
||||
imap_credentials.pass = imap_password;
|
||||
set_imap_password(imap_password);
|
||||
this.imap_remember_password = imap_remember_password;
|
||||
}
|
||||
|
||||
if (services.has_smtp()) {
|
||||
smtp_credentials.pass = smtp_password;
|
||||
set_smtp_password(smtp_password);
|
||||
this.smtp_remember_password = smtp_remember_password;
|
||||
}
|
||||
|
||||
|
|
@ -221,27 +243,6 @@ public class Geary.AccountInformation : Object {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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:
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
/* Copyright 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* AccountSettings is a complement to AccountInformation. AccountInformation stores these settings
|
||||
* as well as defaults and provides validation and persistence functionality. Settings is simply
|
||||
* the values loaded from a backing store, perhaps chosen from defaults, and validated, then filtered
|
||||
* down to a set of working settings for the Account to use. Changes made to AccountInformation
|
||||
* are not reflected here; a new AccountSettings object must be created.
|
||||
*/
|
||||
|
||||
public class Geary.AccountSettings {
|
||||
public RFC822.MailboxAddress email { get; private set; }
|
||||
public string real_name { get; private set; }
|
||||
public Geary.Credentials imap_credentials { get; private set; }
|
||||
public Geary.Credentials smtp_credentials { get; private set; }
|
||||
public Geary.ServiceProvider service_provider { get; private set; }
|
||||
public bool imap_server_pipeline { get; private set; }
|
||||
public Endpoint imap_endpoint { get; private set; }
|
||||
public Endpoint smtp_endpoint { get; private set; }
|
||||
|
||||
internal File settings_dir { get; private set; }
|
||||
|
||||
internal AccountSettings(AccountInformation info) throws EngineError {
|
||||
email = new RFC822.MailboxAddress(info.real_name, info.email);
|
||||
real_name = info.real_name;
|
||||
imap_credentials = info.imap_credentials;
|
||||
smtp_credentials = info.smtp_credentials;
|
||||
service_provider = info.service_provider;
|
||||
imap_server_pipeline = info.imap_server_pipeline;
|
||||
imap_endpoint = info.get_imap_endpoint();
|
||||
smtp_endpoint = info.get_smtp_endpoint();
|
||||
|
||||
settings_dir = info.settings_dir;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ public interface Geary.Account : Object {
|
|||
DATABASE_FAILURE
|
||||
}
|
||||
|
||||
public abstract Geary.AccountSettings settings { get; protected set; }
|
||||
public abstract Geary.AccountInformation information { get; protected set; }
|
||||
|
||||
public signal void opened();
|
||||
|
||||
|
|
@ -21,8 +21,7 @@ public interface Geary.Account : Object {
|
|||
|
||||
public signal void email_sent(Geary.RFC822.Message rfc822);
|
||||
|
||||
public signal void report_problem(Geary.Account.Problem problem, Geary.AccountSettings settings,
|
||||
Error? err);
|
||||
public signal void report_problem(Geary.Account.Problem problem, Error? err);
|
||||
|
||||
/**
|
||||
* Fired when folders become available or unavailable in the account.
|
||||
|
|
@ -57,8 +56,7 @@ public interface Geary.Account : Object {
|
|||
/**
|
||||
* Signal notification method for subclasses to use.
|
||||
*/
|
||||
protected abstract void notify_report_problem(Geary.Account.Problem problem,
|
||||
Geary.AccountSettings? settings, Error? err);
|
||||
protected abstract void notify_report_problem(Geary.Account.Problem problem, Error? err);
|
||||
|
||||
/**
|
||||
* Signal notification method for subclasses to use.
|
||||
|
|
@ -83,18 +81,26 @@ public interface Geary.Account : Object {
|
|||
public abstract async void close_async(Cancellable? cancellable = null) throws Error;
|
||||
|
||||
/**
|
||||
* Lists all the folders found under the parent path unless it's null, in which case it lists
|
||||
* all the root folders. If the parent path cannot be found, EngineError.NOT_FOUND is thrown.
|
||||
* If no folders exist in the root, EngineError.NOT_FOUND may be thrown as well. However,
|
||||
* the caller should be prepared to deal with an empty list being returned instead.
|
||||
* Lists all the currently-available folders found under the parent path
|
||||
* unless it's null, in which case it lists all the root folders. If the
|
||||
* parent path cannot be found, EngineError.NOT_FOUND is thrown. If no
|
||||
* folders exist in the root, EngineError.NOT_FOUND may be thrown as well.
|
||||
* However, the caller should be prepared to deal with an empty list being
|
||||
* returned instead.
|
||||
*
|
||||
* The same Geary.Folder objects (instances) will be returned if the same path is submitted
|
||||
* multiple times. This means that multiple callers may be holding references to the same
|
||||
* Folders. This is important when thinking of opening and closing folders and signal
|
||||
* notifications.
|
||||
*/
|
||||
public abstract async Gee.Collection<Geary.Folder> list_folders_async(Geary.FolderPath? parent,
|
||||
Cancellable? cancellable = null) throws Error;
|
||||
public abstract Gee.Collection<Geary.Folder> list_matching_folders(
|
||||
Geary.FolderPath? parent) throws Error;
|
||||
|
||||
/**
|
||||
* Lists all currently-available folders. See caveats under
|
||||
* list_matching_folders().
|
||||
*/
|
||||
public abstract Gee.Collection<Geary.Folder> list_folders() throws Error;
|
||||
|
||||
/**
|
||||
* Gets a perpetually update-to-date collection of autocompletion contacts.
|
||||
|
|
|
|||
|
|
@ -241,27 +241,26 @@ public class Geary.Engine {
|
|||
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);
|
||||
ImapDB.Account local_account = new ImapDB.Account(account_information);
|
||||
Imap.Account remote_account = new Imap.Account(account_information);
|
||||
|
||||
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);
|
||||
account_information, remote_account, local_account);
|
||||
break;
|
||||
|
||||
case ServiceProvider.YAHOO:
|
||||
account = new ImapEngine.YahooAccount("Yahoo account %s".printf(account_information.email),
|
||||
settings, remote_account, local_account);
|
||||
account_information, remote_account, local_account);
|
||||
break;
|
||||
|
||||
case ServiceProvider.OTHER:
|
||||
account = new ImapEngine.OtherAccount("Other account %s".printf(account_information.email),
|
||||
settings, remote_account, local_account);
|
||||
account_information, remote_account, local_account);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ public interface Geary.Folder : Object {
|
|||
}
|
||||
}
|
||||
|
||||
public abstract Geary.Account account { get; }
|
||||
|
||||
/**
|
||||
* This is fired when the Folder is successfully opened by a caller. It will only fire once
|
||||
* until the Folder is closed, with the OpenState indicating what has been opened and the count
|
||||
|
|
|
|||
|
|
@ -19,17 +19,17 @@ private class Geary.ImapDB.Account : Object {
|
|||
public SmtpOutboxFolder? outbox { get; private set; default = null; }
|
||||
|
||||
private string name;
|
||||
private AccountSettings settings;
|
||||
private AccountInformation account_information;
|
||||
private ImapDB.Database? db = null;
|
||||
private Gee.HashMap<Geary.FolderPath, FolderReference> folder_refs =
|
||||
new Gee.HashMap<Geary.FolderPath, FolderReference>(Hashable.hash_func, Equalable.equal_func);
|
||||
public ContactStore contact_store { get; private set; }
|
||||
|
||||
public Account(Geary.AccountSettings settings) {
|
||||
this.settings = settings;
|
||||
public Account(Geary.AccountInformation account_information) {
|
||||
this.account_information = account_information;
|
||||
contact_store = new ContactStore();
|
||||
|
||||
name = "IMAP database account for %s".printf(settings.imap_credentials.user);
|
||||
name = "IMAP database account for %s".printf(account_information.imap_credentials.user);
|
||||
}
|
||||
|
||||
private void check_open() throws Error {
|
||||
|
|
@ -42,7 +42,7 @@ private class Geary.ImapDB.Account : Object {
|
|||
if (db != null)
|
||||
throw new EngineError.ALREADY_OPEN("IMAP database already open");
|
||||
|
||||
db = new ImapDB.Database(user_data_dir, schema_dir, settings.email.address);
|
||||
db = new ImapDB.Database(user_data_dir, schema_dir, account_information.email);
|
||||
|
||||
try {
|
||||
db.open(Db.DatabaseFlags.CREATE_DIRECTORY | Db.DatabaseFlags.CREATE_FILE, null,
|
||||
|
|
@ -56,10 +56,21 @@ private class Geary.ImapDB.Account : Object {
|
|||
throw err;
|
||||
}
|
||||
|
||||
Geary.Account account;
|
||||
try {
|
||||
account = Geary.Engine.instance.get_account_instance(account_information);
|
||||
} catch (Error e) {
|
||||
// If they're opening an account, the engine should already be
|
||||
// open, and there should be no reason for this to fail. Thus, if
|
||||
// we get here, it's a programmer error.
|
||||
|
||||
error("Error finding account from its information: %s", e.message);
|
||||
}
|
||||
|
||||
initialize_contacts(cancellable);
|
||||
|
||||
// ImapDB.Account holds the Outbox, which is tied to the database it maintains
|
||||
outbox = new SmtpOutboxFolder(db, settings);
|
||||
outbox = new SmtpOutboxFolder(db, account);
|
||||
|
||||
// Need to clear duplicate folders due to old bug that caused multiple folders to be
|
||||
// created in the database ... benign due to other logic, but want to prevent this from
|
||||
|
|
@ -370,7 +381,7 @@ private class Geary.ImapDB.Account : Object {
|
|||
}
|
||||
|
||||
// create folder
|
||||
folder = new Geary.ImapDB.Folder(db, path, contact_store, settings.email.address, folder_id,
|
||||
folder = new Geary.ImapDB.Folder(db, path, contact_store, account_information.email, folder_id,
|
||||
properties);
|
||||
|
||||
// build a reference to it
|
||||
|
|
|
|||
|
|
@ -32,9 +32,8 @@ private class Geary.SmtpOutboxFolder : Geary.AbstractFolder, Geary.FolderSupport
|
|||
}
|
||||
}
|
||||
|
||||
public signal void report_problem(Geary.Account.Problem problem, Geary.AccountSettings settings,
|
||||
Error? err);
|
||||
|
||||
public signal void report_problem(Geary.Account.Problem problem, Error? err);
|
||||
|
||||
// Min and max times between attempting to re-send after a connection failure.
|
||||
private const uint MIN_SEND_RETRY_INTERVAL_SEC = 4;
|
||||
private const uint MAX_SEND_RETRY_INTERVAL_SEC = 64;
|
||||
|
|
@ -42,18 +41,20 @@ private class Geary.SmtpOutboxFolder : Geary.AbstractFolder, Geary.FolderSupport
|
|||
private static FolderRoot? path = null;
|
||||
|
||||
private ImapDB.Database db;
|
||||
private AccountSettings settings;
|
||||
private weak Account _account;
|
||||
private Geary.Smtp.ClientSession smtp;
|
||||
private bool opened = false;
|
||||
private NonblockingMailbox<OutboxRow> outbox_queue = new NonblockingMailbox<OutboxRow>();
|
||||
|
||||
public override Account account { get { return _account; } }
|
||||
|
||||
// Requires the Database from the get-go because it runs a background task that access it
|
||||
// whether open or not
|
||||
public SmtpOutboxFolder(ImapDB.Database db, AccountSettings settings) {
|
||||
public SmtpOutboxFolder(ImapDB.Database db, Account account) {
|
||||
this.db = db;
|
||||
this.settings = settings;
|
||||
_account = account;
|
||||
|
||||
smtp = new Geary.Smtp.ClientSession(settings.smtp_endpoint);
|
||||
smtp = new Geary.Smtp.ClientSession(_account.information.get_smtp_endpoint());
|
||||
|
||||
do_postman_async.begin();
|
||||
}
|
||||
|
|
@ -127,15 +128,26 @@ private class Geary.SmtpOutboxFolder : Geary.AbstractFolder, Geary.FolderSupport
|
|||
} catch (Error send_err) {
|
||||
debug("Outbox postman send error, retrying: %s", send_err.message);
|
||||
|
||||
if (send_err is SmtpError.AUTHENTICATION_FAILED)
|
||||
report_problem(Geary.Account.Problem.SEND_EMAIL_LOGIN_FAILED, settings, send_err);
|
||||
|
||||
try {
|
||||
outbox_queue.send(row);
|
||||
} catch (Error send_err) {
|
||||
debug("Outbox postman: Unable to re-enqueue message, dropping on floor: %s", send_err.message);
|
||||
}
|
||||
|
||||
|
||||
if (send_err is SmtpError.AUTHENTICATION_FAILED) {
|
||||
bool report = true;
|
||||
try {
|
||||
if (yield _account.information.fetch_passwords_async(
|
||||
CredentialsMediator.ServiceFlag.SMTP))
|
||||
report = false;
|
||||
} catch (Error e) {
|
||||
debug("Error prompting for IMAP password: %s", e.message);
|
||||
}
|
||||
|
||||
if (report)
|
||||
report_problem(Geary.Account.Problem.SEND_EMAIL_LOGIN_FAILED, send_err);
|
||||
}
|
||||
|
||||
// Take a brief nap before continuing to allow connection problems to resolve.
|
||||
yield Geary.Scheduler.sleep_async(send_retry_seconds);
|
||||
send_retry_seconds *= 2;
|
||||
|
|
@ -499,7 +511,7 @@ private class Geary.SmtpOutboxFolder : Geary.AbstractFolder, Geary.FolderSupport
|
|||
Error? smtp_err = null;
|
||||
|
||||
try {
|
||||
yield smtp.login_async(settings.smtp_credentials, cancellable);
|
||||
yield smtp.login_async(_account.information.smtp_credentials, cancellable);
|
||||
} catch (Error login_err) {
|
||||
debug("SMTP login error: %s", login_err.message);
|
||||
smtp_err = login_err;
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@ private class Geary.ImapEngine.GmailAccount : Geary.ImapEngine.GenericAccount {
|
|||
|
||||
private static Gee.HashMap<Geary.FolderPath, Geary.SpecialFolderType>? path_type_map = null;
|
||||
|
||||
public GmailAccount(string name, Geary.AccountSettings settings, Imap.Account remote,
|
||||
ImapDB.Account local) {
|
||||
base (name, settings, remote, local);
|
||||
public GmailAccount(string name, Geary.AccountInformation account_information,
|
||||
Imap.Account remote, ImapDB.Account local) {
|
||||
base (name, account_information, remote, local);
|
||||
|
||||
if (path_type_map == null) {
|
||||
path_type_map = new Gee.HashMap<Geary.FolderPath, Geary.SpecialFolderType>(
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
|
|||
private Gee.HashMap<FolderPath, Folder> local_only = new Gee.HashMap<FolderPath, Folder>(
|
||||
Hashable.hash_func, Equalable.equal_func);
|
||||
|
||||
public GenericAccount(string name, Geary.AccountSettings settings, Imap.Account remote,
|
||||
public GenericAccount(string name, Geary.AccountInformation information, Imap.Account remote,
|
||||
ImapDB.Account local) {
|
||||
base (name, settings);
|
||||
base (name, information);
|
||||
|
||||
this.remote = remote;
|
||||
this.local = local;
|
||||
|
|
@ -71,7 +71,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
|
|||
if (open)
|
||||
throw new EngineError.ALREADY_OPEN("Account %s already opened", to_string());
|
||||
|
||||
yield local.open_async(settings.settings_dir, Engine.instance.resource_dir.get_child("sql"), cancellable);
|
||||
yield local.open_async(information.settings_dir, Engine.instance.resource_dir.get_child("sql"), cancellable);
|
||||
|
||||
// outbox is now available
|
||||
local.outbox.report_problem.connect(notify_report_problem);
|
||||
|
|
@ -170,8 +170,10 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
|
|||
return return_folders;
|
||||
}
|
||||
|
||||
public override async Gee.Collection<Geary.Folder> list_folders_async(Geary.FolderPath? parent,
|
||||
Cancellable? cancellable = null) throws Error {
|
||||
public override Gee.Collection<Geary.Folder> list_matching_folders(
|
||||
Geary.FolderPath? parent) throws Error {
|
||||
check_open();
|
||||
|
||||
Gee.ArrayList<Geary.Folder> matches = new Gee.ArrayList<Geary.Folder>();
|
||||
|
||||
foreach(FolderPath path in existing_folders.keys) {
|
||||
|
|
@ -184,6 +186,11 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
|
|||
return matches;
|
||||
}
|
||||
|
||||
public override Gee.Collection<Geary.Folder> list_folders() throws Error {
|
||||
check_open();
|
||||
return existing_folders.values;
|
||||
}
|
||||
|
||||
private async Gee.Collection<Geary.Folder> enumerate_folders_async(Geary.FolderPath? parent,
|
||||
Cancellable? cancellable = null) throws Error {
|
||||
check_open();
|
||||
|
|
@ -384,7 +391,18 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
|
|||
}
|
||||
|
||||
private void on_login_failed(Geary.Credentials? credentials) {
|
||||
notify_report_problem(Geary.Account.Problem.RECV_EMAIL_LOGIN_FAILED, settings, null);
|
||||
do_login_failed_async.begin(credentials);
|
||||
}
|
||||
|
||||
private async void do_login_failed_async(Geary.Credentials? credentials) {
|
||||
try {
|
||||
if (yield information.fetch_passwords_async(CredentialsMediator.ServiceFlag.IMAP))
|
||||
return;
|
||||
} catch (Error e) {
|
||||
debug("Error prompting for IMAP password: %s", e.message);
|
||||
}
|
||||
|
||||
notify_report_problem(Geary.Account.Problem.RECV_EMAIL_LOGIN_FAILED, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,11 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
|
|||
private const Geary.Email.Field NORMALIZATION_FIELDS =
|
||||
Geary.Email.Field.PROPERTIES | Geary.Email.Field.FLAGS | ImapDB.Folder.REQUIRED_FOR_DUPLICATE_DETECTION;
|
||||
|
||||
private weak GenericAccount _account;
|
||||
public override Account account { get { return _account; } }
|
||||
internal ImapDB.Folder local_folder { get; protected set; }
|
||||
internal Imap.Folder? remote_folder { get; protected set; default = null; }
|
||||
|
||||
private weak GenericAccount account;
|
||||
private Imap.Account remote;
|
||||
private ImapDB.Account local;
|
||||
private EmailFlagWatcher email_flag_watcher;
|
||||
|
|
@ -28,7 +29,7 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
|
|||
|
||||
public GenericFolder(GenericAccount account, Imap.Account remote, ImapDB.Account local,
|
||||
ImapDB.Folder local_folder, SpecialFolderType special_folder_type) {
|
||||
this.account = account;
|
||||
_account = account;
|
||||
this.remote = remote;
|
||||
this.local = local;
|
||||
this.local_folder = local_folder;
|
||||
|
|
@ -74,7 +75,7 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
|
|||
properties = remote_folder.get_properties();
|
||||
|
||||
if (properties == null)
|
||||
properties = account.get_properties_for_folder(local_folder.get_path());
|
||||
properties = _account.get_properties_for_folder(local_folder.get_path());
|
||||
|
||||
if (properties == null)
|
||||
properties = local_folder.get_properties();
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
*/
|
||||
|
||||
private class Geary.ImapEngine.OtherAccount : Geary.ImapEngine.GenericAccount {
|
||||
public OtherAccount(string name, AccountSettings settings, Imap.Account remote,
|
||||
ImapDB.Account local) {
|
||||
base (name, settings, remote, local);
|
||||
public OtherAccount(string name, AccountInformation account_information,
|
||||
Imap.Account remote, ImapDB.Account local) {
|
||||
base (name, account_information, remote, local);
|
||||
}
|
||||
|
||||
protected override GenericFolder new_folder(Geary.FolderPath path, Imap.Account remote_account,
|
||||
|
|
|
|||
|
|
@ -33,9 +33,9 @@ private class Geary.ImapEngine.YahooAccount : Geary.ImapEngine.GenericAccount {
|
|||
|
||||
private static Gee.HashMap<Geary.FolderPath, Geary.SpecialFolderType>? special_map = null;
|
||||
|
||||
public YahooAccount(string name, AccountSettings settings, Imap.Account remote,
|
||||
ImapDB.Account local) {
|
||||
base (name, settings, remote, local);
|
||||
public YahooAccount(string name, AccountInformation account_information,
|
||||
Imap.Account remote, ImapDB.Account local) {
|
||||
base (name, account_information, remote, local);
|
||||
|
||||
if (special_map == null) {
|
||||
special_map = new Gee.HashMap<Geary.FolderPath, Geary.SpecialFolderType>(
|
||||
|
|
|
|||
|
|
@ -30,17 +30,17 @@ private class Geary.Imap.Account : Object {
|
|||
}
|
||||
|
||||
private string name;
|
||||
private AccountSettings settings;
|
||||
private AccountInformation account_information;
|
||||
private ClientSessionManager session_mgr;
|
||||
private Gee.HashMap<string, string?> delims = new Gee.HashMap<string, string?>();
|
||||
|
||||
public signal void login_failed(Geary.Credentials cred);
|
||||
|
||||
public Account(Geary.AccountSettings settings) {
|
||||
name = "IMAP Account for %s".printf(settings.imap_credentials.to_string());
|
||||
this.settings = settings;
|
||||
public Account(Geary.AccountInformation account_information) {
|
||||
name = "IMAP Account for %s".printf(account_information.imap_credentials.to_string());
|
||||
this.account_information = account_information;
|
||||
|
||||
session_mgr = new ClientSessionManager(settings);
|
||||
session_mgr = new ClientSessionManager(account_information);
|
||||
session_mgr.login_failed.connect(on_login_failed);
|
||||
}
|
||||
|
||||
|
|
@ -185,7 +185,7 @@ private class Geary.Imap.Account : Object {
|
|||
}
|
||||
|
||||
private void on_login_failed() {
|
||||
login_failed(settings.imap_credentials);
|
||||
login_failed(account_information.imap_credentials);
|
||||
}
|
||||
|
||||
public string to_string() {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
public class Geary.Imap.ClientSessionManager {
|
||||
public const int DEFAULT_MIN_POOL_SIZE = 2;
|
||||
|
||||
private AccountSettings settings;
|
||||
private AccountInformation account_information;
|
||||
private int min_pool_size;
|
||||
private Gee.HashSet<ClientSession> sessions = new Gee.HashSet<ClientSession>();
|
||||
private Geary.NonblockingMutex sessions_mutex = new Geary.NonblockingMutex();
|
||||
|
|
@ -20,10 +20,18 @@ public class Geary.Imap.ClientSessionManager {
|
|||
|
||||
public signal void login_failed();
|
||||
|
||||
public ClientSessionManager(AccountSettings settings, int min_pool_size = DEFAULT_MIN_POOL_SIZE) {
|
||||
this.settings = settings;
|
||||
public ClientSessionManager(AccountInformation account_information,
|
||||
int min_pool_size = DEFAULT_MIN_POOL_SIZE) {
|
||||
this.account_information = account_information;
|
||||
this.min_pool_size = min_pool_size;
|
||||
|
||||
account_information.notify["imap-credentials"].connect(on_imap_credentials_notified);
|
||||
|
||||
adjust_session_pool.begin();
|
||||
}
|
||||
|
||||
private void on_imap_credentials_notified() {
|
||||
authentication_failed = false;
|
||||
adjust_session_pool.begin();
|
||||
}
|
||||
|
||||
|
|
@ -43,7 +51,8 @@ public class Geary.Imap.ClientSessionManager {
|
|||
try {
|
||||
yield create_new_authorized_session(null);
|
||||
} catch (Error err) {
|
||||
debug("Unable to create authorized session to %s: %s", settings.imap_endpoint.to_string(), err.message);
|
||||
debug("Unable to create authorized session to %s: %s",
|
||||
account_information.get_imap_endpoint().to_string(), err.message);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -222,7 +231,8 @@ public class Geary.Imap.ClientSessionManager {
|
|||
if (authentication_failed)
|
||||
throw new ImapError.UNAUTHENTICATED("Invalid ClientSessionManager credentials");
|
||||
|
||||
ClientSession new_session = new ClientSession(settings.imap_endpoint, settings.imap_server_pipeline);
|
||||
ClientSession new_session = new ClientSession(account_information.get_imap_endpoint(),
|
||||
account_information.imap_server_pipeline);
|
||||
|
||||
// add session to pool before launching all the connect activity so error cases can properly
|
||||
// back it out
|
||||
|
|
@ -240,7 +250,7 @@ public class Geary.Imap.ClientSessionManager {
|
|||
}
|
||||
|
||||
try {
|
||||
yield new_session.initiate_session_async(settings.imap_credentials, cancellable);
|
||||
yield new_session.initiate_session_async(account_information.imap_credentials, cancellable);
|
||||
} catch (Error err) {
|
||||
debug("[%s] Initiate session failure: %s", new_session.to_string(), err.message);
|
||||
|
||||
|
|
@ -365,7 +375,7 @@ public class Geary.Imap.ClientSessionManager {
|
|||
* Use only for debugging and logging.
|
||||
*/
|
||||
public string to_string() {
|
||||
return settings.imap_endpoint.to_string();
|
||||
return account_information.get_imap_endpoint().to_string();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue