geary/src/engine/imap-engine/imap-engine-generic-account.vala

1403 lines
53 KiB
Vala
Raw Normal View History

/*
* Copyright 2016 Software Freedom Conservancy Inc.
* Copyright 2017-2019 Michael Gratton <mike@vee.net>.
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
*/
private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
/** Default IMAP session pool size. */
private const int IMAP_MIN_POOL_SIZE = 2;
// This is high since it's an expensive operation, and we'll go
// looking changes caused by local operations as they happen, so
// we don't need to double check.
private const int REFRESH_FOLDER_LIST_SEC = 15 * 60;
/** Minimum interval between account storage cleanup work */
private const uint APP_BACKGROUNDED_CLEANUP_WORK_INTERVAL_MINUTES = 60 * 24;
private const Geary.SpecialFolderType[] SUPPORTED_SPECIAL_FOLDERS = {
Geary.SpecialFolderType.DRAFTS,
Geary.SpecialFolderType.SENT,
Geary.SpecialFolderType.SPAM,
Geary.SpecialFolderType.TRASH,
Geary.SpecialFolderType.ARCHIVE,
};
private static GLib.VariantType email_id_type = new GLib.VariantType(
EmailIdentifier.BASE_VARIANT_TYPE
);
/** Service for incoming IMAP connections. */
public Imap.ClientService imap { get; private set; }
/** Service for outgoing SMTP connections. */
public Smtp.ClientService smtp { get; private set; }
/** Local database for the account. */
public ImapDB.Account local { get; private set; }
2020-01-09 14:08:46 +01:00
public signal void old_messages_background_cleanup_request(GLib.Cancellable? cancellable);
Remove SQLHeavy: Closes #5034 It is done. Initial implementation of the new database subsystem These pieces represent the foundation for ticket #5034 Expanded transactions, added VersionedDatabase Further expansions of the async code. Moved async pool logic into Database, where it realistically belongs. Further improvements. Introduced geary-db-test. Added SQL create and update files for Geary.Db version-001 to version-003 are exact copies of the SQLHeavy scripts to ensure no slight changes when migrating. version-004 upgrades the database to remove the ImapFolderPropertiesTable and ImapMessagePropertiesTable, now that the database code is pure IMAP. When we support other messaging systems (such as POP3), those subsystems will need to code their own database layers OR rely on the IMAP schema and simply ignore the IMAP-specific fields. ImapDB.Account fleshed out ImapDB.Folder is commented out, however. Need to port next. ImapDB.Folder fleshed out MessageTable, MessageLocationTable, and AttachementTable are now handled inside ImapDB.Folder. chmod -x imap-db-database.vala OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties Moved SmtpOutboxFolderRoot into its own source file SmtpOutboxFolder ported to new database code Move Engine implementations to ImapDB. Integration and cleanup of new database code with main source This commit performs the final integration steps to move Geary completely over to the new database model. This also cleans out the old SQLHeavy-based code and fixes a handful of small bugs that were detected during basic test runs. Moved Outbox to ImapDB As the Outbox is tied to the database that ImapDB runs, move the Outbox code into that folder. Outbox fixes and better parameter checking Bumped Database thread pool count and made them exclusive My reasoning is that there may be a need for a lot of threads at once (when a big batch of commands comes in, especially at startup). If performance looks ok, we might consider relaxing this later.
2012-06-14 14:47:53 -07:00
private bool open = false;
private Cancellable? open_cancellable = null;
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
private Nonblocking.Semaphore? remote_ready_lock = null;
private Gee.Map<FolderPath,MinimalFolder> folder_map =
new Gee.HashMap<FolderPath,MinimalFolder>();
private AccountProcessor? processor;
private AccountSynchronizer sync;
private TimeoutManager refresh_folder_timer;
private Gee.Map<Geary.SpecialFolderType, Gee.List<string>> special_search_names =
new Gee.HashMap<Geary.SpecialFolderType, Gee.List<string>>();
protected GenericAccount(AccountInformation config,
ImapDB.Account local,
Endpoint incoming_remote,
Endpoint outgoing_remote) {
Imap.ClientService imap = new Imap.ClientService(
config,
config.incoming,
incoming_remote
);
Smtp.ClientService smtp = new Smtp.ClientService(
config,
config.outgoing,
outgoing_remote
);
base(config, imap, smtp);
this.local = local;
this.contact_store = new ContactStoreImpl(local.db);
imap.min_pool_size = IMAP_MIN_POOL_SIZE;
imap.notify["current-status"].connect(
on_imap_status_notify
);
imap.set_logging_parent(this);
this.imap = imap;
smtp.outbox = new Outbox.Folder(this, local_folder_root, local);
smtp.report_problem.connect(notify_report_problem);
smtp.set_logging_parent(this);
this.smtp = smtp;
this.sync = new AccountSynchronizer(this);
this.refresh_folder_timer = new TimeoutManager.seconds(
REFRESH_FOLDER_LIST_SEC,
() => { this.update_remote_folders(); }
);
this.background_progress = new ReentrantProgressMonitor(ACTIVITY);
this.db_upgrade_monitor = local.upgrade_monitor;
this.db_vacuum_monitor = local.vacuum_monitor;
compile_special_search_names();
}
/** {@inheritDoc} */
public override async void open_async(Cancellable? cancellable = null) throws Error {
Remove SQLHeavy: Closes #5034 It is done. Initial implementation of the new database subsystem These pieces represent the foundation for ticket #5034 Expanded transactions, added VersionedDatabase Further expansions of the async code. Moved async pool logic into Database, where it realistically belongs. Further improvements. Introduced geary-db-test. Added SQL create and update files for Geary.Db version-001 to version-003 are exact copies of the SQLHeavy scripts to ensure no slight changes when migrating. version-004 upgrades the database to remove the ImapFolderPropertiesTable and ImapMessagePropertiesTable, now that the database code is pure IMAP. When we support other messaging systems (such as POP3), those subsystems will need to code their own database layers OR rely on the IMAP schema and simply ignore the IMAP-specific fields. ImapDB.Account fleshed out ImapDB.Folder is commented out, however. Need to port next. ImapDB.Folder fleshed out MessageTable, MessageLocationTable, and AttachementTable are now handled inside ImapDB.Folder. chmod -x imap-db-database.vala OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties Moved SmtpOutboxFolderRoot into its own source file SmtpOutboxFolder ported to new database code Move Engine implementations to ImapDB. Integration and cleanup of new database code with main source This commit performs the final integration steps to move Geary completely over to the new database model. This also cleans out the old SQLHeavy-based code and fixes a handful of small bugs that were detected during basic test runs. Moved Outbox to ImapDB As the Outbox is tied to the database that ImapDB runs, move the Outbox code into that folder. Outbox fixes and better parameter checking Bumped Database thread pool count and made them exclusive My reasoning is that there may be a need for a lot of threads at once (when a big batch of commands comes in, especially at startup). If performance looks ok, we might consider relaxing this later.
2012-06-14 14:47:53 -07:00
if (open)
throw new EngineError.ALREADY_OPEN("Account %s already opened", to_string());
this.background_progress.notify_start();
try {
yield internal_open_async(cancellable);
} finally {
this.background_progress.notify_finish();
}
}
private async void internal_open_async(Cancellable? cancellable) throws Error {
this.open_cancellable = new Cancellable();
this.remote_ready_lock = new Nonblocking.Semaphore(this.open_cancellable);
this.processor = new AccountProcessor(this.background_progress);
this.processor.operation_error.connect(on_operation_error);
this.processor.set_logging_parent(this);
try {
yield this.local.open_async(cancellable);
} catch (Error err) {
// convert database-open errors
if (err is DatabaseError.CORRUPT)
throw new EngineError.CORRUPT("%s", err.message);
else if (err is DatabaseError.ACCESS)
throw new EngineError.PERMISSIONS("%s", err.message);
else if (err is DatabaseError.SCHEMA_VERSION)
throw new EngineError.VERSION("%s", err.message);
else
throw err;
}
this.last_storage_cleanup = yield this.local.fetch_last_cleanup_async(cancellable);
this.last_storage_cleanup_changed.connect ((dt) => {
this.local.set_last_cleanup_async.begin(dt, cancellable);
});
this.open = true;
notify_opened();
this.queue_operation(
new LoadFolders(this, this.local, get_supported_special_folders())
);
// Start the mail services. Start incoming directly, but queue
// outgoing so local folders can be loaded first in case
// queued mail gets sent and needs to get saved somewhere.
yield this.imap.start(cancellable);
this.queue_operation(new StartPostie(this));
// Kick off a background update of the search table.
//
// XXX since this hammers the database, this is an example of
// an operation for which we need an engine-wide operation
// queue, not just an account-wide queue.
this.queue_operation(new PopulateSearchTable(this));
}
public override async void close_async(Cancellable? cancellable = null) throws Error {
Remove SQLHeavy: Closes #5034 It is done. Initial implementation of the new database subsystem These pieces represent the foundation for ticket #5034 Expanded transactions, added VersionedDatabase Further expansions of the async code. Moved async pool logic into Database, where it realistically belongs. Further improvements. Introduced geary-db-test. Added SQL create and update files for Geary.Db version-001 to version-003 are exact copies of the SQLHeavy scripts to ensure no slight changes when migrating. version-004 upgrades the database to remove the ImapFolderPropertiesTable and ImapMessagePropertiesTable, now that the database code is pure IMAP. When we support other messaging systems (such as POP3), those subsystems will need to code their own database layers OR rely on the IMAP schema and simply ignore the IMAP-specific fields. ImapDB.Account fleshed out ImapDB.Folder is commented out, however. Need to port next. ImapDB.Folder fleshed out MessageTable, MessageLocationTable, and AttachementTable are now handled inside ImapDB.Folder. chmod -x imap-db-database.vala OutboxEmailIdentifier/Properties -> SmtpOutboxEmailIdentifier/Properties Moved SmtpOutboxFolderRoot into its own source file SmtpOutboxFolder ported to new database code Move Engine implementations to ImapDB. Integration and cleanup of new database code with main source This commit performs the final integration steps to move Geary completely over to the new database model. This also cleans out the old SQLHeavy-based code and fixes a handful of small bugs that were detected during basic test runs. Moved Outbox to ImapDB As the Outbox is tied to the database that ImapDB runs, move the Outbox code into that folder. Outbox fixes and better parameter checking Bumped Database thread pool count and made them exclusive My reasoning is that there may be a need for a lot of threads at once (when a big batch of commands comes in, especially at startup). If performance looks ok, we might consider relaxing this later.
2012-06-14 14:47:53 -07:00
if (!open)
return;
// Stop attempting to send any outgoing messages
try {
yield this.smtp.stop();
} catch (Error err) {
debug("Error stopping SMTP service: %s", err.message);
}
// Halt internal tasks early so they stop using local and
// remote connections.
this.refresh_folder_timer.reset();
this.open_cancellable.cancel();
this.processor.stop();
2019-03-17 16:04:07 +11:00
// Block obtaining and reusing IMAP connections. This *must*
// happen after internal tasks above are cancelled otherwise
// they may block while waiting/using a remote session.
this.imap.discard_returned_sessions = true;
this.remote_ready_lock.reset();
// Close folders and ensure they do in fact close
Gee.BidirSortedSet<Folder> remotes = sort_by_path(this.folder_map.values);
this.folder_map.clear();
notify_folders_available_unavailable(null, remotes);
foreach (Geary.Folder folder in remotes) {
debug("Waiting for remote to close: %s", folder.to_string());
yield folder.wait_for_close_async();
}
// Close IMAP service manager now that folders are closed
try {
yield this.imap.stop();
} catch (Error err) {
debug("Error stopping IMAP service: %s", err.message);
}
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
this.remote_ready_lock = null;
// Close local infrastructure
try {
yield local.close_async(cancellable);
} finally {
this.open = false;
notify_closed();
}
}
/** {@inheritDoc} */
public override bool is_open() {
return open;
}
public override async void rebuild_async(GLib.Cancellable? cancellable = null)
throws GLib.Error {
if (this.open) {
throw new EngineError.ALREADY_OPEN(
"Account cannot be open during rebuild"
);
}
message("Rebuilding account local data");
yield this.local.delete_all_data(cancellable);
message("Rebuild complete");
}
/**
* Queues an operation for execution by this account.
*
* The operation will added to the account's {@link
* AccountProcessor} and executed asynchronously by that when it
* reaches the front.
*/
public void queue_operation(AccountOperation op)
throws EngineError {
check_open();
debug("Enqueuing operation: %s", op.to_string());
this.processor.enqueue(op);
}
/**
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
* Claims a new IMAP account session from the pool.
*
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
* A new IMAP client session will be retrieved from the pool,
* connecting if needed, and used for a new account session. This
* call will wait until the pool is ready to provide sessions. The
* session must be returned via {@link release_account_session}
* after use.
*
* The account must have been opened before calling this method.
*/
public async Imap.AccountSession claim_account_session(Cancellable? cancellable = null)
throws Error {
check_open();
debug("Acquiring account session");
yield this.remote_ready_lock.wait_async(cancellable);
var client = yield this.imap.claim_authorized_session_async(cancellable);
var session = new Imap.AccountSession(this.local.imap_folder_root, client);
session.set_logging_parent(this.imap);
return session;
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
}
/**
* Returns an IMAP account session to the pool for re-use.
*/
public void release_account_session(Imap.AccountSession session) {
debug("Releasing account session");
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
Imap.ClientSession? old_session = session.close();
if (old_session != null) {
this.imap.release_session_async.begin(
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
old_session,
(obj, res) => {
try {
this.imap.release_session_async.end(res);
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
} catch (Error err) {
debug(
"Error releasing account session: %s", err.message
);
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
}
}
);
}
}
/**
* Claims a new IMAP folder session from the pool.
*
* A new IMAP client session will be retrieved from the pool,
* connecting if needed, and used for a new folder session. This
* call will wait until the pool is ready to provide sessions. The
* session must be returned via {@link release_folder_session}
* after use.
*
* The account must have been opened before calling this method.
*/
public async Imap.FolderSession claim_folder_session(Geary.FolderPath path,
Cancellable cancellable)
throws Error {
check_open();
debug("Acquiring folder session for: %s", path.to_string());
yield this.remote_ready_lock.wait_async(cancellable);
// We manually construct an account session here and then
// reuse it for the folder session so we only need to claim as
// single session from the pool, not two.
Imap.ClientSession? client =
yield this.imap.claim_authorized_session_async(cancellable);
Imap.AccountSession account = new Imap.AccountSession(
this.local.imap_folder_root, client
);
account.set_logging_parent(this.imap);
Imap.Folder? folder = null;
GLib.Error? folder_err = null;
try {
folder = yield account.fetch_folder_async(path, cancellable);
} catch (Error err) {
folder_err = err;
}
account.close();
Imap.FolderSession? folder_session = null;
if (folder_err == null) {
try {
folder_session = yield new Imap.FolderSession(
client, folder, cancellable
);
folder_session.set_logging_parent(this.imap);
} catch (Error err) {
folder_err = err;
}
}
if (folder_err != null) {
try {
yield this.imap.release_session_async(client);
} catch (Error release_err) {
debug("Error releasing folder session: %s", release_err.message);
}
throw folder_err;
}
return folder_session;
}
/**
* Returns an IMAP folder session to the pool for cleanup and re-use.
*/
public async void release_folder_session(Imap.FolderSession session) {
debug("Releasing folder session");
Imap.ClientSession? old_session = session.close();
if (old_session != null) {
try {
yield this.imap.release_session_async(old_session);
} catch (Error err) {
debug("Error releasing %s session: %s",
session.folder.path.to_string(),
err.message);
}
}
}
/** {@inheritDoc} */
public override EmailIdentifier to_email_identifier(GLib.Variant serialised)
throws EngineError.BAD_PARAMETERS {
if (!serialised.is_of_type(GenericAccount.email_id_type)) {
throw new EngineError.BAD_PARAMETERS("Invalid outer serialised type");
}
char type = (char) serialised.get_child_value(0).get_byte();
if (type == 'i')
return new ImapDB.EmailIdentifier.from_variant(serialised);
if (type == 'o')
return new Outbox.EmailIdentifier.from_variant(serialised);
throw new EngineError.BAD_PARAMETERS("Unknown serialised type: %c", type);
}
/** {@inheritDoc} */
public override FolderPath to_folder_path(GLib.Variant serialised)
throws EngineError.BAD_PARAMETERS {
FolderPath? path = null;
try {
path = this.local.imap_folder_root.from_variant(serialised);
} catch (EngineError.BAD_PARAMETERS err) {
path = this.local_folder_root.from_variant(serialised);
}
return path;
}
/** {@inheritDoc} */
public override Folder get_folder(FolderPath path)
throws EngineError.NOT_FOUND {
Folder? folder = this.folder_map.get(path);
if (folder == null) {
throw new EngineError.NOT_FOUND(
"Folder not found: %s", path.to_string()
);
}
return folder;
}
/** {@inheritDoc} */
public override Gee.Collection<Folder> list_folders() {
var all = new Gee.HashSet<Folder>();
all.add_all(this.folder_map.values);
return all;
}
/** {@inheritDoc} */
public override Gee.Collection<Folder> list_matching_folders(FolderPath? parent)
throws EngineError.NOT_FOUND {
return traverse<FolderPath>(folder_map.keys)
.filter(p => {
FolderPath? path_parent = p.parent;
return ((parent == null && path_parent == null) ||
(parent != null && path_parent != null &&
path_parent.equal_to(parent)));
})
.map<Geary.Folder>(p => folder_map.get(p))
.to_array_list();
}
public override async Geary.Folder get_required_special_folder_async(Geary.SpecialFolderType special,
Cancellable? cancellable) throws Error {
if (!(special in get_supported_special_folders())) {
throw new EngineError.BAD_PARAMETERS(
"Invalid special folder type %s passed to get_required_special_folder_async",
special.to_string());
}
check_open();
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
Geary.Folder? folder = get_special_folder(special);
if (folder == null) {
Imap.AccountSession account = yield claim_account_session();
try {
folder = yield ensure_special_folder_async(account, special, cancellable);
} finally {
release_account_session(account);
}
}
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
return folder;
}
private ImapDB.EmailIdentifier check_id(Geary.EmailIdentifier id) throws EngineError {
ImapDB.EmailIdentifier? imapdb_id = id as ImapDB.EmailIdentifier;
if (imapdb_id == null)
throw new EngineError.BAD_PARAMETERS("EmailIdentifier %s not from ImapDB folder", id.to_string());
return imapdb_id;
}
private Gee.Collection<ImapDB.EmailIdentifier> check_ids(Gee.Collection<Geary.EmailIdentifier> ids)
throws EngineError {
foreach (Geary.EmailIdentifier id in ids) {
if (!(id is ImapDB.EmailIdentifier))
throw new EngineError.BAD_PARAMETERS("EmailIdentifier %s not from ImapDB folder", id.to_string());
}
return (Gee.Collection<ImapDB.EmailIdentifier>) ids;
}
/** {@inheritDoc} */
public override async SearchQuery new_search_query(string query,
SearchQuery.Strategy strategy,
GLib.Cancellable? cancellable)
throws GLib.Error {
return yield new ImapDB.SearchQuery(
this, local, query, strategy, cancellable
);
}
public override async Gee.MultiMap<Geary.Email, Geary.FolderPath?>? local_search_message_id_async(
Geary.RFC822.MessageID message_id, Geary.Email.Field requested_fields, bool partial_ok,
Gee.Collection<Geary.FolderPath?>? folder_blacklist, Geary.EmailFlags? flag_blacklist,
Cancellable? cancellable = null) throws Error {
return yield local.search_message_id_async(
message_id, requested_fields, partial_ok, folder_blacklist, flag_blacklist, cancellable);
}
public override async Geary.Email local_fetch_email_async(Geary.EmailIdentifier email_id,
Geary.Email.Field required_fields, Cancellable? cancellable = null) throws Error {
return yield local.fetch_email_async(check_id(email_id), required_fields, cancellable);
}
/** {@inheritDoc} */
public override async Gee.List<Email> list_local_email_async(
Gee.Collection<EmailIdentifier> ids,
Email.Field required_fields,
GLib.Cancellable? cancellable = null
) throws GLib.Error {
return yield local.list_email(
check_ids(ids), required_fields, cancellable
);
}
public override async Gee.Collection<Geary.EmailIdentifier>? local_search_async(Geary.SearchQuery query,
int limit = 100, int offset = 0, Gee.Collection<Geary.FolderPath?>? folder_blacklist = null,
Gee.Collection<Geary.EmailIdentifier>? search_ids = null, Cancellable? cancellable = null) throws Error {
if (offset < 0)
throw new EngineError.BAD_PARAMETERS("Offset must not be negative");
return yield local.search_async(query, limit, offset, folder_blacklist, search_ids, cancellable);
}
public override async Gee.Set<string>? get_search_matches_async(Geary.SearchQuery query,
Gee.Collection<Geary.EmailIdentifier> ids, Cancellable? cancellable = null) throws Error {
return yield local.get_search_matches_async(query, check_ids(ids), cancellable);
}
public override async Gee.MultiMap<EmailIdentifier,FolderPath>?
get_containing_folders_async(Gee.Collection<Geary.EmailIdentifier> ids,
GLib.Cancellable? cancellable)
throws GLib.Error {
Gee.MultiMap<EmailIdentifier,FolderPath> map =
new Gee.HashMultiMap<EmailIdentifier,FolderPath>();
yield this.local.get_containing_folders_async(ids, map, cancellable);
yield this.smtp.outbox.add_to_containing_folders_async(ids, map, cancellable);
return (map.size == 0) ? null : map;
}
/** {@inheritDoc} */
2020-01-09 14:08:46 +01:00
public override async void cleanup_storage(GLib.Cancellable? cancellable) {
2020-01-09 13:07:17 +01:00
debug("Backgrounded storage cleanup check for %s account", this.information.display_name);
DateTime now = new DateTime.now_local();
2020-01-09 13:00:52 +01:00
DateTime? last_cleanup = this.last_storage_cleanup;
if (last_cleanup == null ||
(now.difference(last_cleanup) / TimeSpan.MINUTE > APP_BACKGROUNDED_CLEANUP_WORK_INTERVAL_MINUTES)) {
// Interval check is OK, start by detaching old messages
2020-01-09 13:00:52 +01:00
this.last_storage_cleanup = now;
this.old_messages_background_cleanup_request(cancellable);
} else if (local.db.want_background_vacuum) {
// Vacuum has been flagged as needed, run it
local.db.run_gc.begin(cancellable, false, true, this.imap, this.smtp);
}
}
/**
* Constructs a set of folders and adds them to the account.
*
* This constructs a high-level folder representation for each
* folder, adds them to this account object, fires the appropriate
* signals, then returns them. Both the local and remote folder
* equivalents need to exist beforehand they are not created.
*
* If `are_existing` is true, the folders are assumed to have been
* seen before and the {@link Geary.Account.folders_created} signal is
* not fired.
*/
internal Gee.Collection<Folder> add_folders(Gee.Collection<ImapDB.Folder> db_folders,
bool are_existing) {
Gee.TreeSet<MinimalFolder> built_folders = new Gee.TreeSet<MinimalFolder>(
Account.folder_path_comparator
);
foreach(ImapDB.Folder db_folder in db_folders) {
if (!this.folder_map.has_key(db_folder.get_path())) {
MinimalFolder folder = new_folder(db_folder);
folder.report_problem.connect(notify_report_problem);
built_folders.add(folder);
this.folder_map.set(folder.path, folder);
}
}
if (!built_folders.is_empty) {
notify_folders_available_unavailable(built_folders, null);
if (!are_existing) {
notify_folders_created(built_folders);
}
}
return built_folders;
}
/**
* Fires appropriate signals for a single altered folder.
*
* This is functionally equivalent to {@link update_folders}.
*/
internal void update_folder(Geary.Folder folder) {
Gee.Collection<Geary.Folder> folders =
new Gee.LinkedList<Geary.Folder>();
folders.add(folder);
debug("Folder updated: %s", folder.path.to_string());
notify_folders_contents_altered(folders);
}
/**
* Fires appropriate signals for folders have been altered.
*
* This is functionally equivalent to {@link update_folder}.
*/
internal void update_folders(Gee.Collection<Geary.Folder> folders) {
if (!folders.is_empty) {
notify_folders_contents_altered(sort_by_path(folders));
}
}
/**
* Marks a folder as a specific special folder type.
*/
internal void promote_folders(Gee.Map<Geary.SpecialFolderType,Geary.Folder> specials) {
Gee.Set<Geary.Folder> changed = new Gee.HashSet<Geary.Folder>();
foreach (Geary.SpecialFolderType special in specials.keys) {
MinimalFolder? minimal = specials.get(special) as MinimalFolder;
if (minimal.special_folder_type != special) {
debug("Promoting %s to %s",
minimal.to_string(), special.to_string());
minimal.set_special_folder_type(special);
changed.add(minimal);
MinimalFolder? existing =
get_special_folder(special) as MinimalFolder;
if (existing != null && existing != minimal) {
existing.set_special_folder_type(SpecialFolderType.NONE);
changed.add(existing);
}
}
}
if (!changed.is_empty) {
folders_special_type(changed);
}
}
/**
* Removes a set of folders from the account.
*
* This removes the high-level folder representations from this
* account object, and fires the appropriate signals. Deletion of
* both the local and remote folder equivalents must be handled
* before, then after calling this method.
*
* A collection of folders that was actually removed is returned.
*/
internal Gee.BidirSortedSet<MinimalFolder>
remove_folders(Gee.Collection<Folder> folders) {
Gee.TreeSet<MinimalFolder> removed = new Gee.TreeSet<MinimalFolder>(
Account.folder_path_comparator
);
foreach(Geary.Folder folder in folders) {
MinimalFolder? impl = this.folder_map.get(folder.path);
if (impl != null) {
this.folder_map.unset(folder.path);
removed.add(impl);
}
}
if (!removed.is_empty) {
notify_folders_available_unavailable(null, removed);
notify_folders_deleted(removed);
}
return removed;
}
/**
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
* Locates a special folder, creating it if needed.
*/
internal async Folder
ensure_special_folder_async(Imap.AccountSession remote,
SpecialFolderType type,
GLib.Cancellable? cancellable)
throws GLib.Error {
Folder? special = get_special_folder(type);
if (special == null) {
FolderPath? path = information.get_special_folder_path(type);
if (path != null) {
if (!remote.is_folder_path_valid(path)) {
warning(
"Ignoring bad special folder path '%s' for type %s",
path.to_string(),
type.to_string()
);
path = null;
} else {
path = this.local.imap_folder_root.copy(path);
}
}
if (path == null) {
FolderPath root =
yield remote.get_default_personal_namespace(cancellable);
Gee.List<string> search_names = special_search_names.get(type);
foreach (string search_name in search_names) {
FolderPath search_path = root.get_child(search_name);
foreach (FolderPath test_path in folder_map.keys) {
if (test_path.compare_normalized_ci(search_path) == 0) {
path = search_path;
break;
}
}
if (path != null)
break;
}
if (path == null) {
path = root.get_child(search_names[0]);
}
debug("Guessed folder \'%s\' for special_path %s",
path.to_string(), type.to_string()
);
information.set_special_folder_path(type, path);
}
if (!this.folder_map.has_key(path)) {
debug("Creating \"%s\" to use as special folder %s",
path.to_string(), type.to_string());
GLib.Error? created_err = null;
try {
yield remote.create_folder_async(path, type, cancellable);
} catch (GLib.Error err) {
// Hang on to the error since the folder might exist
// on the remote, so try fetching it anyway.
created_err = err;
}
Imap.Folder? remote_folder = null;
try {
remote_folder = yield remote.fetch_folder_async(
path, cancellable
);
} catch (GLib.Error err) {
// If we couldn't fetch it after also failing to
// create it, it's probably due to the problem
// creating it, so throw that error instead.
if (created_err != null) {
throw created_err;
} else {
throw err;
}
}
ImapDB.Folder local_folder =
yield this.local.clone_folder_async(
remote_folder, cancellable
);
add_folders(
Collection.single(local_folder), created_err != null
);
}
special= this.folder_map.get(path);
promote_folders(
Collection.single_map<SpecialFolderType,Folder>(
type, special
)
);
}
return special;
}
/**
* Constructs a concrete folder implementation.
*
* Subclasses should implement this to return their flavor of a
* MinimalFolder with the appropriate interfaces attached. The
* returned folder should have its SpecialFolderType set using
* either the properties from the local folder or its path.
*
* This won't be called to build the Outbox or search folder, but
* for all others (including Inbox) it will.
*/
protected abstract MinimalFolder new_folder(ImapDB.Folder local_folder);
/** {@inheritDoc} */
protected override void
notify_folders_available_unavailable(Gee.BidirSortedSet<Folder>? available,
Gee.BidirSortedSet<Folder>? unavailable) {
base.notify_folders_available_unavailable(available, unavailable);
if (available != null) {
foreach (Geary.Folder folder in available) {
folder.email_appended.connect(notify_email_appended);
folder.email_inserted.connect(notify_email_inserted);
folder.email_removed.connect(notify_email_removed);
folder.email_locally_removed.connect(notify_email_locally_removed);
folder.email_locally_complete.connect(notify_email_locally_complete);
folder.email_flags_changed.connect(notify_email_flags_changed);
}
}
if (unavailable != null) {
foreach (Geary.Folder folder in unavailable) {
folder.email_appended.disconnect(notify_email_appended);
folder.email_inserted.disconnect(notify_email_inserted);
folder.email_removed.disconnect(notify_email_removed);
folder.email_locally_removed.disconnect(notify_email_locally_removed);
folder.email_locally_complete.disconnect(notify_email_locally_complete);
folder.email_flags_changed.disconnect(notify_email_flags_changed);
}
}
}
/** {@inheritDoc} */
protected override void notify_email_appended(Geary.Folder folder, Gee.Collection<Geary.EmailIdentifier> ids) {
base.notify_email_appended(folder, ids);
schedule_unseen_update(folder);
}
/** {@inheritDoc} */
protected override void notify_email_inserted(Geary.Folder folder, Gee.Collection<Geary.EmailIdentifier> ids) {
base.notify_email_inserted(folder, ids);
schedule_unseen_update(folder);
}
/** {@inheritDoc} */
protected override void notify_email_removed(Geary.Folder folder, Gee.Collection<Geary.EmailIdentifier> ids) {
base.notify_email_removed(folder, ids);
schedule_unseen_update(folder);
}
/** {@inheritDoc} */
protected override void notify_email_locally_removed(Geary.Folder folder, Gee.Collection<Geary.EmailIdentifier> ids) {
base.notify_email_locally_removed(folder, ids);
}
/** {@inheritDoc} */
protected override void notify_email_flags_changed(Geary.Folder folder,
Gee.Map<Geary.EmailIdentifier, Geary.EmailFlags> flag_map) {
base.notify_email_flags_changed(folder, flag_map);
schedule_unseen_update(folder);
}
/**
* Hooks up and queues an {@link UpdateRemoteFolders} operation.
*/
private void update_remote_folders() {
this.refresh_folder_timer.reset();
UpdateRemoteFolders op = new UpdateRemoteFolders(
this,
get_supported_special_folders()
);
op.completed.connect(() => {
this.refresh_folder_timer.start();
});
try {
queue_operation(op);
} catch (Error err) {
// oh well
}
}
/**
* Hooks up and queues an {@link RefreshFolderUnseen} operation.
*/
private void schedule_unseen_update(Geary.Folder folder) {
MinimalFolder? impl = folder as MinimalFolder;
if (impl != null) {
impl.refresh_unseen();
}
}
protected virtual Geary.SpecialFolderType[] get_supported_special_folders() {
return SUPPORTED_SPECIAL_FOLDERS;
}
private void compile_special_search_names() {
/*
* Compiles the list of names used to search for special
* folders when they aren't known in advance and the server
* supports neither SPECIAL-USE not XLIST.
*
* Uses both translated and untranslated names in case the
* server has not localised the folders that match the login
* session's language. Also checks for lower-case versions of
* each.
*/
foreach (Geary.SpecialFolderType type in get_supported_special_folders()) {
Gee.List<string> compiled = new Gee.ArrayList<string>();
foreach (string names in get_special_search_names(type)) {
foreach (string name in names.split("|")) {
name = name.strip();
if (name.length != 0) {
if (!(name in compiled)) {
compiled.add(name);
}
name = name.down();
if (!(name in compiled)) {
compiled.add(name);
}
}
}
}
special_search_names.set(type, compiled);
}
}
private Gee.List<string> get_special_search_names(Geary.SpecialFolderType type) {
Gee.List<string> loc_names = new Gee.ArrayList<string>();
Gee.List<string> unloc_names = new Gee.ArrayList<string>();
switch (type) {
case Geary.SpecialFolderType.DRAFTS:
// List of general possible folder names to match for the
// Draft mailbox. Separate names using a vertical bar and
// put the most common localized name to the front for the
// default. English names do not need to be included.
loc_names.add(_("Drafts | Draft"));
unloc_names.add("Drafts | Draft");
break;
case Geary.SpecialFolderType.SENT:
// List of general possible folder names to match for the
// Sent mailbox. Separate names using a vertical bar and
// put the most common localized name to the front for the
// default. English names do not need to be included.
loc_names.add(_("Sent | Sent Mail | Sent Email | Sent E-Mail"));
unloc_names.add("Sent | Sent Mail | Sent Email | Sent E-Mail");
// The localised name(s) of the Sent folder name as used
// by MS Outlook/Exchange.
loc_names.add(NC_("Outlook localised name", "Sent Items"));
unloc_names.add("Sent Items");
break;
case Geary.SpecialFolderType.SPAM:
// List of general possible folder names to match for the
// Spam mailbox. Separate names using a vertical bar and
// put the most common localized name to the front for the
// default. English names do not need to be included.
loc_names.add(_("Junk | Spam | Junk Mail | Junk Email | Junk E-Mail | Bulk Mail | Bulk Email | Bulk E-Mail"));
unloc_names.add("Junk | Spam | Junk Mail | Junk Email | Junk E-Mail | Bulk Mail | Bulk Email | Bulk E-Mail");
break;
case Geary.SpecialFolderType.TRASH:
// List of general possible folder names to match for the
// Trash mailbox. Separate names using a vertical bar and
// put the most common localized name to the front for the
// default. English names do not need to be included.
loc_names.add(_("Trash | Rubbish | Rubbish Bin"));
unloc_names.add("Trash | Rubbish | Rubbish Bin");
// The localised name(s) of the Trash folder name as used
// by MS Outlook/Exchange.
loc_names.add(NC_("Outlook localised name", "Deleted Items"));
unloc_names.add("Deleted Items");
break;
case Geary.SpecialFolderType.ARCHIVE:
// List of general possible folder names to match for the
// Archive mailbox. Separate names using a vertical bar
// and put the most common localized name to the front for
// the default. English names do not need to be included.
loc_names.add(_("Archive | Archives"));
unloc_names.add("Archive | Archives");
break;
}
loc_names.add_all(unloc_names);
return loc_names;
}
private void check_open() throws EngineError {
if (!open)
throw new EngineError.OPEN_REQUIRED("Account %s not opened", to_string());
}
private void on_operation_error(AccountOperation op, Error error) {
notify_service_problem(this.information.incoming, error);
}
private void on_imap_status_notify() {
if (this.open) {
if (this.imap.current_status == CONNECTED) {
this.remote_ready_lock.blind_notify();
update_remote_folders();
} else {
this.remote_ready_lock.reset();
this.refresh_folder_timer.reset();
}
}
}
}
/**
* Account operation for loading local folders from the database.
*/
internal class Geary.ImapEngine.LoadFolders : AccountOperation {
private weak ImapDB.Account local;
private Geary.SpecialFolderType[] specials;
internal LoadFolders(GenericAccount account,
ImapDB.Account local,
Geary.SpecialFolderType[] specials) {
base(account);
this.local = local;
this.specials = specials;
}
public override async void execute(Cancellable cancellable) throws Error {
GenericAccount generic = (GenericAccount) this.account;
Gee.List<ImapDB.Folder> folders = new Gee.LinkedList<ImapDB.Folder>();
yield enumerate_local_folders_async(
folders, generic.local.imap_folder_root, cancellable
);
generic.add_folders(folders, true);
if (!folders.is_empty) {
// If we have some folders to load, then this isn't the
// first run, and hence the special folders should already
// exist
yield check_special_folders(cancellable);
}
}
private async void enumerate_local_folders_async(Gee.List<ImapDB.Folder> folders,
Geary.FolderPath parent,
Cancellable? cancellable)
throws Error {
Gee.Collection<ImapDB.Folder>? children = null;
try {
children = yield this.local.list_folders_async(parent, cancellable);
} catch (EngineError err) {
// don't pass on NOT_FOUND's, that means we need to go to
// the server for more info
if (!(err is EngineError.NOT_FOUND))
throw err;
}
if (children != null) {
foreach (ImapDB.Folder child in children) {
folders.add(child);
yield enumerate_local_folders_async(
folders, child.get_path(), cancellable
);
}
}
}
private async void check_special_folders(GLib.Cancellable cancellable)
throws GLib.Error {
// Local folders loaded that have the SPECIAL-USE flags set
// will have been promoted already via derived account type's
// new_child overrides or some other means. However for those
// that do not have the flag, check here against the local
// config and promote ASAP.
//
// Can't just use ensure_special_folder_async however since
// that will attempt to create the folders if missing, which
// is bad if offline.
GenericAccount generic = (GenericAccount) this.account;
Gee.Map<Geary.SpecialFolderType,Geary.Folder> added_specials =
new Gee.HashMap<Geary.SpecialFolderType,Geary.Folder>();
foreach (Geary.SpecialFolderType type in this.specials) {
if (generic.get_special_folder(type) == null) {
Geary.FolderPath? path =
generic.information.get_special_folder_path(type);
path = this.local.imap_folder_root.copy(path);
if (path != null) {
try {
Geary.Folder target = generic.get_folder(path);
added_specials.set(type, target);
} catch (Error err) {
debug(
"Previously used special folder %s not loaded: %s",
type.to_string(),
err.message
);
}
}
}
}
generic.promote_folders(added_specials);
}
}
/**
* Account operation for starting the outgoing service.
*/
internal class Geary.ImapEngine.StartPostie : AccountOperation {
internal StartPostie(Account account) {
base(account);
}
public override async void execute(GLib.Cancellable cancellable)
throws GLib.Error {
yield this.account.outgoing.start(cancellable);
}
}
/**
* Account operation for populating the full-text-search table.
*/
internal class Geary.ImapEngine.PopulateSearchTable : AccountOperation {
internal PopulateSearchTable(GenericAccount account) {
base(account);
}
public override async void execute(GLib.Cancellable cancellable)
throws GLib.Error {
yield ((GenericAccount) this.account).local.populate_search_table(
cancellable
);
}
}
/**
* Account operation that updates folders from the remote.
*/
internal class Geary.ImapEngine.UpdateRemoteFolders : AccountOperation {
private weak GenericAccount generic_account;
private Geary.SpecialFolderType[] specials;
internal UpdateRemoteFolders(GenericAccount account,
Geary.SpecialFolderType[] specials) {
base(account);
this.generic_account = account;
this.specials = specials;
}
public override async void execute(Cancellable cancellable) throws Error {
Gee.Map<FolderPath, Geary.Folder> existing_folders =
Geary.traverse<Geary.Folder>(this.account.list_folders())
.to_hash_map<FolderPath>(f => f.path);
Gee.Map<FolderPath, Imap.Folder> remote_folders =
new Gee.HashMap<FolderPath, Imap.Folder>();
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
GenericAccount account = (GenericAccount) this.account;
Imap.AccountSession remote = yield account.claim_account_session(
cancellable
);
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
try {
bool is_suspect = yield enumerate_remote_folders_async(
remote,
remote_folders,
account.local.imap_folder_root,
cancellable
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
);
debug("Existing folders:");
foreach (FolderPath path in existing_folders.keys) {
debug(" - %s (%u)", path.to_string(), path.hash());
}
debug("Remote folders:");
foreach (FolderPath path in remote_folders.keys) {
debug(" - %s (%u)", path.to_string(), path.hash());
}
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
// pair the local and remote folders and make sure
// everything is up-to-date
yield update_folders_async(
remote, existing_folders, remote_folders, is_suspect, cancellable
);
} finally {
account.release_account_session(remote);
}
}
private async bool enumerate_remote_folders_async(Imap.AccountSession remote,
Gee.Map<FolderPath,Imap.Folder> folders,
Geary.FolderPath? parent,
Cancellable? cancellable)
throws Error {
bool results_suspect = false;
Gee.List<Imap.Folder>? children = null;
try {
children = yield remote.fetch_child_folders_async(parent, cancellable);
} catch (Error err) {
// ignore everything but I/O and IMAP errors (cancellation is an IOError)
if (err is IOError || err is ImapError)
throw err;
debug("Ignoring error listing child folders of %s: %s",
(parent != null ? parent.to_string() : "root"), err.message);
results_suspect = true;
}
if (children != null) {
foreach (Imap.Folder child in children) {
FolderPath path = child.path;
folders.set(path, child);
if (child.properties.has_children.is_possible() &&
yield enumerate_remote_folders_async(
remote, folders, path, cancellable)) {
results_suspect = true;
}
}
}
return results_suspect;
}
private async void update_folders_async(Imap.AccountSession remote,
Gee.Map<FolderPath,Geary.Folder> existing_folders,
Gee.Map<FolderPath,Imap.Folder> remote_folders,
bool remote_folders_suspect,
Cancellable? cancellable) {
// update all remote folders properties in the local store and
// active in the system
2013-04-24 12:22:32 -07:00
Gee.HashSet<Geary.FolderPath> altered_paths = new Gee.HashSet<Geary.FolderPath>();
foreach (Imap.Folder remote_folder in remote_folders.values) {
MinimalFolder? minimal_folder = existing_folders.get(remote_folder.path)
as MinimalFolder;
if (minimal_folder == null)
continue;
// only worry about alterations if the remote is openable
2013-04-25 14:47:20 -07:00
if (remote_folder.properties.is_openable.is_possible()) {
ImapDB.Folder local_folder = minimal_folder.local_folder;
if (remote_folder.properties.have_contents_changed(local_folder.get_properties(),
minimal_folder.to_string())) {
altered_paths.add(remote_folder.path);
}
}
// always update, openable or not; have the folder update the UID info the next time
// it's opened
try {
yield minimal_folder.local_folder.update_folder_status(
2019-04-04 20:50:48 +11:00
remote_folder.properties, false, cancellable
);
} catch (Error update_error) {
debug("Unable to update local folder %s with remote properties: %s",
remote_folder.path.to_string(), update_error.message);
}
// set the engine folder's special type (but only promote,
// not demote, since getting the special folder type via
// its properties relies on the optional SPECIAL-USE or
// XLIST extensions) use this iteration to add discovered
// properties to map
if (minimal_folder.special_folder_type == SpecialFolderType.NONE)
minimal_folder.set_special_folder_type(remote_folder.properties.attrs.get_special_folder_type());
}
// If path in remote but not local, need to add it
Gee.ArrayList<Imap.Folder> to_add = Geary.traverse<Imap.Folder>(remote_folders.values)
.filter(f => !existing_folders.has_key(f.path))
.to_array_list();
// Remove if path in local but not remote
Gee.ArrayList<Geary.Folder> to_remove
2016-10-04 00:06:54 +11:00
= Geary.traverse<Gee.Map.Entry<FolderPath,Geary.Folder>>(existing_folders)
.filter(e => !remote_folders.has_key(e.key))
.map<Geary.Folder>(e => (Geary.Folder) e.value)
.to_array_list();
// For folders to add, clone them and their properties
// locally, then add to the account
ImapDB.Account local = ((GenericAccount) this.account).local;
Gee.ArrayList<ImapDB.Folder> to_build = new Gee.ArrayList<ImapDB.Folder>();
foreach (Geary.Imap.Folder remote_folder in to_add) {
try {
to_build.add(
yield local.clone_folder_async(remote_folder, cancellable)
);
} catch (Error err) {
debug("Unable to clone folder %s in local store: %s",
remote_folder.path.to_string(),
err.message);
}
}
this.generic_account.add_folders(to_build, false);
if (remote_folders_suspect) {
debug("Skipping removing folders due to prior errors");
} else {
Gee.BidirSortedSet<MinimalFolder> removed =
this.generic_account.remove_folders(to_remove);
Gee.BidirIterator<MinimalFolder> removed_iterator =
removed.bidir_iterator();
bool has_prev = removed_iterator.last();
while (has_prev) {
MinimalFolder folder = removed_iterator.get();
try {
debug("Locally deleting removed folder %s", folder.to_string());
yield local.delete_folder_async(folder.path, cancellable);
} catch (Error e) {
debug("Unable to locally delete removed folder %s: %s", folder.to_string(), e.message);
}
has_prev = removed_iterator.previous();
}
// Let the remote know as well
remote.folders_removed(
Geary.traverse<Geary.Folder>(removed)
.map<FolderPath>(f => f.path).to_array_list()
);
}
// report all altered folders
if (altered_paths.size > 0) {
Gee.ArrayList<Geary.Folder> altered = new Gee.ArrayList<Geary.Folder>();
foreach (Geary.FolderPath altered_path in altered_paths) {
if (existing_folders.has_key(altered_path))
altered.add(existing_folders.get(altered_path));
else
debug("Unable to report %s altered: no local representation", altered_path.to_string());
}
this.generic_account.update_folders(altered);
}
// Ensure each of the important special folders we need already exist
foreach (Geary.SpecialFolderType special in this.specials) {
try {
yield this.generic_account.ensure_special_folder_async(
remote, special, cancellable
);
} catch (Error e) {
warning("Unable to ensure special folder %s: %s", special.to_string(), e.message);
}
}
}
}
/**
* Account operation that updates a folder's unseen message count.
*
* This performs a IMAP STATUS on the folder, but only if it is not
* open - if it is open it is already maintaining its unseen count.
*/
internal class Geary.ImapEngine.RefreshFolderUnseen : FolderOperation {
internal RefreshFolderUnseen(MinimalFolder folder,
GenericAccount account) {
base(account, folder);
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: 81ef002 e18bef9 Author: 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: c9ed434 a9dc52b Author: 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: b29abce d538bf0 Author: 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: 2b9dbb9 ff5f9fa Author: Charles Lindsay <chaz@yorba.org> Date: Mon Jan 28 17:42:34 2013 -0800 Merge branch 'master' into multiple-accounts commit 2b9dbb9b6963b1d52b2b90300bcea277b01d2094 Merge: 7583241 fcfb460 Author: 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: 5e84e93 e971275 Author: 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: 30b611e 6de36ae Author: 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: 335480e 6de36ae Author: 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.
2013-01-31 15:17:44 -08:00
}
public override async void execute(Cancellable cancellable) throws Error {
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
GenericAccount account = (GenericAccount) this.account;
if (this.folder.get_open_state() == Geary.Folder.OpenState.CLOSED) {
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
Imap.AccountSession? remote = yield account.claim_account_session(
cancellable
);
try {
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
Imap.Folder remote_folder = yield remote.fetch_folder_async(
folder.path,
cancellable
);
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
// Implementation-specific hack: Although this is called
// when the MinimalFolder is closed, we can safely use
// local_folder since we are only using its properties,
// and the properties were loaded when the folder was
// first instantiated.
ImapDB.Folder local_folder = ((MinimalFolder) this.folder).local_folder;
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
if (remote_folder.properties.have_contents_changed(
local_folder.get_properties(),
this.folder.to_string())) {
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
yield local_folder.update_folder_status(
2019-04-04 20:50:48 +11:00
remote_folder.properties, true, cancellable
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
);
Remove GenericAccount's IMAP account session attribute. For most of the time, GenericAccount does not need an open client session, yet it always claims one from the pool on open and hangs on to it. This means that the account synchroniser for example cannot use the same session to perform sync, requiring an additional session to be opened. This patch removes the held session with methods to claim and release account sessions instances for those code paths that need it, allowing the previously claimed session to be re-used when not in use. * src/engine/imap-engine/imap-engine-generic-account.vala (GenericAccount): Remove remote_open_lock and remote_session, just claim new client sessions from the pool as needed instead. Add release_account_session to allow claimed sessions to be returned to the pool. Update uses of remote_session to claim and release instead. * src/engine/imap/transport/imap-client-session-manager.vala (ClientSessionManager): Update ready signal to include a parameter indicating if ready or not, so GenericAccount can still block claim_account_session callers when not ready. Rework all code that sets is_ready to use a common notify method that both does that and fires the signal, and rework all code paths that stop the pool to use a common code path that uniformly resets timers, notifies no longer ready, and drops all client sessions. * src/engine/imap/api/imap-account-session.vala: Remove distinction between fetch_folder_async and fetch_folder_cached_async since account session objects are now short-lived.
2018-02-27 01:03:21 +11:00
((GenericAccount) this.account).update_folder(this.folder);
}
} finally {
account.release_account_session(remote);
}
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: 81ef002 e18bef9 Author: 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: c9ed434 a9dc52b Author: 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: b29abce d538bf0 Author: 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: 2b9dbb9 ff5f9fa Author: Charles Lindsay <chaz@yorba.org> Date: Mon Jan 28 17:42:34 2013 -0800 Merge branch 'master' into multiple-accounts commit 2b9dbb9b6963b1d52b2b90300bcea277b01d2094 Merge: 7583241 fcfb460 Author: 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: 5e84e93 e971275 Author: 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: 30b611e 6de36ae Author: 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: 335480e 6de36ae Author: 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.
2013-01-31 15:17:44 -08:00
}
}
}