diff --git a/src/engine/api/geary-account.vala b/src/engine/api/geary-account.vala index ae0fc056..41e74cfa 100644 --- a/src/engine/api/geary-account.vala +++ b/src/engine/api/geary-account.vala @@ -320,6 +320,48 @@ public abstract class Geary.Account : BaseObject { public abstract EmailIdentifier to_email_identifier(GLib.Variant serialised) throws EngineError.BAD_PARAMETERS; + /** + * Returns the folder path from its serialised form. + * + * This is useful for converting a string representation of a + * folder path back into an actual instance of a path. This does + * not guarantee that the folder represented by the path will + * exist. + * + * @see FolderPath.to_variant + * @throws EngineError.BAD_PARAMETERS when the variant is not the + * have the correct type or if no folder root with an appropriate + * label exists. + */ + public abstract FolderPath to_folder_path(GLib.Variant serialised) + throws EngineError.BAD_PARAMETERS; + + /** + * Determines if a folder is known to the engine. + * + * This method only considers currently known folders, it does not + * check the remote to see if a previously folder exists. + */ + public virtual bool has_folder(FolderPath path) { + try { + get_folder(path); + return true; + } catch (EngineError.NOT_FOUND err) { + return false; + } + } + + /** + * Returns the folder represented by a specific path. + * + * This method only considers currently known folders, it does not + * check the remote to see if a previously folder exists. + * + * @throws EngineError.NOT_FOUND if the folder does not exist. + */ + public abstract Folder get_folder(FolderPath path) + throws EngineError.NOT_FOUND; + /** * Lists all the currently-available folders found under the parent path * unless it's null, in which case it lists all the root folders. If the @@ -347,26 +389,6 @@ public abstract class Geary.Account : BaseObject { */ public abstract Geary.ContactStore get_contact_store(); - /** - * Returns true if the folder exists. - * - * This method never throws EngineError.NOT_FOUND. - */ - public abstract async bool folder_exists_async(Geary.FolderPath path, Cancellable? cancellable = null) - throws Error; - - /** - * Fetches a Folder object corresponding to the supplied path. If the backing medium does - * not have a record of a folder at the path, EngineError.NOT_FOUND will be thrown. - * - * The same Geary.Folder object (instance) will be returned if the same path is submitted - * multiple times. This means that multiple callers may be holding references to the same - * Folders. This is important when thinking of opening and closing folders and signal - * notifications. - */ - public abstract async Geary.Folder fetch_folder_async(Geary.FolderPath path, - Cancellable? cancellable = null) throws Error; - /** * Returns the folder representing the given special folder type. If no such folder exists, * null is returned. diff --git a/src/engine/app/app-email-store.vala b/src/engine/app/app-email-store.vala index a346409b..103fbf05 100644 --- a/src/engine/app/app-email-store.vala +++ b/src/engine/app/app-email-store.vala @@ -41,7 +41,7 @@ public class Geary.App.EmailStore : BaseObject { foreach (Geary.FolderPath path in folders.get(email)) { Geary.Folder folder; try { - folder = yield account.fetch_folder_async(path, cancellable); + folder = account.get_folder(path); } catch (Error e) { debug("Error getting a folder from path %s: %s", path.to_string(), e.message); continue; @@ -108,33 +108,23 @@ public class Geary.App.EmailStore : BaseObject { emails, cancellable); } - private async Gee.HashMap get_folder_instances_async( - Gee.Collection paths, Cancellable? cancellable) throws Error { - Gee.HashMap folders - = new Gee.HashMap(); - foreach (Geary.FolderPath path in paths) { - Geary.Folder folder = yield account.fetch_folder_async(path, cancellable); - folders.set(path, folder); - } - return folders; - } - - private Geary.FolderPath? next_folder_for_operation(AsyncFolderOperation operation, - Gee.MultiMap folders_to_ids, - Gee.Map folders) throws Error { + private FolderPath? + next_folder_for_operation(AsyncFolderOperation operation, + Gee.MultiMap folders_to_ids) + throws GLib.Error { bool best_is_open = false; int best_count = 0; Geary.FolderPath? best = null; foreach (Geary.FolderPath path in folders_to_ids.get_keys()) { - assert(folders.has_key(path)); - if (!folders.get(path).get_type().is_a(operation.folder_type)) + Folder folder = this.account.get_folder(path); + if (!folder.get_type().is_a(operation.folder_type)) continue; int count = folders_to_ids.get(path).size; if (count == 0) continue; - if (folders.get(path).get_open_state() == Geary.Folder.OpenState.REMOTE) { + if (folder.get_open_state() == Geary.Folder.OpenState.REMOTE) { if (!best_is_open) { best_is_open = true; best_count = 0; @@ -167,12 +157,9 @@ public class Geary.App.EmailStore : BaseObject { Gee.MultiMap folders_to_ids = Geary.Collection.reverse_multi_map(ids_to_folders); - Gee.HashMap folders - = yield get_folder_instances_async(folders_to_ids.get_keys(), cancellable); - Geary.FolderPath? path; - while ((path = next_folder_for_operation(operation, folders_to_ids, folders)) != null) { - Geary.Folder folder = folders.get(path); + while ((path = next_folder_for_operation(operation, folders_to_ids)) != null) { + Geary.Folder folder = this.account.get_folder(path); Gee.Collection ids = folders_to_ids.get(path); assert(ids.size > 0); diff --git a/src/engine/imap-db/search/imap-db-search-folder.vala b/src/engine/imap-db/search/imap-db-search-folder.vala index 5a2b84e1..0081f349 100644 --- a/src/engine/imap-db/search/imap-db-search-folder.vala +++ b/src/engine/imap-db/search/imap-db-search-folder.vala @@ -336,7 +336,7 @@ private class Geary.ImapDB.SearchFolder : Geary.SearchFolder, Geary.FolderSuppor = Geary.Collection.reverse_multi_map(ids_to_folders); foreach (Geary.FolderPath path in folders_to_ids.get_keys()) { - Geary.Folder folder = yield account.fetch_folder_async(path, cancellable); + Geary.Folder folder = account.get_folder(path); Geary.FolderSupport.Remove? remove = folder as Geary.FolderSupport.Remove; if (remove == null) continue; diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala b/src/engine/imap-engine/imap-engine-generic-account.vala index acb92b48..6e4c4bb9 100644 --- a/src/engine/imap-engine/imap-engine-generic-account.vala +++ b/src/engine/imap-engine/imap-engine-generic-account.vala @@ -434,6 +434,34 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account { 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) { + folder = this.local_only.get(path); + if (folder == null) { + throw new EngineError.NOT_FOUND( + "Folder not found: %s", path.to_string() + ); + } + } + return folder; + } + + /** {@inheritDoc} */ public override Gee.Collection list_matching_folders(Geary.FolderPath? parent) throws Error { check_open(); @@ -461,33 +489,6 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account { return local.contact_store; } - /** {@inheritDoc} */ - public override async bool folder_exists_async(Geary.FolderPath path, - Cancellable? cancellable = null) - throws Error { - check_open(); - return this.local_only.has_key(path) || this.folder_map.has_key(path); - } - - /** {@inheritDoc} */ - public override async Geary.Folder fetch_folder_async(Geary.FolderPath path, - Cancellable? cancellable = null) - throws Error { - check_open(); - - Geary.Folder? folder = this.local_only.get(path); - if (folder == null) { - folder = this.folder_map.get(path); - - if (folder == null) { - throw new EngineError.NOT_FOUND( - "Folder not found: %s", path.to_string() - ); - } - } - return folder; - } - public override async Geary.Folder get_required_special_folder_async(Geary.SpecialFolderType special, Cancellable? cancellable) throws Error { if (!(special in get_supported_special_folders())) { @@ -1125,9 +1126,7 @@ internal class Geary.ImapEngine.LoadFolders : AccountOperation { path = this.local.imap_folder_root.copy(path); if (path != null) { try { - Geary.Folder target = yield generic.fetch_folder_async( - path, cancellable - ); + Geary.Folder target = generic.get_folder(path); added_specials.set(type, target); } catch (Error err) { debug( diff --git a/src/engine/imap-engine/imap-engine-minimal-folder.vala b/src/engine/imap-engine/imap-engine-minimal-folder.vala index e6e4e3d7..bbe2bded 100644 --- a/src/engine/imap-engine/imap-engine-minimal-folder.vala +++ b/src/engine/imap-engine/imap-engine-minimal-folder.vala @@ -1272,7 +1272,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport Geary.FolderPath destination, GLib.Cancellable? cancellable = null) throws GLib.Error { - Geary.Folder target = yield this._account.fetch_folder_async(destination); + Geary.Folder target = this._account.get_folder(destination); yield copy_email_uids_async(to_copy, destination, cancellable); this._account.update_folder(target); } @@ -1321,7 +1321,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport if (prepare.prepared_for_move == null || prepare.prepared_for_move.size == 0) return null; - Geary.Folder target = yield this._account.fetch_folder_async(destination); + Geary.Folder target = this._account.get_folder(destination); return new RevokableMove( _account, this, target, prepare.prepared_for_move ); diff --git a/src/engine/imap-engine/imap-engine-revokable-committed-move.vala b/src/engine/imap-engine/imap-engine-revokable-committed-move.vala index 54431035..386186c0 100644 --- a/src/engine/imap-engine/imap-engine-revokable-committed-move.vala +++ b/src/engine/imap-engine/imap-engine-revokable-committed-move.vala @@ -40,7 +40,7 @@ private class Geary.ImapEngine.RevokableCommittedMove : Revokable { notify_revoked(); - Geary.Folder target = yield this.account.fetch_folder_async(this.destination); + Geary.Folder target = this.account.get_folder(this.destination); this.account.update_folder(target); } finally { if (session != null) { diff --git a/test/engine/api/geary-account-mock.vala b/test/engine/api/geary-account-mock.vala index fb1189a6..ce5304e3 100644 --- a/test/engine/api/geary-account-mock.vala +++ b/test/engine/api/geary-account-mock.vala @@ -135,6 +135,36 @@ public class Geary.MockAccount : Account, MockObject { } } + public override FolderPath to_folder_path(GLib.Variant serialised) + throws EngineError.BAD_PARAMETERS { + try { + return object_or_throw_call( + "to_folder_path", + { box_arg(serialised) }, + new EngineError.BAD_PARAMETERS("Mock error") + ); + } catch (EngineError.BAD_PARAMETERS err) { + throw err; + } catch (GLib.Error err) { + return new FolderRoot("#mock", false); + } + } + + public override Folder get_folder(FolderPath path) + throws EngineError.NOT_FOUND { + try { + return object_or_throw_call( + "get_folder", + { path }, + new EngineError.NOT_FOUND("Mock error") + ); + } catch (EngineError.NOT_FOUND err) { + throw err; + } catch (GLib.Error err) { + return new MockFolder(null, null, null, SpecialFolderType.NONE, null); + } + } + public override Gee.Collection list_folders() throws Error { return object_call>( "list_folders", {}, Gee.List.empty() @@ -145,22 +175,6 @@ public class Geary.MockAccount : Account, MockObject { return new MockContactStore(); } - public override async bool folder_exists_async(FolderPath path, - Cancellable? cancellable = null) - throws Error { - return boolean_call("folder_exists_async", {path, cancellable}, false); - } - - public override async Folder fetch_folder_async(FolderPath path, - Cancellable? cancellable = null) - throws Error { - return object_or_throw_call( - "fetch_folder_async", - {path, cancellable}, - new EngineError.NOT_FOUND("Mock call") - ); - } - public override Folder? get_special_folder(SpecialFolderType special) throws Error { return object_call(