[geary/wip/remote-retry: 10/10] More refinements, progress



commit f3683512dbc3ccb8ddbb54fb18d2a652afe0ecd1
Author: Jim Nelson <jim yorba org>
Date:   Fri Jan 16 15:45:03 2015 -0800

    More refinements, progress

 src/engine/api/geary-folder-supports-archive.vala  |    6 ++-
 src/engine/api/geary-folder-supports-copy.vala     |    7 ++-
 src/engine/api/geary-folder-supports-create.vala   |   12 ++++-
 src/engine/api/geary-folder-supports-empty.vala    |    7 ++-
 src/engine/api/geary-folder-supports-mark.vala     |    7 ++-
 src/engine/api/geary-folder-supports-move.vala     |    7 ++-
 src/engine/api/geary-folder-supports-remove.vala   |    7 ++-
 src/engine/api/geary-folder.vala                   |   10 ++++-
 src/engine/api/geary-future.vala                   |    3 +-
 src/engine/api/geary-search-folder.vala            |    2 +-
 src/engine/imap-db/outbox/smtp-outbox-folder.vala  |    4 +-
 .../gmail/imap-engine-gmail-drafts-folder.vala     |    2 +-
 .../gmail/imap-engine-gmail-folder.vala            |    8 ++--
 .../gmail/imap-engine-gmail-search-folder.vala     |    2 +-
 .../gmail/imap-engine-gmail-spam-trash-folder.vala |    4 +-
 .../imap-engine/imap-engine-generic-folder.vala    |    6 +-
 .../imap-engine/imap-engine-minimal-folder.vala    |   27 +++++++----
 .../imap-engine/imap-engine-replay-operation.vala  |   49 ++++++++++++++------
 .../replay-ops/imap-engine-create-email.vala       |    7 ++-
 .../replay-ops/imap-engine-fetch-email.vala        |   10 +++-
 .../replay-ops/imap-engine-replay-append.vala      |    6 +-
 .../replay-ops/imap-engine-replay-disconnect.vala  |    6 +-
 .../replay-ops/imap-engine-replay-removal.vala     |    6 +-
 23 files changed, 131 insertions(+), 74 deletions(-)
---
diff --git a/src/engine/api/geary-folder-supports-archive.vala 
b/src/engine/api/geary-folder-supports-archive.vala
index 9cfedb1..7bb51df 100644
--- a/src/engine/api/geary-folder-supports-archive.vala
+++ b/src/engine/api/geary-folder-supports-archive.vala
@@ -17,9 +17,13 @@ public interface Geary.FolderSupport.Archive : Geary.Folder {
     /**
      * Archives the specified emails from the folder.
      *
+     * The method throws an Error if there's an issue with initiating the operation.  The
+     * { link Future} throws an Error if there's an issue with ''completing'' the operation, which
+     * may occur after this call has completed.
+     *
      * The { link Geary.Folder} must be opened prior to attempting this operation.
      */
-    public abstract async Geary.Future? archive_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
+    public abstract async Geary.Future archive_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
         Cancellable? cancellable = null) throws Error;
 }
 
