diff --git a/src/engine/api/geary-account.vala b/src/engine/api/geary-account.vala index 0a234e28..e08f9cc0 100644 --- a/src/engine/api/geary-account.vala +++ b/src/engine/api/geary-account.vala @@ -406,6 +406,18 @@ public abstract class Geary.Account : BaseObject, Logging.Source { GLib.Cancellable? cancellable = null ) throws GLib.Error; + /** + * Creates a new folder in the root of the personal name space. + * + * If this account is backed by a remote server, calling this + * causes the folder to be created on the remote. + */ + public abstract async Folder create_personal_folder( + string name, + Folder.SpecialUse use = NONE, + GLib.Cancellable? cancellable = null + ) throws GLib.Error; + /** * Search the local account for emails referencing a Message-ID value * (which can appear in the Message-ID header itself, as well as the diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala b/src/engine/imap-engine/imap-engine-generic-account.vala index bb550fb4..1bce766e 100644 --- a/src/engine/imap-engine/imap-engine-generic-account.vala +++ b/src/engine/imap-engine/imap-engine-generic-account.vala @@ -447,6 +447,41 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account { return folder; } + /** {@inheritDoc} */ + public override async Folder create_personal_folder( + string name, + Folder.SpecialUse use = NONE, + GLib.Cancellable? cancellable = null + ) throws GLib.Error { + check_open(); + var remote = yield claim_account_session(cancellable); + FolderPath root = + yield remote.get_default_personal_namespace(cancellable); + FolderPath path = root.get_child(name); + if (this.folder_map.has_key(path)) { + throw new EngineError.ALREADY_EXISTS( + "Folder already exists: %s", path.to_string() + ); + } + yield remote.create_folder_async(path, use, cancellable); + + Imap.Folder? remote_folder = yield remote.fetch_folder_async( + path, cancellable + ); + + ImapDB.Folder local_folder = yield this.local.clone_folder_async( + remote_folder, cancellable + ); + add_folders(Collection.single(local_folder), false); + var folder = this.folder_map.get(path); + if (use != NONE) { + promote_folders( + Collection.single_map(use, folder) + ); + } + return folder; + } + private ImapDB.EmailIdentifier check_id(Geary.EmailIdentifier id) throws EngineError { ImapDB.EmailIdentifier? imapdb_id = id as ImapDB.EmailIdentifier; if (imapdb_id == null) @@ -699,50 +734,18 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account { ); } - if (!this.folder_map.has_key(path)) { + if (this.folder_map.has_key(path)) { + special = this.folder_map.get(path); + promote_folders( + Collection.single_map(use, special) + ); + } else { debug("Creating \"%s\" to use as special folder %s", path.to_string(), use.to_string()); - - GLib.Error? created_err = null; - try { - yield remote.create_folder_async(path, use, 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 = yield create_personal_folder( + path.name, use, cancellable ); } - - special= this.folder_map.get(path); - promote_folders( - Collection.single_map( - use, special - ) - ); } return special; diff --git a/test/engine/api/geary-account-mock.vala b/test/engine/api/geary-account-mock.vala index b39ad115..d2a6cae5 100644 --- a/test/engine/api/geary-account-mock.vala +++ b/test/engine/api/geary-account-mock.vala @@ -107,6 +107,18 @@ public class Geary.MockAccount : Account, MockObject { } } + public override async Folder create_personal_folder( + string name, + Folder.SpecialUse use = NONE, + GLib.Cancellable? cancellable = null + ) throws GLib.Error { + return object_call( + "create_personal_folder", + { box_arg(name), box_arg(use), cancellable }, + new MockFolder(null, null, null, use, null) + ); + } + public override EmailIdentifier to_email_identifier(GLib.Variant serialised) throws EngineError.BAD_PARAMETERS { try {