[geary/wip/remote-retry] Expanded concept to all replay operations and Folder interface
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/remote-retry] Expanded concept to all replay operations and Folder interface
- Date: Fri, 16 Jan 2015 18:19:31 +0000 (UTC)
commit 2b7555dfcd25b3a734c34c5bb9017b52559bc4bd
Author: Jim Nelson <jim yorba org>
Date: Fri Jan 16 10:19:08 2015 -0800
Expanded concept to all replay operations and Folder interface
src/engine/api/geary-folder-supports-archive.vala | 15 +----
src/engine/api/geary-folder-supports-copy.vala | 5 +-
src/engine/api/geary-folder-supports-create.vala | 6 +-
src/engine/api/geary-folder-supports-empty.vala | 5 +-
src/engine/api/geary-folder-supports-mark.vala | 14 ----
src/engine/api/geary-folder-supports-move.vala | 5 +-
src/engine/api/geary-folder-supports-remove.vala | 18 +----
src/engine/api/geary-future.vala | 4 +-
src/engine/api/geary-search-folder.vala | 6 +-
src/engine/app/app-draft-manager.vala | 3 +-
src/engine/imap-db/outbox/smtp-outbox-folder.vala | 4 +-
.../gmail/imap-engine-gmail-all-mail-folder.vala | 4 +-
.../gmail/imap-engine-gmail-drafts-folder.vala | 4 +-
.../gmail/imap-engine-gmail-folder.vala | 23 +++++---
.../gmail/imap-engine-gmail-search-folder.vala | 4 +-
.../gmail/imap-engine-gmail-spam-trash-folder.vala | 8 +-
.../imap-engine/imap-engine-generic-folder.vala | 14 ++--
.../imap-engine/imap-engine-minimal-folder.vala | 63 ++++++++++++-------
.../imap-engine/imap-engine-replay-operation.vala | 20 ++++---
.../imap-engine/imap-engine-replay-queue.vala | 48 ++++++++-------
.../imap-engine-send-replay-operation.vala | 8 +-
.../imap-engine-abstract-list-email.vala | 2 +-
.../replay-ops/imap-engine-copy-email.vala | 2 +-
.../replay-ops/imap-engine-create-email.vala | 2 +-
.../replay-ops/imap-engine-empty-folder.vala | 2 +-
.../replay-ops/imap-engine-fetch-email.vala | 2 +-
.../replay-ops/imap-engine-mark-email.vala | 2 +-
.../replay-ops/imap-engine-move-email.vala | 2 +-
.../replay-ops/imap-engine-remove-email.vala | 5 +-
.../replay-ops/imap-engine-replay-append.vala | 4 +-
.../replay-ops/imap-engine-replay-removal.vala | 3 +-
.../imap-engine-server-search-email.vala | 3 +
32 files changed, 166 insertions(+), 144 deletions(-)
---
diff --git a/src/engine/api/geary-folder-supports-archive.vala
b/src/engine/api/geary-folder-supports-archive.vala
index 9796a76..9cfedb1 100644
--- a/src/engine/api/geary-folder-supports-archive.vala
+++ b/src/engine/api/geary-folder-supports-archive.vala
@@ -19,20 +19,7 @@ public interface Geary.FolderSupport.Archive : Geary.Folder {
*
* The { link Geary.Folder} must be opened prior to attempting this operation.
*/
- public abstract async void 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;
-
- /**
- * Archive one email from the folder.
- *
- * The { link Geary.Folder} must be opened prior to attempting this operation.
- */
- public virtual async void archive_single_email_async(Geary.EmailIdentifier email_id,
- Cancellable? cancellable = null) throws Error {
- Gee.ArrayList<Geary.EmailIdentifier> ids = new Gee.ArrayList<Geary.EmailIdentifier>();
- ids.add(email_id);
-
- yield archive_email_async(ids, cancellable);
- }
}
diff --git a/src/engine/api/geary-folder-supports-copy.vala b/src/engine/api/geary-folder-supports-copy.vala
index 351a16a..eb12b48 100644
--- a/src/engine/api/geary-folder-supports-copy.vala
+++ b/src/engine/api/geary-folder-supports-copy.vala
@@ -19,9 +19,12 @@ 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 Folder must be opened prior to attempting this operation.
*/
- public abstract async void 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 babffe6..54cb9d6 100644
--- a/src/engine/api/geary-folder-supports-create.vala
+++ b/src/engine/api/geary-folder-supports-create.vala
@@ -26,9 +26,9 @@ public interface Geary.FolderSupport.Create : Geary.Folder {
* 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.
+ * message is created. The new message's ID is returned in the { link Future}.
*/
- public abstract async Geary.EmailIdentifier? create_email_async(Geary.RFC822.Message rfc822, EmailFlags?
flags,
- DateTime? date_received, Geary.EmailIdentifier? id = null, Cancellable? cancellable = null) throws
Error;
+ 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 69f1e48..69b48c2 100644
--- a/src/engine/api/geary-folder-supports-empty.vala
+++ b/src/engine/api/geary-folder-supports-empty.vala
@@ -19,7 +19,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.
*/
- public abstract async void 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 4556fa7..eb28a61 100644
--- a/src/engine/api/geary-folder-supports-mark.vala
+++ b/src/engine/api/geary-folder-supports-mark.vala
@@ -21,19 +21,5 @@ public interface Geary.FolderSupport.Mark : Geary.Folder {
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;
-
- /**
- * Adds and removes flags from a single message.
- *
- * The { link Geary.Folder} must be opened prior to attempting this operation.
- */
- public virtual async Geary.Future? mark_single_email_async(Geary.EmailIdentifier to_mark,
- Geary.EmailFlags? flags_to_add, Geary.EmailFlags? flags_to_remove,
- Cancellable? cancellable = null) throws Error {
- Gee.ArrayList<Geary.EmailIdentifier> list = new Gee.ArrayList<Geary.EmailIdentifier>();
- list.add(to_mark);
-
- return yield mark_email_async(list, flags_to_add, flags_to_remove, cancellable);
- }
}
diff --git a/src/engine/api/geary-folder-supports-move.vala b/src/engine/api/geary-folder-supports-move.vala
index 58ededf..a43b4ae 100644
--- a/src/engine/api/geary-folder-supports-move.vala
+++ b/src/engine/api/geary-folder-supports-move.vala
@@ -18,9 +18,12 @@ 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 { link Geary.Folder} must be opened prior to attempting this operation.
*/
- public abstract async void 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 8326fb5..fec1fb5 100644
--- a/src/engine/api/geary-folder-supports-remove.vala
+++ b/src/engine/api/geary-folder-supports-remove.vala
@@ -23,22 +23,12 @@ public interface Geary.FolderSupport.Remove : Geary.Folder {
/**
* Removes the specified emails from the folder.
*
- * The { link Geary.Folder} must be opened prior to attempting this operation.
- */
- public abstract async void remove_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
- Cancellable? cancellable = null) throws Error;
-
- /**
- * Removes one 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 { link Geary.Folder} must be opened prior to attempting this operation.
*/
- public virtual async void remove_single_email_async(Geary.EmailIdentifier email_id,
- Cancellable? cancellable = null) throws Error {
- Gee.ArrayList<Geary.EmailIdentifier> ids = new Gee.ArrayList<Geary.EmailIdentifier>();
- ids.add(email_id);
-
- yield remove_email_async(ids, cancellable);
- }
+ 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-future.vala b/src/engine/api/geary-future.vala
index 9d76cbf..4632239 100644
--- a/src/engine/api/geary-future.vala
+++ b/src/engine/api/geary-future.vala
@@ -5,10 +5,12 @@
*/
/**
- * A generic mechanism for a method to return a result value after completing.
+ * A generic mechanism for a method to return a result value after an asynchronous call completes.
*
* Although designed with Geary's asynchronous interface in mind, this can be expanded for
* synchronous (nonblocking) methods as well.
+ *
+ * See also [[http://c2.com/cgi/wiki?FutureValue]]
*/
public class Geary.Future : BaseObject {
diff --git a/src/engine/api/geary-search-folder.vala b/src/engine/api/geary-search-folder.vala
index c064a62..1beeb8f 100644
--- a/src/engine/api/geary-search-folder.vala
+++ b/src/engine/api/geary-search-folder.vala
@@ -380,12 +380,12 @@ public class Geary.SearchFolder : Geary.AbstractLocalFolder, Geary.FolderSupport
return yield account.local_fetch_email_async(id, required_fields, cancellable);
}
- public virtual async void 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);
if (ids_to_folders == null)
- return;
+ return null;
Gee.MultiMap<Geary.FolderPath, Geary.EmailIdentifier> folders_to_ids
= Geary.Collection.reverse_multi_map<Geary.EmailIdentifier, Geary.FolderPath>(ids_to_folders);
@@ -424,6 +424,8 @@ public class Geary.SearchFolder : Geary.AbstractLocalFolder, Geary.FolderSupport
}
}
}
+
+ return null;
}
/**
diff --git a/src/engine/app/app-draft-manager.vala b/src/engine/app/app-draft-manager.vala
index 985f700..f52f7c7 100644
--- a/src/engine/app/app-draft-manager.vala
+++ b/src/engine/app/app-draft-manager.vala
@@ -423,7 +423,8 @@ public class Geary.App.DraftManager : BaseObject {
if (current_draft_id != null && op.draft == null) {
bool success = false;
try {
- yield remove_support.remove_single_email_async(current_draft_id);
+ yield remove_support.remove_email_async(
+ iterate<EmailIdentifier>(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(),
diff --git a/src/engine/imap-db/outbox/smtp-outbox-folder.vala
b/src/engine/imap-db/outbox/smtp-outbox-folder.vala
index 745967b..85a7991 100644
--- a/src/engine/imap-db/outbox/smtp-outbox-folder.vala
+++ b/src/engine/imap-db/outbox/smtp-outbox-folder.vala
@@ -552,11 +552,13 @@ private class Geary.SmtpOutboxFolder : Geary.AbstractLocalFolder, Geary.FolderSu
notify_email_flags_changed(changed_map);
}
- public virtual async void 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();
yield internal_remove_email_async(email_ids, cancellable);
+
+ return null;
}
// Like remove_email_async(), but can be called even when the folder isn't open
diff --git a/src/engine/imap-engine/gmail/imap-engine-gmail-all-mail-folder.vala
b/src/engine/imap-engine/gmail/imap-engine-gmail-all-mail-folder.vala
index ce46e75..3c42875 100644
--- a/src/engine/imap-engine/gmail/imap-engine-gmail-all-mail-folder.vala
+++ b/src/engine/imap-engine/gmail/imap-engine-gmail-all-mail-folder.vala
@@ -14,8 +14,8 @@ private class Geary.ImapEngine.GmailAllMailFolder : MinimalFolder, FolderSupport
base (account, remote, local, local_folder, special_folder_type);
}
- public async void 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 {
- yield GmailFolder.true_remove_email_async(this, email_ids, cancellable);
+ return yield GmailFolder.true_remove_email_async(this, email_ids, cancellable);
}
}
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 57ea1df..4176f28 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,8 +22,8 @@ private class Geary.ImapEngine.GmailDraftsFolder : MinimalFolder, FolderSupport.
return yield base.create_email_async(rfc822, flags, date_received, id, cancellable);
}
- public async void 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 {
- yield GmailFolder.true_remove_email_async(this, email_ids, cancellable);
+ 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 16e5529..dba3c42 100644
--- a/src/engine/imap-engine/gmail/imap-engine-gmail-folder.vala
+++ b/src/engine/imap-engine/gmail/imap-engine-gmail-folder.vala
@@ -17,14 +17,14 @@ private class Geary.ImapEngine.GmailFolder : MinimalFolder, FolderSupport.Archiv
return yield base.create_email_async(rfc822, flags, date_received, id, cancellable);
}
- public async void 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 {
- yield expunge_email_async(email_ids, cancellable);
+ return yield expunge_email_async(email_ids, cancellable);
}
- public async void 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 {
- yield true_remove_email_async(this, email_ids, cancellable);
+ 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 void 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);
@@ -45,14 +45,19 @@ private class Geary.ImapEngine.GmailFolder : MinimalFolder, FolderSupport.Archiv
// Copy to Trash, collect UIDs (note that copying to Trash is like a move; the copied
// messages are removed from all labels)
- Gee.Set<Imap.UID>? uids = yield folder.copy_email_uids_async(email_ids, trash.path, cancellable);
+ Gee.Set<Imap.UID>? uids;
+ Geary.Future? future = yield folder.copy_email_uids_async(email_ids, trash.path, out uids,
+ cancellable);
+
+ if (future != null)
+ uids = (Gee.Set<Imap.UID>?) yield future.wait_for_fulfillment_async(cancellable);
+
if (uids == null || uids.size == 0) {
debug("%s: Can't true-remove %d emails, no COPYUIDs returned", folder.to_string(),
email_ids.size);
- return;
+ return null;
}
-
// For speed reasons, use a detached Imap.Folder object to delete moved emails; this is a
// separate connection and is not synchronized with the database, but also avoids a full
// folder normalization, which can be a heavyweight operation
@@ -73,6 +78,8 @@ private class Geary.ImapEngine.GmailFolder : MinimalFolder, FolderSupport.Archiv
debug("%s: Successfully true-removed %d/%d emails", folder.to_string(), uids.size,
email_ids.size);
+
+ return null;
}
}
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 18aecee..caebbcd 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 void 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 {
@@ -34,5 +34,7 @@ public class Geary.ImapEngine.GmailSearchFolder : Geary.SearchFolder {
// to fully trash the message.
yield email_store.copy_email_async(email_ids, trash_folder.path, cancellable);
}
+
+ return null;
}
}
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 e9bb552..e82e269 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,13 +16,13 @@ private class Geary.ImapEngine.GmailSpamTrashFolder : MinimalFolder, FolderSuppo
base (account, remote, local, local_folder, special_folder_type);
}
- public async void 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 {
- yield expunge_email_async(email_ids, cancellable);
+ return yield expunge_email_async(email_ids, cancellable);
}
- public async void empty_folder_async(Cancellable? cancellable = null) throws Error {
- yield expunge_all_async(cancellable);
+ 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 2f234af..9cd77a0 100644
--- a/src/engine/imap-engine/imap-engine-generic-folder.vala
+++ b/src/engine/imap-engine/imap-engine-generic-folder.vala
@@ -11,18 +11,18 @@ private class Geary.ImapEngine.GenericFolder : MinimalFolder, Geary.FolderSuppor
base (account, remote, local, local_folder, special_folder_type);
}
- public async void 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 {
- yield expunge_email_async(email_ids, cancellable);
+ return yield expunge_email_async(email_ids, cancellable);
}
- public async void empty_folder_async(Cancellable? cancellable = null) throws Error {
- yield expunge_all_async(cancellable);
+ public async Geary.Future? empty_folder_async(Cancellable? cancellable = null) throws Error {
+ return 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 {
+ 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 a86a327..7b3d5c8 100644
--- a/src/engine/imap-engine/imap-engine-minimal-folder.vala
+++ b/src/engine/imap-engine/imap-engine-minimal-folder.vala
@@ -206,6 +206,11 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
assert(local_earliest_id.has_uid());
assert(local_latest_id.has_uid());
+ //
+ // TODO: Flush retry commands on the ReplayQueue (but not pending commands, as they may
+ // have come in naturally while waiting for open to complete)
+ //
+
// if any messages are still marked for removal from last time, that means the EXPUNGE
// never arrived from the server, in which case the folder is "dirty" and needs a full
// normalization
@@ -1224,8 +1229,8 @@ 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 void expunge_email_async(Gee.List<Geary.EmailIdentifier> email_ids,
- Cancellable? cancellable = null) throws Error {
+ 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);
@@ -1233,16 +1238,16 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
cancellable);
replay_queue.schedule(remove);
- yield remove.wait_for_ready_async(cancellable);
+ return yield remove.wait_for_ready_async(cancellable);
}
- protected async void 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);
replay_queue.schedule(empty_folder);
- yield empty_folder.wait_for_ready_async(cancellable);
+ return yield empty_folder.wait_for_ready_async(cancellable);
}
private void check_open(string method) throws EngineError {
@@ -1278,43 +1283,55 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
return yield mark.wait_for_ready_async(cancellable);
}
- public virtual async void 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 {
- yield copy_email_uids_async(to_copy, destination, cancellable);
+ return yield copy_email_uids_async(to_copy, destination, null, cancellable);
}
/**
* Returns the destination folder's UIDs for the copied messages.
+ *
+ * If returned Future is non-null, must wait for Future to fulfill to get destination UIDs.
*/
- public async Gee.Set<Imap.UID>? copy_email_uids_async(Gee.List<Geary.EmailIdentifier> to_copy,
- Geary.FolderPath destination, Cancellable? cancellable = null) throws Error {
+ 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");
check_ids("copy_email_uids_async", to_copy);
// watch for copying to this folder, which is treated as a no-op
- if (destination.equal_to(path))
+ if (destination.equal_to(path)) {
+ destination_uids = null;
+
return null;
+ }
CopyEmail copy = new CopyEmail(this, (Gee.List<ImapDB.EmailIdentifier>) to_copy, destination);
replay_queue.schedule(copy);
- yield copy.wait_for_ready_async(cancellable);
+ Geary.Future? future = yield copy.wait_for_ready_async(cancellable);
+
+ if (future != null)
+ destination_uids = copy.destination_uids.size > 0 ? copy.destination_uids : null;
+ else
+ destination_uids = null;
- return copy.destination_uids.size > 0 ? copy.destination_uids : null;
+ return future;
}
- public virtual async void 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);
// watch for moving to this folder, which is treated as a no-op
if (destination.equal_to(path))
- return;
+ return null;
MoveEmail move = new MoveEmail(this, (Gee.List<ImapDB.EmailIdentifier>) to_move, destination);
replay_queue.schedule(move);
- yield move.wait_for_ready_async(cancellable);
+
+ return yield move.wait_for_ready_async(cancellable);
}
private void on_email_flags_changed(Gee.Map<Geary.EmailIdentifier, Geary.EmailFlags> changed) {
@@ -1372,21 +1389,21 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
return earliest_id;
}
- 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 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");
if (id != null)
check_id("create_email_async", id);
Error? cancel_error = null;
- Geary.EmailIdentifier? ret = null;
+ Geary.Future? future = 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;
+ future = yield create.wait_for_ready_async(cancellable);
+ ret = create.created_id ++
} catch (Error e) {
if (e is IOError.CANCELLED)
cancel_error = e;
@@ -1398,7 +1415,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
// Remove old message.
if (id != null && remove_folder != null)
- yield remove_folder.remove_single_email_async(id, null);
+ yield remove_folder.remove_email_async(iterate<EmailIdentifier>(id).to_array_list());
// If the user cancelled the operation, throw the error here.
if (cancel_error != null)
@@ -1407,7 +1424,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
// 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_single_email_async(ret, null);
+ yield remove_folder.remove_email_async(iterate<EmailIdentifier>(ret).to_array_list());
return ret;
}
diff --git a/src/engine/imap-engine/imap-engine-replay-operation.vala
b/src/engine/imap-engine/imap-engine-replay-operation.vala
index e5cf26b..0cba71c 100644
--- a/src/engine/imap-engine/imap-engine-replay-operation.vala
+++ b/src/engine/imap-engine/imap-engine-replay-operation.vala
@@ -29,10 +29,10 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject {
CONTINUE
}
- [Flags]
- public enum Retry {
- NONE = 0,
- REMOTE
+ public enum OnError {
+ THROW,
+ RETRY,
+ IGNORE
}
private static int next_opnum = 0;
@@ -40,19 +40,19 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject {
public string name { get; set; }
public int opnum { get; private set; }
public Scope scope { get; private set; }
- public Retry retry { get; protected set; }
- public int retry_count { get; set; default = 0; }
+ public OnError on_remote_error { get; protected set; }
+ public int remote_retry_count { get; set; default = 0; }
public Error? err { get; private set; default = null; }
public bool notified { get { return semaphore.is_passed(); } }
private Nonblocking.Semaphore semaphore = new Nonblocking.Semaphore();
private Geary.Future? future = null;
- public ReplayOperation(string name, Scope scope, Retry retry = Retry.NONE) {
+ public ReplayOperation(string name, Scope scope, OnError on_remote_error = OnError.THROW) {
this.name = name;
opnum = next_opnum++;
this.scope = scope;
- this.retry = retry;
+ this.on_remote_error = on_remote_error;
}
/**
@@ -135,6 +135,10 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject {
* Completes when the operation has completed execution. If the operation threw an error
* during execution, it will be thrown here.
*
+ * TODO: Always return a Future and require returning results to be fetched from the Future.
+ * Child classes must supply a fulfill_future() override method that does the right thing for
+ * the operation. Or...they just know to do it.
+ *
* Returns a Semaphore if the operation is retrying. The Semaphore will be triggered when the
* retry completes or errors out.
*/
diff --git a/src/engine/imap-engine/imap-engine-replay-queue.vala
b/src/engine/imap-engine/imap-engine-replay-queue.vala
index f3c4ff4..7939396 100644
--- a/src/engine/imap-engine/imap-engine-replay-queue.vala
+++ b/src/engine/imap-engine/imap-engine-replay-queue.vala
@@ -12,7 +12,7 @@ private class Geary.ImapEngine.ReplayQueue : Geary.BaseObject {
private class CloseReplayQueue : ReplayOperation {
public CloseReplayQueue() {
// LOCAL_AND_REMOTE to make sure this operation is flushed all the way down the pipe
- base ("CloseReplayQueue", ReplayOperation.Scope.LOCAL_AND_REMOTE, ReplayOperation.Retry.NONE);
+ base ("CloseReplayQueue", ReplayOperation.Scope.LOCAL_AND_REMOTE, OnError.IGNORE);
}
public override void notify_remote_removed_position(Imap.SequenceNumber removed) {
@@ -50,10 +50,9 @@ private class Geary.ImapEngine.ReplayQueue : Geary.BaseObject {
} }
private weak MinimalFolder owner;
- private Nonblocking.Mailbox<ReplayOperation> local_queue = new Nonblocking.Mailbox<ReplayOperation>(
- replay_operation_comparator);
+ private Nonblocking.Mailbox<ReplayOperation> local_queue = new Nonblocking.Mailbox<ReplayOperation>();
private Nonblocking.Mailbox<ReplayOperation> remote_queue = new Nonblocking.Mailbox<ReplayOperation>(
- replay_operation_comparator);
+ remote_replay_operation_comparator);
private ReplayOperation? local_op_active = null;
private ReplayOperation? remote_op_active = null;
private Gee.ArrayList<ReplayOperation> notification_queue = new Gee.ArrayList<ReplayOperation>();
@@ -346,8 +345,8 @@ private class Geary.ImapEngine.ReplayQueue : Geary.BaseObject {
}
}
- private static int replay_operation_comparator(ReplayOperation a, ReplayOperation b) {
- return a.retry_count - b.retry_count;
+ private static int remote_replay_operation_comparator(ReplayOperation a, ReplayOperation b) {
+ return a.remote_retry_count - b.remote_retry_count;
}
private async void do_replay_local_async() {
@@ -421,9 +420,6 @@ private class Geary.ImapEngine.ReplayQueue : Geary.BaseObject {
}
}
- // completed one way or another, clear retry count for next round
- op.retry_count = 0;
-
if (remote_enqueue) {
if (!remote_queue.send(op)) {
debug("Unable to enqueue operation %s for %s remote operation", op.to_string(),
@@ -492,34 +488,42 @@ private class Geary.ImapEngine.ReplayQueue : Geary.BaseObject {
Error? remote_err = null;
if (folder_opened || is_close_op) {
- if (op.retry_count > 0) {
- debug("RETRYING OP %s on %s: retry_count=%d", op.to_string(), to_string(),
- op.retry_count);
+ if (op.remote_retry_count > 0) {
+ debug("Retrying op %s on %s: retry_count=%d", op.to_string(), to_string(),
+ op.remote_retry_count);
}
try {
yield op.replay_remote_async();
} catch (Error replay_err) {
- debug("Replay remote error for %s on %s: %s", op.to_string(), to_string(),
- replay_err.message);
+ debug("Replay remote error for %s on %s: %s (%s)", op.to_string(), to_string(),
+ replay_err.message, op.on_remote_error.to_string());
// If a hard failure and operation allows remote replay, schedule now
- if (is_hard_failure(replay_err) && (op.retry & ReplayOperation.Retry.REMOTE) != 0) {
- debug("SCHEDULING RETRY OP %s on %s: retry_count=%d", op.to_string(),
- to_string(), op.retry_count);
+ if ((op.on_remote_error == ReplayOperation.OnError.RETRY) &&
is_hard_failure(replay_err)) {
+ debug("Schedule op retry %s on %s: remote_retry_count=%d", op.to_string(),
+ to_string(), op.remote_retry_count);
// if this is the first retry, complete the waiting async caller but allow
- // them to wait later or be signaled when completed
- if (op.retry_count == 0)
+ // them to wait later or be signaled when completed ... this returns to the
+ // original caller a Future they can use to be notified of final results
+ if (op.remote_retry_count == 0)
op.notify_retrying();
- op.retry_count++;
+ // use the retry count to sort the command at the top of the queue and
+ // take another go at it ... the Folder will disconnect and reconnect due
+ // to the hard error and wait_for_open_async() will block this command until
+ // reconnected and normalized
+ op.remote_retry_count++;
remote_queue.send(op);
continue;
+ } else if (op.on_remote_error == ReplayOperation.OnError.IGNORE) {
+ // ignoring error, simply notify as completed and continue
+ } else {
+ // store for notification
+ remote_err = replay_err;
}
-
- remote_err = replay_err;
}
} else if (!is_close_op) {
remote_err = new EngineError.SERVER_UNAVAILABLE("Folder %s not available",
owner.to_string());
diff --git a/src/engine/imap-engine/imap-engine-send-replay-operation.vala
b/src/engine/imap-engine/imap-engine-send-replay-operation.vala
index dcfc041..5ae0dce 100644
--- a/src/engine/imap-engine/imap-engine-send-replay-operation.vala
+++ b/src/engine/imap-engine/imap-engine-send-replay-operation.vala
@@ -5,12 +5,12 @@
*/
private abstract class Geary.ImapEngine.SendReplayOperation : Geary.ImapEngine.ReplayOperation {
- public SendReplayOperation(string name, ReplayOperation.Retry retry = ReplayOperation.Retry.NONE) {
- base (name, ReplayOperation.Scope.LOCAL_AND_REMOTE, retry);
+ public SendReplayOperation(string name, ReplayOperation.OnError on_remote_error = OnError.THROW) {
+ base (name, ReplayOperation.Scope.LOCAL_AND_REMOTE, on_remote_error);
}
- public SendReplayOperation.only_remote(string name, ReplayOperation.Retry retry =
ReplayOperation.Retry.NONE) {
- base (name, ReplayOperation.Scope.REMOTE_ONLY, retry);
+ public SendReplayOperation.only_remote(string name, ReplayOperation.OnError on_remote_error =
OnError.THROW) {
+ base (name, ReplayOperation.Scope.REMOTE_ONLY, on_remote_error);
}
public override void notify_remote_removed_position(Imap.SequenceNumber removed) {
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-abstract-list-email.vala
b/src/engine/imap-engine/replay-ops/imap-engine-abstract-list-email.vala
index 758c29b..15243a7 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-abstract-list-email.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-abstract-list-email.vala
@@ -66,7 +66,7 @@ private abstract class Geary.ImapEngine.AbstractListEmail : Geary.ImapEngine.Sen
public AbstractListEmail(string name, MinimalFolder owner, Geary.Email.Field required_fields,
Folder.ListFlags flags, Cancellable? cancellable) {
- base(name);
+ base(name, OnError.IGNORE);
this.owner = owner;
this.required_fields = required_fields;
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-copy-email.vala
b/src/engine/imap-engine/replay-ops/imap-engine-copy-email.vala
index f054780..703a0c3 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-copy-email.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-copy-email.vala
@@ -14,7 +14,7 @@ private class Geary.ImapEngine.CopyEmail : Geary.ImapEngine.SendReplayOperation
public CopyEmail(MinimalFolder engine, Gee.List<ImapDB.EmailIdentifier> to_copy,
Geary.FolderPath destination, Cancellable? cancellable = null) {
- base("CopyEmail");
+ base("CopyEmail", OnError.RETRY);
this.engine = engine;
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 3750ff0..bb8974b 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
@@ -15,7 +15,7 @@ private class Geary.ImapEngine.CreateEmail : Geary.ImapEngine.SendReplayOperatio
public CreateEmail(MinimalFolder engine, RFC822.Message rfc822, Geary.EmailFlags? flags,
DateTime? date_received, Cancellable? cancellable) {
- base.only_remote("CreateEmail");
+ base.only_remote("CreateEmail", OnError.RETRY);
this.engine = engine;
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-empty-folder.vala
b/src/engine/imap-engine/replay-ops/imap-engine-empty-folder.vala
index 1cf774a..05aedb4 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-empty-folder.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-empty-folder.vala
@@ -16,7 +16,7 @@ private class Geary.ImapEngine.EmptyFolder : Geary.ImapEngine.SendReplayOperatio
private int original_count = 0;
public EmptyFolder(MinimalFolder engine, Cancellable? cancellable) {
- base("EmptyFolder");
+ base("EmptyFolder", OnError.RETRY);
this.engine = engine;
this.cancellable = cancellable;
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 a6090fd..604af6b 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
@@ -18,7 +18,7 @@ private class Geary.ImapEngine.FetchEmail : Geary.ImapEngine.SendReplayOperation
public FetchEmail(MinimalFolder engine, ImapDB.EmailIdentifier id, Email.Field required_fields,
Folder.ListFlags flags, Cancellable? cancellable) {
- base ("FetchEmail");
+ base ("FetchEmail", OnError.IGNORE);
this.engine = engine;
this.id = id;
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-mark-email.vala
b/src/engine/imap-engine/replay-ops/imap-engine-mark-email.vala
index f7c6069..aa3c019 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-mark-email.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-mark-email.vala
@@ -15,7 +15,7 @@ private class Geary.ImapEngine.MarkEmail : Geary.ImapEngine.SendReplayOperation
public MarkEmail(MinimalFolder engine, Gee.List<Geary.EmailIdentifier> to_mark,
Geary.EmailFlags? flags_to_add, Geary.EmailFlags? flags_to_remove,
Cancellable? cancellable = null) {
- base("MarkEmail", Retry.REMOTE);
+ base("MarkEmail", OnError.RETRY);
this.engine = engine;
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-move-email.vala
b/src/engine/imap-engine/replay-ops/imap-engine-move-email.vala
index 6be265d..45a1a60 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-move-email.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-move-email.vala
@@ -14,7 +14,7 @@ private class Geary.ImapEngine.MoveEmail : Geary.ImapEngine.SendReplayOperation
public MoveEmail(MinimalFolder engine, Gee.List<ImapDB.EmailIdentifier> to_move,
Geary.FolderPath destination, Cancellable? cancellable = null) {
- base("MoveEmail");
+ base("MoveEmail", OnError.RETRY);
this.engine = engine;
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-remove-email.vala
b/src/engine/imap-engine/replay-ops/imap-engine-remove-email.vala
index 95cbed8..979c6f9 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-remove-email.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-remove-email.vala
@@ -13,7 +13,7 @@ private class Geary.ImapEngine.RemoveEmail : Geary.ImapEngine.SendReplayOperatio
public RemoveEmail(MinimalFolder engine, Gee.List<ImapDB.EmailIdentifier> to_remove,
Cancellable? cancellable = null) {
- base("RemoveEmail");
+ base("RemoveEmail", OnError.RETRY);
this.engine = engine;
@@ -57,6 +57,9 @@ private class Geary.ImapEngine.RemoveEmail : Geary.ImapEngine.SendReplayOperatio
}
public override async ReplayOperation.Status replay_remote_async() throws Error {
+ if (removed_ids.size == 0)
+ return ReplayOperation.Status.COMPLETED;
+
// Remove from server. Note that this causes the receive replay queue to kick into
// action, removing the e-mail but *NOT* firing a signal; the "remove marker" indicates
// that the signal has already been fired.
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 6d561be..1950058 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
@@ -10,7 +10,9 @@ private class Geary.ImapEngine.ReplayAppend : Geary.ImapEngine.ReplayOperation {
public Gee.List<Imap.SequenceNumber> positions;
public ReplayAppend(MinimalFolder owner, int remote_count, Gee.List<Imap.SequenceNumber> positions) {
- base ("Append", Scope.REMOTE_ONLY);
+ // IGNORE remote errors because the reconnect will re-normalize the folder, making this
+ // append moot
+ base ("Append", Scope.REMOTE_ONLY, OnError.IGNORE);
this.owner = owner;
this.remote_count = remote_count;
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 eeea5e2..5cacc8f 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
@@ -10,7 +10,8 @@ private class Geary.ImapEngine.ReplayRemoval : Geary.ImapEngine.ReplayOperation
public Imap.SequenceNumber position;
public ReplayRemoval(MinimalFolder owner, int remote_count, Imap.SequenceNumber position) {
- base ("Removal", Scope.LOCAL_AND_REMOTE);
+ // remote error will cause folder to reconnect and re-normalize, making this remove moot
+ base ("Removal", Scope.LOCAL_AND_REMOTE, OnError.IGNORE);
this.owner = owner;
this.remote_count = remote_count;
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-server-search-email.vala
b/src/engine/imap-engine/replay-ops/imap-engine-server-search-email.vala
index 5b1443d..b8d6f5d 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-server-search-email.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-server-search-email.vala
@@ -19,6 +19,9 @@ private class Geary.ImapEngine.ServerSearchEmail : Geary.ImapEngine.AbstractList
base ("ServerSearchEmail", owner, required_fields, Geary.Folder.ListFlags.OLDEST_TO_NEWEST,
cancellable);
+ // unlike list, need to retry this as there's no local component to return
+ on_remote_error = OnError.RETRY;
+
this.criteria = criteria;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]