diff --git a/src/engine/api/geary-folder-supports-copy.vala b/src/engine/api/geary-folder-supports-copy.vala
index eb12b48..861efb7 100644
--- a/src/engine/api/geary-folder-supports-copy.vala
+++ b/src/engine/api/geary-folder-supports-copy.vala
@@ -19,12 +19,13 @@ public interface Geary.FolderSupport.Copy : Geary.Folder {
      * If the destination is this { link Folder}, the operation will not make a copy of the message
      * but will return success.
      *
-     * If a { link Future} is returned, the operation has been scheduled for completion in the
-     * background.  The Future can be monitored or waited upon for final completion.
+     * The method throws an Error if there's an issue with initiating the operation.  The
+     * { link Future} throws an Error if there's an issue with ''completing'' the operation, which
+     * may occur after this call has completed.
      *
      * The Folder must be opened prior to attempting this operation.
      */
-    public abstract async Geary.Future? copy_email_async(Gee.List<Geary.EmailIdentifier> to_copy,
+    public abstract async Geary.Future copy_email_async(Gee.List<Geary.EmailIdentifier> to_copy,
         Geary.FolderPath destination, Cancellable? cancellable = null) throws Error;
 }
 
diff --git a/src/engine/api/geary-folder-supports-create.vala 
b/src/engine/api/geary-folder-supports-create.vala
index 54cb9d6..8da9695 100644
--- a/src/engine/api/geary-folder-supports-create.vala
+++ b/src/engine/api/geary-folder-supports-create.vala
@@ -17,8 +17,6 @@ public interface Geary.FolderSupport.Create : Geary.Folder {
     /**
      *  Creates (appends) the message to this folder.
      *
-     * The Folder must be opened prior to attempting this operation.
-     *
      * The optional { link EmailFlags} allows for those flags to be set when saved.  Some Folders
      * may ignore those flags (i.e. Outbox) if not applicable.
      *
@@ -27,8 +25,16 @@ public interface Geary.FolderSupport.Create : Geary.Folder {
      * 
      * 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 in the { link Future}.
+     *
+     * The method throws an Error if there's an issue with initiating the operation.  The
+     * { link Future} throws an Error if there's an issue with ''completing'' the operation, which
+     * may occur after this call has completed.
+     *
+     * The Folder must be opened prior to attempting this operation.
+     *
+     * @returns A Future whose result Value is the created { link EmailIdentifier}.
      */
-    public abstract async Geary.Future? create_email_async(Geary.RFC822.Message rfc822, EmailFlags? flags,
+    public abstract async Geary.Future create_email_async(Geary.RFC822.Message rfc822, EmailFlags? flags,
         DateTime? date_received, Geary.EmailIdentifier? id, Cancellable? cancellable = null) throws Error;
 }
 
diff --git a/src/engine/api/geary-folder-supports-empty.vala b/src/engine/api/geary-folder-supports-empty.vala
index 69b48c2..d58f467 100644
--- a/src/engine/api/geary-folder-supports-empty.vala
+++ b/src/engine/api/geary-folder-supports-empty.vala
@@ -20,9 +20,10 @@ public interface Geary.FolderSupport.Empty : Geary.Folder {
     /**
      * Removes all email from the folder.
      *
-     * If a { link Future} is returned, the operation has been scheduled for completion in the
-     * background.  The Future can be monitored or waited upon for final completion.
+     * The method throws an Error if there's an issue with initiating the operation.  The
+     * { link Future} throws an Error if there's an issue with ''completing'' the operation, which
+     * may occur after this call has completed.
      */
-    public abstract async Geary.Future? empty_folder_async(Cancellable? cancellable = null) throws Error;
+    public abstract async Geary.Future empty_folder_async(Cancellable? cancellable = null) throws Error;
 }
 
diff --git a/src/engine/api/geary-folder-supports-mark.vala b/src/engine/api/geary-folder-supports-mark.vala
index eb28a61..83b0e50 100644
--- a/src/engine/api/geary-folder-supports-mark.vala
+++ b/src/engine/api/geary-folder-supports-mark.vala
@@ -13,12 +13,13 @@ public interface Geary.FolderSupport.Mark : Geary.Folder {
     /**
      * Adds and removes flags from a list of messages.
      *
-     * If a { link Future} is returned, the operation has been scheduled for completion in the
-     * background.  The Future can be monitored or waited upon for final completion.
+     * The method throws an Error if there's an issue with initiating the operation.  The
+     * { link Future} throws an Error if there's an issue with ''completing'' the operation, which
+     * may occur after this call has completed.
      *
      * The { link Geary.Folder} must be opened prior to attempting this operation.
      */
-    public abstract async Geary.Future? mark_email_async(Gee.List<Geary.EmailIdentifier> to_mark,
+    public abstract async Geary.Future mark_email_async(Gee.List<Geary.EmailIdentifier> to_mark,
         Geary.EmailFlags? flags_to_add, Geary.EmailFlags? flags_to_remove,
         Cancellable? cancellable = null) throws Error;
 }
diff --git a/src/engine/api/geary-folder-supports-move.vala b/src/engine/api/geary-folder-supports-move.vala
index a43b4ae..244c4d5 100644
--- a/src/engine/api/geary-folder-supports-move.vala
+++ b/src/engine/api/geary-folder-supports-move.vala
@@ -18,12 +18,13 @@ public interface Geary.FolderSupport.Move : Geary.Folder {
      * If the destination is this { link Folder}, the operation will not move the message in any
      * way but will return success.
      *
-     * If a { link Future} is returned, the operation has been scheduled for completion in the
-     * background.  The Future can be monitored or waited upon for final completion.
+     * The method throws an Error if there's an issue with initiating the operation.  The
+     * { link Future} throws an Error if there's an issue with ''completing'' the operation, which
+     * may occur after this call has completed.
      *
      * The { link Geary.Folder} must be opened prior to attempting this operation.
      */
-    public abstract async Geary.Future? move_email_async(Gee.List<Geary.EmailIdentifier> to_move,
+    public abstract async Geary.Future move_email_async(Gee.List<Geary.EmailIdentifier> to_move,
         Geary.FolderPath destination, Cancellable? cancellable = null) throws Error;
 }
 
diff --git a/src/engine/api/geary-folder-supports-remove.vala 
b/src/engine/api/geary-folder-supports-remove.vala
index fec1fb5..76dc57d 100644
--- a/src/engine/api/geary-folder-supports-remove.vala
+++ b/src/engine/api/geary-folder-supports-remove.vala
@@ -23,12 +23,13 @@ public interface Geary.FolderSupport.Remove : Geary.Folder {
     /**
      * Removes the specified emails from the folder.
      *
-     * If a { link Future} is returned, the operation has been scheduled for completion in the
-     * background.  The Future can be monitored or waited upon for final completion.
+     * The method throws an Error if there's an issue with initiating the operation.  The
+     * { link Future} throws an Error if there's an issue with ''completing'' the operation, which
+     * may occur after this call has completed.
      *
      * The { link Geary.Folder} must be opened prior to attempting this operation.
      */
-    public abstract async Geary.Future? remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
+    public abstract async Geary.Future remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
         Cancellable? cancellable = null) throws Error;
 }
 
diff --git a/src/engine/api/geary-folder.vala b/src/engine/api/geary-folder.vala
index bf5b1cf..b1c7c3d 100644
--- a/src/engine/api/geary-folder.vala
+++ b/src/engine/api/geary-folder.vala
@@ -483,6 +483,8 @@ public abstract class Geary.Folder : BaseObject {
      * EmailIdentifier implies that the top most email is included in the result (i.e.
      * ListFlags.INCLUDING_ID is not required);
      *
+     * If the remote connection fails, this call will return locally-available Email without error.
+     *
      * There's no guarantee of the returned messages' order.
      *
      * The Folder must be opened prior to attempting this operation.
@@ -499,6 +501,8 @@ public abstract class Geary.Folder : BaseObject {
      * one email for each requested; duplicates are ignored.  ListFlags.INCLUDING_ID is ignored
      * for this call.
      *
+     * If the remote connection fails, this call will return locally-available Email without error.
+     *
      * The Folder must be opened prior to attempting this operation.
      */
     public abstract async Gee.List<Geary.Email>? list_email_by_sparse_id_async(
@@ -533,9 +537,13 @@ public abstract class Geary.Folder : BaseObject {
      * force waiting for the server to connect.  Unlike the list variants, if in the OPENING state
      * and the message is not found locally, EngineError.NOT_FOUND is thrown.
      *
+     * The method throws an Error if there's an issue with initiating the operation.  The
+     * { link Future} throws an Error if there's an issue with ''completing'' the operation, which
+     * may occur after this call has completed.
+     *
      * The Folder must be opened prior to attempting this operation.
      */
-    public abstract async Geary.Email fetch_email_async(Geary.EmailIdentifier email_id,
+    public abstract async Geary.Future fetch_email_async(Geary.EmailIdentifier email_id,
         Geary.Email.Field required_fields, ListFlags flags, Cancellable? cancellable = null) throws Error;
     
     /**
diff --git a/src/engine/api/geary-future.vala b/src/engine/api/geary-future.vala
index 4632239..069f1f0 100644
--- a/src/engine/api/geary-future.vala
+++ b/src/engine/api/geary-future.vala
@@ -88,8 +88,7 @@ public class Geary.Future : BaseObject {
      * If the Future was fulfilled with an Error, it is thrown.  Otherwise, the result Value is
      * returned.
      *
-     * This method may be called any number of times.  If already fulfilled, it will complete
-     * instantly.
+     * This method may be called any number of times.
      *
      * @see fulfill
      */
diff --git a/src/engine/api/geary-search-folder.vala b/src/engine/api/geary-search-folder.vala
index 1beeb8f..e1bfb9c 100644
--- a/src/engine/api/geary-search-folder.vala
+++ b/src/engine/api/geary-search-folder.vala
@@ -380,7 +380,7 @@ public class Geary.SearchFolder : Geary.AbstractLocalFolder, Geary.FolderSupport
         return yield account.local_fetch_email_async(id, required_fields, cancellable);
     }
     
-    public virtual async Geary.Future? remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
+    public virtual async Geary.Future remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
         Cancellable? cancellable = null) throws Error {
         Gee.MultiMap<Geary.EmailIdentifier, Geary.FolderPath>? ids_to_folders
             = yield account.get_containing_folders_async(email_ids, cancellable);
diff --git a/src/engine/imap-db/outbox/smtp-outbox-folder.vala 
b/src/engine/imap-db/outbox/smtp-outbox-folder.vala
index 85a7991..6a8e0b4 100644
--- a/src/engine/imap-db/outbox/smtp-outbox-folder.vala
+++ b/src/engine/imap-db/outbox/smtp-outbox-folder.vala
@@ -386,7 +386,7 @@ private class Geary.SmtpOutboxFolder : Geary.AbstractLocalFolder, Geary.FolderSu
         return row.outbox_id;
     }
     
-    public virtual async Geary.EmailIdentifier? create_email_async(Geary.RFC822.Message rfc822, EmailFlags? 
flags,
+    public virtual async Geary.EmailIdentifier create_email_async(Geary.RFC822.Message rfc822, EmailFlags? 
flags,
         DateTime? date_received, Geary.EmailIdentifier? id = null, Cancellable? cancellable = null) throws 
Error {
         check_open();
         
@@ -552,7 +552,7 @@ private class Geary.SmtpOutboxFolder : Geary.AbstractLocalFolder, Geary.FolderSu
         notify_email_flags_changed(changed_map);
     }
     
-    public virtual async Geary.Future? remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
+    public virtual async Geary.Future remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
         Cancellable? cancellable = null) throws Error {
         check_open();
         
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 4176f28..a814549 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
@@ -22,7 +22,7 @@ private class Geary.ImapEngine.GmailDraftsFolder : MinimalFolder, FolderSupport.
         return yield base.create_email_async(rfc822, flags, date_received, id, cancellable);
     }
     
-    public async Geary.Future? remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
+    public async Geary.Future remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
         Cancellable? cancellable = null) throws Error {
         return 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 dba3c42..2dd85f6 100644
--- a/src/engine/imap-engine/gmail/imap-engine-gmail-folder.vala
+++ b/src/engine/imap-engine/gmail/imap-engine-gmail-folder.vala
@@ -11,18 +11,18 @@ private class Geary.ImapEngine.GmailFolder : MinimalFolder, FolderSupport.Archiv
         base (account, remote, local, local_folder, special_folder_type);
     }
     
-    public new async Geary.EmailIdentifier? create_email_async(
+    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 async Geary.Future? archive_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
+    public async Geary.Future archive_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
         Cancellable? cancellable = null) throws Error {
         return yield expunge_email_async(email_ids, cancellable);
     }
     
-    public async Geary.Future? remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
+    public async Geary.Future remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
         Cancellable? cancellable = null) throws Error {
         return yield true_remove_email_async(this, email_ids, cancellable);
     }
@@ -36,7 +36,7 @@ private class Geary.ImapEngine.GmailFolder : MinimalFolder, FolderSupport.Archiv
      * no connection (or the connection dies) there's no record that Geary needs to perform the
      * final remove when a connection is reestablished.
      */
-    public static async Geary.Future? true_remove_email_async(MinimalFolder folder,
+    public static async Geary.Future true_remove_email_async(MinimalFolder folder,
         Gee.List<Geary.EmailIdentifier> email_ids, Cancellable? cancellable) throws Error {
         // Get path to Trash folder
         Geary.Folder? trash = folder.account.get_special_folder(SpecialFolderType.TRASH);
diff --git a/src/engine/imap-engine/gmail/imap-engine-gmail-search-folder.vala 
b/src/engine/imap-engine/gmail/imap-engine-gmail-search-folder.vala
index caebbcd..a35de63 100644
--- a/src/engine/imap-engine/gmail/imap-engine-gmail-search-folder.vala
+++ b/src/engine/imap-engine/gmail/imap-engine-gmail-search-folder.vala
@@ -17,7 +17,7 @@ public class Geary.ImapEngine.GmailSearchFolder : Geary.SearchFolder {
         
     }
     
-    public override async Geary.Future? remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
+    public override async Geary.Future remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
         Cancellable? cancellable = null) throws Error {
         Geary.Folder? trash_folder = null;
         try {
diff --git a/src/engine/imap-engine/gmail/imap-engine-gmail-spam-trash-folder.vala 
b/src/engine/imap-engine/gmail/imap-engine-gmail-spam-trash-folder.vala
index e82e269..e99446e 100644
--- a/src/engine/imap-engine/gmail/imap-engine-gmail-spam-trash-folder.vala
+++ b/src/engine/imap-engine/gmail/imap-engine-gmail-spam-trash-folder.vala
@@ -16,12 +16,12 @@ private class Geary.ImapEngine.GmailSpamTrashFolder : MinimalFolder, FolderSuppo
         base (account, remote, local, local_folder, special_folder_type);
     }
     
-    public async Geary.Future? remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
+    public async Geary.Future remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
         Cancellable? cancellable = null) throws Error {
         return yield expunge_email_async(email_ids, cancellable);
     }
     
-    public async Geary.Future? empty_folder_async(Cancellable? cancellable = null) throws Error {
+    public async Geary.Future empty_folder_async(Cancellable? cancellable = null) throws Error {
         return yield expunge_all_async(cancellable);
     }
 }
diff --git a/src/engine/imap-engine/imap-engine-generic-folder.vala 
b/src/engine/imap-engine/imap-engine-generic-folder.vala
index 9cd77a0..48f2c57 100644
--- a/src/engine/imap-engine/imap-engine-generic-folder.vala
+++ b/src/engine/imap-engine/imap-engine-generic-folder.vala
@@ -11,16 +11,16 @@ private class Geary.ImapEngine.GenericFolder : MinimalFolder, Geary.FolderSuppor
         base (account, remote, local, local_folder, special_folder_type);
     }
     
-    public async Geary.Future? remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
+    public async Geary.Future remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
         Cancellable? cancellable = null) throws Error {
         return yield expunge_email_async(email_ids, cancellable);
     }
     
-    public async Geary.Future? empty_folder_async(Cancellable? cancellable = null) throws Error {
+    public async Geary.Future empty_folder_async(Cancellable? cancellable = null) throws Error {
         return yield expunge_all_async(cancellable);
     }
     
-    public new async Geary.Future? create_email_async(RFC822.Message rfc822, Geary.EmailFlags? flags,
+    public new async Geary.Future 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);
diff --git a/src/engine/imap-engine/imap-engine-minimal-folder.vala 
b/src/engine/imap-engine/imap-engine-minimal-folder.vala
index 625743f..e1cea2e 100644
--- a/src/engine/imap-engine/imap-engine-minimal-folder.vala
+++ b/src/engine/imap-engine/imap-engine-minimal-folder.vala
@@ -1274,7 +1274,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
     
     // Helper function for child classes dealing with the delete/archive question.  This method will
     // mark the message as deleted and expunge it.
-    protected async Geary.Future? expunge_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
+    protected async Geary.Future expunge_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
         Cancellable? cancellable) throws Error {
         check_open("expunge_email_async");
         check_ids("expunge_email_async", email_ids);
@@ -1286,7 +1286,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
         return yield remove.wait_for_ready_async(cancellable);
     }
     
-    protected async Geary.Future? expunge_all_async(Cancellable? cancellable = null) throws Error {
+    protected async Geary.Future expunge_all_async(Cancellable? cancellable = null) throws Error {
         check_open("expunge_all_async");
         
         EmptyFolder empty_folder = new EmptyFolder(this, cancellable);
@@ -1317,7 +1317,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
             check_id(method, id);
     }
     
-    public virtual async Geary.Future? mark_email_async(Gee.List<Geary.EmailIdentifier> to_mark,
+    public virtual async Geary.Future mark_email_async(Gee.List<Geary.EmailIdentifier> to_mark,
         Geary.EmailFlags? flags_to_add, Geary.EmailFlags? flags_to_remove,
         Cancellable? cancellable = null) throws Error {
         check_open("mark_email_async");
@@ -1328,7 +1328,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
         return yield mark.wait_for_ready_async(cancellable);
     }
     
-    public virtual async Geary.Future? copy_email_async(Gee.List<Geary.EmailIdentifier> to_copy,
+    public virtual async Geary.Future copy_email_async(Gee.List<Geary.EmailIdentifier> to_copy,
         Geary.FolderPath destination, Cancellable? cancellable = null) throws Error {
         return yield copy_email_uids_async(to_copy, destination, null, cancellable);
     }
@@ -1338,7 +1338,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
      *
      * If returned Future is non-null, must wait for Future to fulfill to get destination UIDs.
      */
-    public async Geary.Future? copy_email_uids_async(Gee.List<Geary.EmailIdentifier> to_copy,
+    public async Geary.Future copy_email_uids_async(Gee.List<Geary.EmailIdentifier> to_copy,
         Geary.FolderPath destination, out Gee.Set<Imap.UID>? destination_uids,
         Cancellable? cancellable = null) throws Error {
         check_open("copy_email_uids_async");
@@ -1348,14 +1348,16 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
         if (destination.equal_to(path)) {
             destination_uids = null;
             
+            // FIX
             return null;
         }
         
         CopyEmail copy = new CopyEmail(this, (Gee.List<ImapDB.EmailIdentifier>) to_copy, destination);
         replay_queue.schedule(copy);
         
-        Geary.Future? future = yield copy.wait_for_ready_async(cancellable);
+        Geary.Future future = yield copy.wait_for_ready_async(cancellable);
         
+        // TODO: Fix
         if (future != null)
             destination_uids = copy.destination_uids.size > 0 ? copy.destination_uids : null;
         else
@@ -1364,7 +1366,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
         return future;
     }
 
-    public virtual async Geary.Future? move_email_async(Gee.List<Geary.EmailIdentifier> to_move,
+    public virtual async Geary.Future move_email_async(Gee.List<Geary.EmailIdentifier> to_move,
         Geary.FolderPath destination, Cancellable? cancellable = null) throws Error {
         check_open("move_email_async");
         check_ids("move_email_async", to_move);
@@ -1417,7 +1419,10 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
         
         replay_queue.schedule(op);
         
-        yield op.wait_for_ready_async(cancellable);
+        // Unlike the list operations, need to wait on the future because ServerSearchEmail will
+        // retry until completed
+        Geary.Future future = yield op.wait_for_ready_async(cancellable);
+        yield future.wait_for_fulfillment_async(cancellable);
         
         // find earliest ID; because all Email comes from Folder, UID should always be present
         ImapDB.EmailIdentifier? earliest_id = null;
@@ -1434,7 +1439,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
         return earliest_id;
     }
     
-    protected async Geary.Future? create_email_async(RFC822.Message rfc822, Geary.EmailFlags? flags,
+    protected async Geary.Future create_email_async(RFC822.Message rfc822, Geary.EmailFlags? flags,
         DateTime? date_received, Geary.EmailIdentifier? id, out Geary.EmailIdentifier? created_id,
         Cancellable? cancellable = null) throws Error {
         check_open("create_email_async");
@@ -1443,12 +1448,14 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
         
         Error? cancel_error = null;
         Geary.Future? future = null;
+        Geary.EmailIdentifier? ret = null;
         try {
             CreateEmail create = new CreateEmail(this, rfc822, flags, date_received, cancellable);
             replay_queue.schedule(create);
             
             future = yield create.wait_for_ready_async(cancellable);
-            ret = create.created_id ++
+            if (future != null)
+                ret = (Geary.EmailIdentifier?) yield future.wait_for_fulfillment_async(cancellable);
         } catch (Error e) {
             if (e is IOError.CANCELLED)
                 cancel_error = e;
diff --git a/src/engine/imap-engine/imap-engine-replay-operation.vala 
b/src/engine/imap-engine/imap-engine-replay-operation.vala
index 0cba71c..8d11766 100644
--- a/src/engine/imap-engine/imap-engine-replay-operation.vala
+++ b/src/engine/imap-engine/imap-engine-replay-operation.vala
@@ -46,13 +46,14 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject {
     public bool notified { get { return semaphore.is_passed(); } }
     
     private Nonblocking.Semaphore semaphore = new Nonblocking.Semaphore();
-    private Geary.Future? future = null;
+    private Geary.Future future;
     
     public ReplayOperation(string name, Scope scope, OnError on_remote_error = OnError.THROW) {
         this.name = name;
         opnum = next_opnum++;
         this.scope = scope;
         this.on_remote_error = on_remote_error;
+        future = new Geary.Future(name);
     }
     
     /**
@@ -103,6 +104,10 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject {
     /**
      * See Scope for conditions where this method will be called.
      *
+     * This result is used to fulfill the { link Future} that is ultimately returned by to the
+     * caller.  It will be ignored if the call throws an Error or returns anything other than
+     * Status.COMPLETED.
+     *
      * Returns:
      *   COMPLETED: the operation has completed and no further calls should be made.
      *   CONTINUE: The local operation has completed and the remote portion must be executed as
@@ -116,6 +121,10 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject {
     /**
      * See Scope for conditions where this method will be called.
      *
+     * This result is used to fulfill the { link Future} that is ultimately returned by to the
+     * caller.  It will be ignored if the call throws an Error or returns anything other than
+     * Status.COMPLETED.
+     *
      * Returns:
      *   COMPLETED: the operation has completed and no further calls should be made.
      *   CONTINUE: Treated as COMPLETED.
@@ -126,6 +135,19 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject {
     public abstract async Status replay_remote_async() throws Error;
     
     /**
+     * Returns the final result of the operation as a Value.
+     *
+     * This result is used to fulfill the { link Future} that is ultimately returned by to the
+     * caller.  It will be ignored if the call throws an Error or returns anything other than
+     * Status.COMPLETED.
+     *
+     * Default implementation returns null.
+     */
+    protected virtual Value? get_operation_result() {
+        return null;
+    }
+    
+    /**
      * See Scope, replay_local_async(), and replay_remote_async() for conditions for this where this
      * will be called.
      */
@@ -142,25 +164,24 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject {
      * Returns a Semaphore if the operation is retrying.  The Semaphore will be triggered when the
      * retry completes or errors out.
      */
-    public async Geary.Future? wait_for_ready_async(Cancellable? cancellable = null) throws Error {
+    public async Geary.Future wait_for_ready_async(Cancellable? cancellable = null) throws Error {
         yield semaphore.wait_async(cancellable);
         
-        if (err != null)
-            throw err;
-        
         return future;
     }
     
-    // Can only be called once, although must be called after notify_retrying() is called.
+    // Can only be called once, although must be called after notify_retrying() has been called and
+    // the operation is complete
     internal void notify_ready(Error? err) {
-        if (semaphore.is_passed() && future != null) {
+        if (err != null)
             future.fulfill(null, err);
-            
-            return;
-        }
+        else
+            future.fulfill(get_operation_result(), null);
         
-        // otherwise, if notified but not due to retry, trouble
-        assert(!semaphore.is_passed());
+        // if original call has already been completed and is merely waiting for the future, our
+        // work is done
+        if (semaphore.is_passed())
+            return;
         
         this.err = err;
         
@@ -175,8 +196,8 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject {
     internal void notify_retrying() {
         assert(!semaphore.is_passed());
         
-        future = new Future(name);
-        
+        // Complete the original call but let the caller wait on the Future (if necessary) to get
+        // the final result
         try {
             semaphore.notify();
         } catch (Error notify_err) {
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-create-email.vala 
b/src/engine/imap-engine/replay-ops/imap-engine-create-email.vala
index bb8974b..3f2ab1a 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-create-email.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-create-email.vala
@@ -5,8 +5,7 @@
  */
 
 private class Geary.ImapEngine.CreateEmail : Geary.ImapEngine.SendReplayOperation {
-    public Geary.EmailIdentifier? created_id { get; private set; default = null; }
-    
+    private Geary.EmailIdentifier? created_id = null;
     private MinimalFolder engine;
     private RFC822.Message rfc822;
     private Geary.EmailFlags? flags;
@@ -70,4 +69,8 @@ private class Geary.ImapEngine.CreateEmail : Geary.ImapEngine.SendReplayOperatio
         
         return ReplayOperation.Status.COMPLETED;
     }
+    
+    protected override Value? get_operation_result() {
+        return created_id;
+    }
 }
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-fetch-email.vala 
b/src/engine/imap-engine/replay-ops/imap-engine-fetch-email.vala
index 604af6b..e0cd438 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-fetch-email.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-fetch-email.vala
@@ -5,8 +5,6 @@
  */
 
 private class Geary.ImapEngine.FetchEmail : Geary.ImapEngine.SendReplayOperation {
-    public Email? email = null;
-    
     private MinimalFolder engine;
     private ImapDB.EmailIdentifier id;
     private Email.Field required_fields;
@@ -15,10 +13,12 @@ private class Geary.ImapEngine.FetchEmail : Geary.ImapEngine.SendReplayOperation
     private Cancellable? cancellable;
     private Imap.UID? uid = null;
     private bool remote_removed = false;
+    private Geary.Email? email = null;
     
     public FetchEmail(MinimalFolder engine, ImapDB.EmailIdentifier id, Email.Field required_fields,
         Folder.ListFlags flags, Cancellable? cancellable) {
-        base ("FetchEmail", OnError.IGNORE);
+        // Unlike the list operations, fetch needs to retry remote
+        base ("FetchEmail", OnError.RETRY);
         
         this.engine = engine;
         this.id = id;
@@ -124,6 +124,10 @@ private class Geary.ImapEngine.FetchEmail : Geary.ImapEngine.SendReplayOperation
         return ReplayOperation.Status.COMPLETED;
     }
     
+    protected override Value? get_operation_result() {
+        return email;
+    }
+    
     public override async void backout_local_async() throws Error {
         // read-only
     }
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-replay-append.vala 
b/src/engine/imap-engine/replay-ops/imap-engine-replay-append.vala
index 1950058..9de7fad 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-replay-append.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-replay-append.vala
@@ -5,9 +5,9 @@
  */
 
 private class Geary.ImapEngine.ReplayAppend : Geary.ImapEngine.ReplayOperation {
-    public MinimalFolder owner;
-    public int remote_count;
-    public Gee.List<Imap.SequenceNumber> positions;
+    private MinimalFolder owner;
+    private int remote_count;
+    private Gee.List<Imap.SequenceNumber> positions;
     
     public ReplayAppend(MinimalFolder owner, int remote_count, Gee.List<Imap.SequenceNumber> positions) {
         // IGNORE remote errors because the reconnect will re-normalize the folder, making this
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-replay-disconnect.vala 
b/src/engine/imap-engine/replay-ops/imap-engine-replay-disconnect.vala
index 2a20990..0d2f7e1 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-replay-disconnect.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-replay-disconnect.vala
@@ -5,8 +5,8 @@
  */
 
 private class Geary.ImapEngine.ReplayDisconnect : Geary.ImapEngine.ReplayOperation {
-    public MinimalFolder owner;
-    public Imap.ClientSession.DisconnectReason reason;
+    private MinimalFolder owner;
+    private Imap.ClientSession.DisconnectReason reason;
     
     public ReplayDisconnect(MinimalFolder owner, Imap.ClientSession.DisconnectReason reason) {
         base ("Disconnect", Scope.LOCAL_ONLY);
@@ -49,7 +49,7 @@ private class Geary.ImapEngine.ReplayDisconnect : Geary.ImapEngine.ReplayOperati
     }
     
     public override async ReplayOperation.Status replay_remote_async() throws Error {
-        // shot not be called
+        // should not be called
         return ReplayOperation.Status.COMPLETED;
     }
     
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-replay-removal.vala 
b/src/engine/imap-engine/replay-ops/imap-engine-replay-removal.vala
index 5cacc8f..4fc652b 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-replay-removal.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-replay-removal.vala
@@ -5,9 +5,9 @@
  */
 
 private class Geary.ImapEngine.ReplayRemoval : Geary.ImapEngine.ReplayOperation {
-    public MinimalFolder owner;
-    public int remote_count;
-    public Imap.SequenceNumber position;
+    private MinimalFolder owner;
+    private int remote_count;
+    private Imap.SequenceNumber position;
     
     public ReplayRemoval(MinimalFolder owner, int remote_count, Imap.SequenceNumber position) {
         // remote error will cause folder to reconnect and re-normalize, making this remove moot


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]