diff --git a/src/engine/api/geary-folder-supports-create.vala b/src/engine/api/geary-folder-supports-create.vala index b04b2080..664e9f6c 100644 --- a/src/engine/api/geary-folder-supports-create.vala +++ b/src/engine/api/geary-folder-supports-create.vala @@ -2,7 +2,7 @@ * Copyright 2016 Software Freedom Conservancy Inc. * * This software is licensed under the GNU Lesser General Public License - * (version 2.1 or later). See the COPYING file in this distribution. + * (version 2.1 or later). See the COPYING file in this distribution. */ /** @@ -30,17 +30,12 @@ public interface Geary.FolderSupport.Create : Folder { * time to be set when saved. Like EmailFlags, this is optional * if not applicable. * - * If an id is passed, this will replace the existing message by - * deleting it after the new message is created. The new - * message's ID is returned. - * * @see FolderProperties.create_never_returns_id */ public abstract async EmailIdentifier? create_email_async(RFC822.Message rfc822, EmailFlags? flags, DateTime? date_received, - EmailIdentifier? id, GLib.Cancellable? cancellable = null) throws GLib.Error; diff --git a/src/engine/app/app-draft-manager.vala b/src/engine/app/app-draft-manager.vala index 620453ba..1ff0fb4a 100644 --- a/src/engine/app/app-draft-manager.vala +++ b/src/engine/app/app-draft-manager.vala @@ -408,8 +408,13 @@ public class Geary.App.DraftManager : BaseObject { return false; // make sure there's a folder to work with - if (drafts_folder == null || drafts_folder.get_open_state() == Folder.OpenState.CLOSED) { - fatal(new EngineError.SERVER_UNAVAILABLE("%s: premature drafts folder close", to_string())); + if (this.drafts_folder == null || + this.drafts_folder.get_open_state() == CLOSED) { + fatal( + new EngineError.SERVER_UNAVAILABLE( + "%s: premature drafts folder close", to_string() + ) + ); return false; } @@ -417,44 +422,48 @@ public class Geary.App.DraftManager : BaseObject { // at this point, only operation left is PUSH assert(op.op_type == OperationType.PUSH); - draft_state = DraftState.STORING; - - // delete old draft for all PUSHes: best effort ... since create_email_async() will handle - // replacement in a transactional-kinda-way, only outright delete if not using create - if (current_draft_id != null && op.draft == null) { - bool success = false; - try { - yield remove_support.remove_email_async( - iterate(current_draft_id).to_array_list()); - success = true; - } catch (Error err) { - debug("%s: Unable to remove existing draft %s: %s", to_string(), current_draft_id.to_string(), - err.message); - } - - // always clear draft id (assuming that retrying a failed remove is unnecessary), but - // only signal the discard if it actually was removed - current_draft_id = null; - if (success) - notify_discarded(); - } + this.draft_state = DraftState.STORING; // if draft supplied, save it if (op.draft != null) { try { - current_draft_id = yield create_support.create_email_async(op.draft, op.flags, - op.date_received, current_draft_id, null); + EmailIdentifier? old_id = this.current_draft_id; + this.current_draft_id = + yield this.create_support.create_email_async( + op.draft, + op.flags, + op.date_received, + null + ); + yield this.remove_support.remove_email_async( + Collection.single(old_id), null + ); - draft_state = DraftState.STORED; + this.draft_state = DraftState.STORED; notify_stored(op.draft); - } catch (Error err) { - draft_state = DraftState.ERROR; - - // notify subscribers + } catch (GLib.Error err) { + this.draft_state = DraftState.ERROR; draft_failed(op.draft, err); } } else { - draft_state = DraftState.NOT_STORED; + this.draft_state = DraftState.NOT_STORED; + + // Delete the old draft if present so it's not hanging + // around + if (this.current_draft_id != null) { + try { + yield this.remove_support.remove_email_async( + Collection.single(this.current_draft_id), + null + ); + notify_discarded(); + } catch (GLib.Error err) { + warning("%s: Unable to remove existing draft %s: %s", + to_string(), + current_draft_id.to_string(), + err.message); + } + } } return true; @@ -463,5 +472,12 @@ public class Geary.App.DraftManager : BaseObject { public string to_string() { return "%s DraftManager".printf(account.to_string()); } -} + private async void save_draft(EmailIdentifier id) { + + } + + private async void remove_draft(EmailIdentifier id) { + + } +} diff --git a/src/engine/imap-engine/gmail/imap-engine-gmail-drafts-folder.vala b/src/engine/imap-engine/gmail/imap-engine-gmail-drafts-folder.vala index b86465c2..ede8622a 100644 --- a/src/engine/imap-engine/gmail/imap-engine-gmail-drafts-folder.vala +++ b/src/engine/imap-engine/gmail/imap-engine-gmail-drafts-folder.vala @@ -1,32 +1,41 @@ -/* Copyright 2016 Software Freedom Conservancy Inc. +/* + * Copyright 2016 Software Freedom Conservancy Inc. * * This software is licensed under the GNU Lesser General Public License - * (version 2.1 or later). See the COPYING file in this distribution. + * (version 2.1 or later). See the COPYING file in this distribution. */ /** - * Gmail's Drafts folder supports basic operations as well as true removal of messages and creating - * new ones (IMAP APPEND). + * A draft folder for Gmail. + * + * Gmail's drafts folders supports basic operations as well as true + * removal of messages and creating new ones (IMAP APPEND). */ +private class Geary.ImapEngine.GmailDraftsFolder : + MinimalFolder, FolderSupport.Create, FolderSupport.Remove { -private class Geary.ImapEngine.GmailDraftsFolder : MinimalFolder, FolderSupport.Create, - FolderSupport.Remove { public GmailDraftsFolder(GmailAccount account, ImapDB.Folder local_folder, SpecialFolderType special_folder_type) { - base (account, local_folder, special_folder_type); + base(account, local_folder, special_folder_type); } - public new async Geary.EmailIdentifier? create_email_async( - RFC822.Message rfc822, Geary.EmailFlags? flags, DateTime? date_received, - Geary.EmailIdentifier? id, Cancellable? cancellable = null) throws Error { - return yield base.create_email_async(rfc822, flags, date_received, id, cancellable); + public new async EmailIdentifier? + create_email_async(RFC822.Message rfc822, + EmailFlags? flags, + DateTime? date_received, + GLib.Cancellable? cancellable = null) + throws GLib.Error { + return yield base.create_email_async( + rfc822, flags, date_received, cancellable + ); } - public async void remove_email_async( - Gee.Collection email_ids, - GLib.Cancellable? cancellable = null) + public async void + remove_email_async(Gee.Collection email_ids, + GLib.Cancellable? cancellable = null) throws GLib.Error { yield GmailFolder.true_remove_email_async(this, email_ids, cancellable); } + } diff --git a/src/engine/imap-engine/gmail/imap-engine-gmail-folder.vala b/src/engine/imap-engine/gmail/imap-engine-gmail-folder.vala index 4744f67c..cab40317 100644 --- a/src/engine/imap-engine/gmail/imap-engine-gmail-folder.vala +++ b/src/engine/imap-engine/gmail/imap-engine-gmail-folder.vala @@ -13,10 +13,15 @@ private class Geary.ImapEngine.GmailFolder : MinimalFolder, FolderSupport.Archiv base (account, local_folder, special_folder_type); } - public new async Geary.EmailIdentifier? create_email_async( - RFC822.Message rfc822, Geary.EmailFlags? flags, DateTime? date_received, - Geary.EmailIdentifier? id, Cancellable? cancellable = null) throws Error { - return yield base.create_email_async(rfc822, flags, date_received, id, cancellable); + public new async EmailIdentifier? + create_email_async(RFC822.Message rfc822, + EmailFlags? flags, + DateTime? date_received, + GLib.Cancellable? cancellable = null) + throws GLib.Error { + return yield base.create_email_async( + rfc822, flags, date_received, cancellable + ); } public async Geary.Revokable? diff --git a/src/engine/imap-engine/imap-engine-generic-folder.vala b/src/engine/imap-engine/imap-engine-generic-folder.vala index 819eac9d..b9a28b22 100644 --- a/src/engine/imap-engine/imap-engine-generic-folder.vala +++ b/src/engine/imap-engine/imap-engine-generic-folder.vala @@ -48,9 +48,14 @@ private class Geary.ImapEngine.GenericFolder : MinimalFolder, yield expunge_all_async(cancellable); } - public new async Geary.EmailIdentifier? create_email_async(RFC822.Message rfc822, - Geary.EmailFlags? flags, DateTime? date_received, Geary.EmailIdentifier? id, - Cancellable? cancellable = null) throws Error { - return yield base.create_email_async(rfc822, flags, date_received, id, cancellable); + public new async EmailIdentifier? + create_email_async(RFC822.Message rfc822, + EmailFlags? flags, + DateTime? date_received, + GLib.Cancellable? cancellable = null) + throws GLib.Error { + return yield base.create_email_async( + rfc822, flags, date_received, cancellable + ); } } diff --git a/src/engine/imap-engine/imap-engine-minimal-folder.vala b/src/engine/imap-engine/imap-engine-minimal-folder.vala index 3f3bc1fe..18eee9bb 100644 --- a/src/engine/imap-engine/imap-engine-minimal-folder.vala +++ b/src/engine/imap-engine/imap-engine-minimal-folder.vala @@ -1458,58 +1458,34 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport return earliest; } - protected async Geary.EmailIdentifier? create_email_async(RFC822.Message rfc822, - Geary.EmailFlags? flags, DateTime? date_received, Geary.EmailIdentifier? id, - Cancellable? cancellable = null) throws Error { + protected async EmailIdentifier? + create_email_async(RFC822.Message rfc822, + EmailFlags? flags, + DateTime? date_received, + GLib.Cancellable? cancellable = null) + throws GLib.Error { check_open("create_email_async"); - if (id != null) - check_id("create_email_async", id); + CreateEmail op = new CreateEmail( + this, rfc822, flags, date_received, cancellable + ); + replay_queue.schedule(op); + yield op.wait_for_ready_async(cancellable); + this._account.update_folder(this); - Error? cancel_error = null; - Geary.EmailIdentifier? ret = null; - try { - CreateEmail create = new CreateEmail(this, rfc822, flags, date_received, cancellable); - replay_queue.schedule(create); - yield create.wait_for_ready_async(cancellable); - - ret = create.created_id; - } catch (Error e) { - if (e is IOError.CANCELLED) - cancel_error = e; - else - throw e; - } - - Geary.FolderSupport.Remove? remove_folder = this as Geary.FolderSupport.Remove; - - // Remove old message. - if (id != null && remove_folder != null) - yield remove_folder.remove_email_async(iterate(id).to_array_list()); - - // If the user cancelled the operation, throw the error here. - if (cancel_error != null) - throw cancel_error; - - // If the caller cancelled during the remove operation, delete the newly created message to - // safely back out. - if (cancellable != null && cancellable.is_cancelled() && ret != null && remove_folder != null) - yield remove_folder.remove_email_async(iterate(ret).to_array_list()); - - if (ret != null) { + if (op.created_id != null) { // Server returned a UID for the new message. It was saved // locally possibly before the server notified that the // message exists. As such, fetch any missing parts from // the remote to ensure it is properly filled in. yield list_email_by_id_async( - ret, 1, ALL, INCLUDING_ID, cancellable + op.created_id, 1, ALL, INCLUDING_ID, cancellable ); } else { // The server didn't return a UID for the new email, so do // a sync now to ensure it shows up immediately. yield synchronise_remote(cancellable); } - - return ret; + return op.created_id; } /** Fires a {@link marked_email_removed} signal for this folder. */ diff --git a/src/engine/outbox/outbox-folder.vala b/src/engine/outbox/outbox-folder.vala index 6f72194f..eb58c1ce 100644 --- a/src/engine/outbox/outbox-folder.vala +++ b/src/engine/outbox/outbox-folder.vala @@ -112,7 +112,6 @@ private class Geary.Outbox.Folder : create_email_async(RFC822.Message rfc822, Geary.EmailFlags? flags, GLib.DateTime? date_received, - Geary.EmailIdentifier? id = null, GLib.Cancellable? cancellable = null) throws GLib.Error { check_open(); diff --git a/src/engine/smtp/smtp-client-service.vala b/src/engine/smtp/smtp-client-service.vala index 51dc2f7f..d22e4712 100644 --- a/src/engine/smtp/smtp-client-service.vala +++ b/src/engine/smtp/smtp-client-service.vala @@ -87,7 +87,7 @@ internal class Geary.Smtp.ClientService : Geary.ClientService { debug("Queuing message for sending: %s", message_subject(rfc822)); EmailIdentifier id = yield this.outbox.create_email_async( - rfc822, null, null, null, cancellable + rfc822, null, null, cancellable ); this.outbox_queue.send(id); } @@ -330,7 +330,7 @@ internal class Geary.Smtp.ClientService : Geary.ClientService { try { yield create.open_async(NO_DELAY, cancellable); open = true; - yield create.create_email_async(raw, null, null, null, cancellable); + yield create.create_email_async(raw, null, null, cancellable); yield wait_for_message(create, message, cancellable); } finally { if (open) {