[geary/wip/789924-network-transition-redux: 9/10] Require users of MinimalFolder's folder session claim it.
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/789924-network-transition-redux: 9/10] Require users of MinimalFolder's folder session claim it.
- Date: Fri, 26 Jan 2018 03:21:48 +0000 (UTC)
commit 6609b4c353a7739664e91ecd03ddb3491a509081
Author: Michael James Gratton <mike vee net>
Date: Fri Jan 26 13:49:52 2018 +1030
Require users of MinimalFolder's folder session claim it.
This makes MinimalFolder.remote_folder private, replacing it with
claim_remote_session method that waits until one is ready and returns
it. This fixes null object errors when there is no session, i.e. when the
remote server is not available.
* src/engine/imap-engine/imap-engine-minimal-folder.vala (MinimalFolder):
Make remote_folder private, rename to remote_session and update
internal uses. Add claim_remote_session method to allow users to access
a session when one is available, update previous users of remote_folder
to use this instead.
* src/engine/imap-engine/replay-ops/imap-engine-abstract-list-email.vala
(RemoteBatchOperation): Pass in local and remote session objects to the
ctor rather than a MinimalFolder instance so we don't need to keep
re-claiming the remote session. Update call sites.
* src/engine/imap-engine/replay-ops/imap-engine-replay-append.vala
(ReplayAppend): Pass in a cancellable to the ctor so we can cancel
claiming a session and the remote operation, rather than just
hanging. Update call sites.
.../imap-engine/imap-engine-minimal-folder.vala | 55 +++++++++----
.../imap-engine-abstract-list-email.vala | 75 +++++++++++------
.../replay-ops/imap-engine-copy-email.vala | 10 ++-
.../replay-ops/imap-engine-create-email.vala | 19 +++--
.../replay-ops/imap-engine-empty-folder.vala | 12 ++-
.../replay-ops/imap-engine-fetch-email.vala | 7 +-
.../replay-ops/imap-engine-mark-email.vala | 12 ++-
.../replay-ops/imap-engine-move-email-commit.vala | 31 ++++---
.../replay-ops/imap-engine-remove-email.vala | 12 ++-
.../replay-ops/imap-engine-replay-append.vala | 88 ++++++++++----------
.../imap-engine-server-search-email.vala | 10 ++-
11 files changed, 203 insertions(+), 128 deletions(-)
---
diff --git a/src/engine/imap-engine/imap-engine-minimal-folder.vala
b/src/engine/imap-engine/imap-engine-minimal-folder.vala
index 9527a0e..6795c94 100644
--- a/src/engine/imap-engine/imap-engine-minimal-folder.vala
+++ b/src/engine/imap-engine/imap-engine-minimal-folder.vala
@@ -57,7 +57,6 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
public override Geary.ProgressMonitor opening_monitor { get { return _opening_monitor; } }
internal ImapDB.Folder local_folder { get; protected set; }
- internal Imap.FolderSession? remote_folder { get; protected set; default = null; }
internal int remote_count { get; private set; default = -1; }
internal ReplayQueue replay_queue { get; private set; }
@@ -71,6 +70,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
private int open_count = 0;
private TimeoutManager remote_open_timer;
+ private Imap.FolderSession? remote_session = null;
private Nonblocking.ReportingSemaphore<bool> remote_wait_semaphore =
new Nonblocking.ReportingSemaphore<bool>(false);
private Nonblocking.Semaphore closed_semaphore = new Nonblocking.Semaphore();
@@ -182,7 +182,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
if (this.open_count == 0)
return Geary.Folder.OpenState.CLOSED;
- return (this.remote_folder != null)
+ return (this.remote_session != null)
? Geary.Folder.OpenState.BOTH
: Geary.Folder.OpenState.LOCAL;
}
@@ -211,7 +211,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
// even if opened or opening, or if forcing a re-open, respect the NO_DELAY flag
if (open_flags.is_all_set(OpenFlags.NO_DELAY)) {
// add NO_DELAY flag if it forces an open
- if (this.remote_folder == null)
+ if (this.remote_session == null)
this.open_flags |= OpenFlags.NO_DELAY;
this.open_remote_session.begin();
@@ -267,7 +267,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
check_open("wait_for_remote_async");
// if remote has not yet been opened, do it now ...
- if (this.remote_folder == null) {
+ if (this.remote_session == null) {
this.open_remote_session.begin();
}
@@ -275,6 +275,27 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
throw new EngineError.ALREADY_CLOSED("%s failed to open", to_string());
}
+ /**
+ * Returns a valid IMAP folder session when one is available.
+ *
+ * Implementations may use this to acquire an IMAP session for
+ * performing folder-related work. The call will wait until a
+ * connection is established then return the session.
+ *
+ * The session returned is guaranteed to be open upon return,
+ * however may close afterwards due to this folder closing, or the
+ * network connection going away.
+ *
+ * The folder must have been opened before calling this method.
+ */
+ public async Imap.FolderSession claim_remote_session(Cancellable? cancellable = null)
+ throws Error {
+ check_open("claim_remote_session");
+ debug("%s: Acquiring folder session", this.to_string());
+ yield this.wait_for_remote_async(cancellable);
+ return this.remote_session;
+ }
+
/** {@inheritDoc} */
public override async bool close_async(Cancellable? cancellable = null) throws Error {
// Check open_count but only decrement inside of replay queue
@@ -309,13 +330,13 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
}
}
- private async void normalize_folders(Geary.Imap.FolderSession remote_folder,
+ private async void normalize_folders(Geary.Imap.FolderSession session,
Cancellable? cancellable)
throws Error {
debug("%s: Begin normalizing remote and local folders", to_string());
Geary.Imap.FolderProperties local_properties = this.local_folder.get_properties();
- Geary.Imap.FolderProperties remote_properties = remote_folder.folder.properties;
+ Geary.Imap.FolderProperties remote_properties = session.folder.properties;
// and both must have their next UID's (it's possible they don't if it's a non-selectable
// folder)
@@ -453,7 +474,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
check_open("normalize_folders (list local)");
// Do the same on the remote ... make non-null for ease of use later
- Gee.Set<Imap.UID>? remote_uids = yield remote_folder.list_uids_async(
+ Gee.Set<Imap.UID>? remote_uids = yield session.list_uids_async(
new Imap.MessageSet.uid_range(first_uid, last_uid), cancellable);
if (remote_uids == null)
remote_uids = new Gee.HashSet<Imap.UID>();
@@ -510,7 +531,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
// detection)
Gee.List<Imap.MessageSet> msg_sets = Imap.MessageSet.uid_sparse(remote_uids);
foreach (Imap.MessageSet msg_set in msg_sets) {
- Gee.List<Geary.Email>? list = yield remote_folder.list_email_async(msg_set,
+ Gee.List<Geary.Email>? list = yield session.list_email_async(msg_set,
ImapDB.Folder.REQUIRED_FIELDS, cancellable);
if (list != null && list.size > 0)
to_create.add_all(list);
@@ -643,8 +664,8 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
* Unhooks the IMAP folder session and returns it to the account.
*/
internal async void close_remote_session(Folder.CloseReason remote_reason) {
- Imap.FolderSession session = this.remote_folder;
- this.remote_folder = null;
+ Imap.FolderSession session = this.remote_session;
+ this.remote_session = null;
this.remote_count = -1;
notify_closed(remote_reason);
@@ -668,8 +689,8 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
// Close the prefetcher early so it stops using the remote ASAP
this.email_prefetcher.close();
- if (this.remote_folder != null)
- _properties.remove(this.remote_folder.folder.properties);
+ if (this.remote_session != null)
+ _properties.remove(this.remote_session.folder.properties);
// block anyone from wait_for_remote_async(), as this is no longer open
this.remote_wait_semaphore.reset();
@@ -799,7 +820,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
// else having called this just before we did.
if (this.open_count > 0 &&
this._account.session_pool.is_ready &&
- this.remote_folder == null) {
+ this.remote_session == null) {
this.opening_monitor.notify_start();
yield open_remote_session_locked(this.open_cancellable);
@@ -898,7 +919,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
// Phase 3: Move in place and notify waiters
- this.remote_folder = session;
+ this.remote_session = session;
// notify any subscribers with similar information
notify_opened(Geary.Folder.OpenState.BOTH, this.remote_count);
@@ -960,7 +981,9 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
this.remote_count = reported_remote_count;
if (positions.size > 0) {
- ReplayAppend op = new ReplayAppend(this, reported_remote_count, positions);
+ ReplayAppend op = new ReplayAppend(
+ this, reported_remote_count, positions, this.open_cancellable
+ );
op.email_appended.connect(notify_email_appended);
op.email_locally_appended.connect(notify_email_locally_appended);
op.email_count_changed.connect(notify_email_count_changed);
@@ -1210,7 +1233,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
public override string to_string() {
return "%s (open_count=%d remote_opened=%s)".printf(
- base.to_string(), open_count, (remote_folder != null).to_string()
+ base.to_string(), open_count, (this.remote_session != null).to_string()
);
}
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 c58977e..c6aa149 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
@@ -8,56 +8,67 @@
* A base class for building replay operations that list messages.
*/
private abstract class Geary.ImapEngine.AbstractListEmail : Geary.ImapEngine.SendReplayOperation {
+
private static int total_fetches_avoided = 0;
-
+
private class RemoteBatchOperation : Nonblocking.BatchOperation {
// IN
- public MinimalFolder owner;
+ public Imap.FolderSession remote;
+ public ImapDB.Folder local;
public Imap.MessageSet msg_set;
public Geary.Email.Field unfulfilled_fields;
public Geary.Email.Field required_fields;
-
+
// OUT
public Gee.Set<Geary.EmailIdentifier> created_ids = new Gee.HashSet<Geary.EmailIdentifier>();
-
- public RemoteBatchOperation(MinimalFolder owner, Imap.MessageSet msg_set,
- Geary.Email.Field unfulfilled_fields, Geary.Email.Field required_fields) {
- this.owner = owner;
+
+ public RemoteBatchOperation(Imap.FolderSession remote,
+ ImapDB.Folder local,
+ Imap.MessageSet msg_set,
+ Geary.Email.Field unfulfilled_fields,
+ Geary.Email.Field required_fields) {
+ this.remote = remote;
+ this.local = local;
this.msg_set = msg_set;
this.unfulfilled_fields = unfulfilled_fields;
this.required_fields = required_fields;
}
-
+
public override async Object? execute_async(Cancellable? cancellable) throws Error {
// fetch from remote folder
- Gee.List<Geary.Email>? list = yield owner.remote_folder.list_email_async(msg_set,
- unfulfilled_fields, cancellable);
+ Gee.List<Geary.Email>? list = yield this.remote.list_email_async(
+ msg_set, unfulfilled_fields, cancellable
+ );
if (list == null || list.size == 0)
return null;
-
+
// TODO: create_or_merge_email_async() should only write if something has changed
- Gee.Map<Geary.Email, bool> created_or_merged = yield
owner.local_folder.create_or_merge_email_async(
+ Gee.Map<Geary.Email, bool> created_or_merged = yield this.local.create_or_merge_email_async(
list, cancellable);
for (int ctr = 0; ctr < list.size; ctr++) {
Geary.Email email = list[ctr];
-
+
// if created, add to id pool
if (created_or_merged.get(email))
created_ids.add(email.id);
-
+
// if remote email doesn't fulfills all required fields, fetch full and return that
// TODO: Need a sparse ID fetch in ImapDB.Folder to do this all at once
if (!email.fields.fulfills(required_fields)) {
- email = yield owner.local_folder.fetch_email_async((ImapDB.EmailIdentifier) email.id,
- required_fields, ImapDB.Folder.ListFlags.NONE, cancellable);
+ email = yield this.local.fetch_email_async(
+ (ImapDB.EmailIdentifier) email.id,
+ required_fields,
+ ImapDB.Folder.ListFlags.NONE,
+ cancellable
+ );
list[ctr] = email;
}
}
-
+
return list;
}
}
-
+
// The accumulated Email from the list operation. Should only be accessed once the operation
// has completed.
public Gee.List<Geary.Email> accumulator = new Gee.ArrayList<Geary.Email>();
@@ -146,7 +157,10 @@ private abstract class Geary.ImapEngine.AbstractListEmail : Geary.ImapEngine.Sen
Geary.Email.Field, Imap.UID>();
foreach (Imap.UID uid in unfulfilled.keys)
reverse_unfulfilled.set(unfulfilled.get(uid), uid);
-
+
+ Imap.FolderSession remote =
+ yield this.owner.claim_remote_session(cancellable);
+
// schedule operations to remote for each set of email with unfulfilled fields and merge
// in results, pulling out the entire email
Nonblocking.Batch batch = new Nonblocking.Batch();
@@ -154,15 +168,20 @@ private abstract class Geary.ImapEngine.AbstractListEmail : Geary.ImapEngine.Sen
Gee.Collection<Imap.UID> unfulfilled_uids = reverse_unfulfilled.get(unfulfilled_fields);
if (unfulfilled_uids.size == 0)
continue;
-
+
Gee.List<Imap.MessageSet> msg_sets = Imap.MessageSet.uid_sparse(unfulfilled_uids);
foreach (Imap.MessageSet msg_set in msg_sets) {
- RemoteBatchOperation remote_op = new RemoteBatchOperation(owner, msg_set,
- unfulfilled_fields, required_fields);
+ RemoteBatchOperation remote_op = new RemoteBatchOperation(
+ remote,
+ this.owner.local_folder,
+ msg_set,
+ unfulfilled_fields,
+ required_fields
+ );
batch.add(remote_op);
}
}
-
+
yield batch.execute_all_async(cancellable);
batch.throw_first_exception();
@@ -251,9 +270,11 @@ private abstract class Geary.ImapEngine.AbstractListEmail : Geary.ImapEngine.Sen
int64 high_pos = -1;
int64 initial_pos = -1;
+ Imap.FolderSession remote =
+ yield this.owner.claim_remote_session(cancellable);
if (initial_uid != null) {
Gee.Map<Imap.UID, Imap.SequenceNumber>? map =
- yield owner.remote_folder.uid_to_position_async(
+ yield remote.uid_to_position_async(
new Imap.MessageSet.uid(initial_uid), cancellable
);
Imap.SequenceNumber? pos = map.get(initial_uid);
@@ -302,10 +323,10 @@ private abstract class Geary.ImapEngine.AbstractListEmail : Geary.ImapEngine.Sen
owner.to_string(), msg_set.to_string(),
(initial_uid != null) ? initial_uid.to_string() : "(null)", count, actual_count.to_string(),
local_count, remote_count, flags.is_oldest_to_newest().to_string());
-
- Gee.List<Geary.Email>? list = yield owner.remote_folder.list_email_async(msg_set,
+
+ Gee.List<Geary.Email>? list = yield remote.list_email_async(msg_set,
Geary.Email.Field.NONE, cancellable);
-
+
Gee.Set<Imap.UID> uids = new Gee.HashSet<Imap.UID>();
if (list != null) {
// add all the new email to the unfulfilled list, which ensures (when replay_remote_async
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 bcf1b66..8049714 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
@@ -45,17 +45,19 @@ private class Geary.ImapEngine.CopyEmail : Geary.ImapEngine.SendReplayOperation
Gee.Set<Imap.UID>? uids = yield engine.local_folder.get_uids_async(to_copy,
ImapDB.Folder.ListFlags.NONE, cancellable);
-
+
if (uids != null && uids.size > 0) {
Gee.List<Imap.MessageSet> msg_sets = Imap.MessageSet.uid_sparse(uids);
+ Imap.FolderSession remote =
+ yield this.engine.claim_remote_session(cancellable);
foreach (Imap.MessageSet msg_set in msg_sets) {
- Gee.Map<Imap.UID, Imap.UID>? src_dst_uids = yield engine.remote_folder.copy_email_async(
- msg_set, destination, cancellable);
+ Gee.Map<Imap.UID, Imap.UID>? src_dst_uids =
+ yield remote.copy_email_async(msg_set, destination, cancellable);
if (src_dst_uids != null)
destination_uids.add_all(src_dst_uids.values);
}
}
-
+
return ReplayOperation.Status.COMPLETED;
}
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 d62ea7d..3a4ea8a 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
@@ -46,24 +46,29 @@ private class Geary.ImapEngine.CreateEmail : Geary.ImapEngine.SendReplayOperatio
// Deal with cancellable manually since create_email_async cannot be cancelled.
if (cancellable.is_cancelled())
throw new IOError.CANCELLED("CreateEmail op cancelled immediately");
-
+
+ Imap.FolderSession remote =
+ yield this.engine.claim_remote_session(cancellable);
+
// use IMAP APPEND command on remote folders, which doesn't require opening a folder ...
// if retrying after a successful create, rfc822 will be null
if (rfc822 != null)
- created_id = yield engine.remote_folder.create_email_async(rfc822, flags, date_received);
-
+ created_id = yield remote.create_email_async(rfc822, flags, date_received);
+
// because this command retries, the create completed, remove the RFC822 message to prevent
// creating it twice
rfc822 = null;
-
+
// If the user cancelled the operation, we need to wipe the new message to keep this
// operation atomic.
if (cancellable.is_cancelled()) {
if (created_id != null) {
- yield engine.remote_folder.remove_email_async(
- new Imap.MessageSet.uid(((ImapDB.EmailIdentifier) created_id).uid).to_list(), null);
+ yield remote.remove_email_async(
+ new Imap.MessageSet.uid(((ImapDB.EmailIdentifier) created_id).uid).to_list(),
+ null
+ );
}
-
+
throw new IOError.CANCELLED("CreateEmail op cancelled after create");
}
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 b0d9adf..e64e1d0 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
@@ -52,17 +52,19 @@ private class Geary.ImapEngine.EmptyFolder : Geary.ImapEngine.SendReplayOperatio
if (removed_ids != null)
ids.add_all(removed_ids);
}
-
+
public override async ReplayOperation.Status replay_remote_async() throws Error {
// STORE and EXPUNGE using positional addressing: "1:*"
+ Imap.FolderSession remote =
+ yield this.engine.claim_remote_session(cancellable);
Imap.MessageSet msg_set = new Imap.MessageSet.range_to_highest(
new Imap.SequenceNumber(Imap.SequenceNumber.MIN));
-
- yield engine.remote_folder.remove_email_async(msg_set.to_list(), cancellable);
-
+
+ yield remote.remove_email_async(msg_set.to_list(), cancellable);
+
return ReplayOperation.Status.COMPLETED;
}
-
+
public override async void backout_local_async() throws Error {
if (removed_ids != null && removed_ids.size > 0) {
yield engine.local_folder.mark_removed_async(removed_ids, false, 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 580a41d..a6da5c0 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
@@ -90,10 +90,13 @@ private class Geary.ImapEngine.FetchEmail : Geary.ImapEngine.SendReplayOperation
throw new EngineError.NOT_FOUND("Unable to fetch %s in %s (removed from remote)",
id.to_string(), engine.to_string());
}
-
+
+ Imap.FolderSession remote =
+ yield this.engine.claim_remote_session(cancellable);
+
// fetch only the remaining fields from the remote folder (if only pulling partial information,
// will merge at end of this method)
- Gee.List<Geary.Email>? list = yield engine.remote_folder.list_email_async(
+ Gee.List<Geary.Email>? list = yield remote.list_email_async(
new Imap.MessageSet.uid(uid), remaining_fields, cancellable);
if (list == null || list.size != 1)
throw new EngineError.NOT_FOUND("Unable to fetch %s in %s", id.to_string(), engine.to_string());
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 4f326d2..5368671 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
@@ -62,12 +62,16 @@ private class Geary.ImapEngine.MarkEmail : Geary.ImapEngine.SendReplayOperation
// potentially empty due to writebehind operation
if (original_flags.size == 0)
return ReplayOperation.Status.COMPLETED;
-
+
+ Imap.FolderSession remote =
+ yield this.engine.claim_remote_session(cancellable);
+
Gee.List<Imap.MessageSet> msg_sets = Imap.MessageSet.uid_sparse(
ImapDB.EmailIdentifier.to_uids(original_flags.keys));
- yield engine.remote_folder.mark_email_async(msg_sets, flags_to_add, flags_to_remove,
- cancellable);
-
+ yield remote.mark_email_async(
+ msg_sets, flags_to_add, flags_to_remove, cancellable
+ );
+
return ReplayOperation.Status.COMPLETED;
}
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-move-email-commit.vala
b/src/engine/imap-engine/replay-ops/imap-engine-move-email-commit.vala
index 94e719f..57947ab 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-move-email-commit.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-move-email-commit.vala
@@ -50,30 +50,37 @@ private class Geary.ImapEngine.MoveEmailCommit : Geary.ImapEngine.SendReplayOper
if (remaining_msg_sets == null || remaining_msg_sets.size == 0)
return ReplayOperation.Status.COMPLETED;
-
+
+ Imap.FolderSession remote =
+ yield this.engine.claim_remote_session(cancellable);
+
Gee.Iterator<Imap.MessageSet> iter = remaining_msg_sets.iterator();
while (iter.next()) {
// don't use Cancellable throughout I/O operations in order to assure transaction completes
// fully
- if (cancellable != null && cancellable.is_cancelled())
- throw new IOError.CANCELLED("Move email to %s cancelled", engine.remote_folder.to_string());
-
+ if (cancellable != null && cancellable.is_cancelled()) {
+ throw new IOError.CANCELLED(
+ "Move email to %s cancelled", this.destination.to_string()
+ );
+ }
+
Imap.MessageSet msg_set = iter.get();
-
- Gee.Map<Imap.UID, Imap.UID>? map = yield engine.remote_folder.copy_email_async(msg_set,
- destination, null);
+
+ Gee.Map<Imap.UID, Imap.UID>? map = yield remote.copy_email_async(
+ msg_set, destination, null
+ );
if (map != null)
destination_uids.add_all(map.values);
-
- yield engine.remote_folder.remove_email_async(msg_set.to_list(), null);
-
+
+ yield remote.remove_email_async(msg_set.to_list(), null);
+
// completed successfully, remove from list in case of retry
iter.remove();
}
-
+
return ReplayOperation.Status.COMPLETED;
}
-
+
public override async void backout_local_async() throws Error {
if (to_move.size == 0)
return;
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 03e944f..acc60aa 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
@@ -55,21 +55,23 @@ private class Geary.ImapEngine.RemoveEmail : Geary.ImapEngine.SendReplayOperatio
if (removed_ids != null)
ids.add_all(removed_ids);
}
-
+
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.
Gee.List<Imap.MessageSet> msg_sets = Imap.MessageSet.uid_sparse(
ImapDB.EmailIdentifier.to_uids(removed_ids));
- yield engine.remote_folder.remove_email_async(msg_sets, cancellable);
-
+ Imap.FolderSession remote =
+ yield this.engine.claim_remote_session(cancellable);
+ yield remote.remove_email_async(msg_sets, cancellable);
+
return ReplayOperation.Status.COMPLETED;
}
-
+
public override async void backout_local_async() throws Error {
if (removed_ids != null && removed_ids.size > 0) {
yield engine.local_folder.mark_removed_async(removed_ids, false, cancellable);
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 11ab3f7..6091052 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
@@ -9,22 +9,27 @@ private class Geary.ImapEngine.ReplayAppend : Geary.ImapEngine.ReplayOperation {
private MinimalFolder owner;
private int remote_count;
private Gee.List<Imap.SequenceNumber> positions;
+ private Cancellable cancellable;
public signal void email_appended(Gee.Collection<Geary.EmailIdentifier> ids);
public signal void email_locally_appended(Gee.Collection<Geary.EmailIdentifier> ids);
public signal void email_count_changed(int count, Folder.CountChangeReason reason);
- public ReplayAppend(MinimalFolder owner, int remote_count, Gee.List<Imap.SequenceNumber> positions) {
+ public ReplayAppend(MinimalFolder owner,
+ int remote_count,
+ Gee.List<Imap.SequenceNumber> positions,
+ Cancellable cancellable) {
// 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;
this.positions = positions;
+ this.cancellable = cancellable;
}
-
+
public override void notify_remote_removed_position(Imap.SequenceNumber removed) {
Gee.List<Imap.SequenceNumber> new_positions = new Gee.ArrayList<Imap.SequenceNumber>();
foreach (Imap.SequenceNumber? position in positions) {
@@ -58,7 +63,8 @@ private class Geary.ImapEngine.ReplayAppend : Geary.ImapEngine.ReplayOperation {
public override async void backout_local_async() throws Error {
}
- public override async ReplayOperation.Status replay_remote_async() {
+ public override async ReplayOperation.Status replay_remote_async()
+ throws Error {
if (this.positions.size > 0)
yield do_replay_appended_messages();
@@ -74,7 +80,8 @@ private class Geary.ImapEngine.ReplayAppend : Geary.ImapEngine.ReplayOperation {
// properly relative to the end of the message list; once this is done, notify user of new
// messages. If duplicates, create_email_async() will fall through to an updated merge,
// which is exactly what we want.
- private async void do_replay_appended_messages() {
+ private async void do_replay_appended_messages()
+ throws Error {
StringBuilder positions_builder = new StringBuilder("( ");
foreach (Imap.SequenceNumber remote_position in this.positions)
positions_builder.append_printf("%s ", remote_position.to_string());
@@ -85,51 +92,46 @@ private class Geary.ImapEngine.ReplayAppend : Geary.ImapEngine.ReplayOperation {
Gee.HashSet<Geary.EmailIdentifier> created = new Gee.HashSet<Geary.EmailIdentifier>();
Gee.HashSet<Geary.EmailIdentifier> appended = new Gee.HashSet<Geary.EmailIdentifier>();
- try {
- Gee.List<Imap.MessageSet> msg_sets = Imap.MessageSet.sparse(this.positions);
- foreach (Imap.MessageSet msg_set in msg_sets) {
- Gee.List<Geary.Email>? list = yield this.owner.remote_folder.list_email_async(msg_set,
- ImapDB.Folder.REQUIRED_FIELDS, null);
- if (list != null && list.size > 0) {
- debug("%s do_replay_appended_message: %d new messages in %s", to_string(),
- list.size, msg_set.to_string());
-
- // need to report both if it was created (not known before) and appended (which
- // could mean created or simply a known email associated with this folder)
- Gee.Map<Geary.Email, bool> created_or_merged =
- yield this.owner.local_folder.create_or_merge_email_async(list, null);
- foreach (Geary.Email email in created_or_merged.keys) {
- // true means created
- if (created_or_merged.get(email)) {
- debug("%s do_replay_appended_message: appended email ID %s added",
- to_string(), email.id.to_string());
-
- created.add(email.id);
- } else {
- debug("%s do_replay_appended_message: appended email ID %s associated",
- to_string(), email.id.to_string());
- }
-
- appended.add(email.id);
+ Gee.List<Imap.MessageSet> msg_sets = Imap.MessageSet.sparse(this.positions);
+ Imap.FolderSession remote =
+ yield this.owner.claim_remote_session(this.cancellable);
+ foreach (Imap.MessageSet msg_set in msg_sets) {
+ Gee.List<Geary.Email>? list = yield remote.list_email_async(
+ msg_set, ImapDB.Folder.REQUIRED_FIELDS, this.cancellable
+ );
+ if (list != null && list.size > 0) {
+ debug("%s do_replay_appended_message: %d new messages in %s", to_string(),
+ list.size, msg_set.to_string());
+
+ // need to report both if it was created (not known before) and appended (which
+ // could mean created or simply a known email associated with this folder)
+ Gee.Map<Geary.Email, bool> created_or_merged =
+ yield this.owner.local_folder.create_or_merge_email_async(list, this.cancellable);
+ foreach (Geary.Email email in created_or_merged.keys) {
+ // true means created
+ if (created_or_merged.get(email)) {
+ debug("%s do_replay_appended_message: appended email ID %s added",
+ to_string(), email.id.to_string());
+
+ created.add(email.id);
+ } else {
+ debug("%s do_replay_appended_message: appended email ID %s associated",
+ to_string(), email.id.to_string());
}
- } else {
- debug("%s do_replay_appended_message: no new messages in %s", to_string(),
- msg_set.to_string());
+
+ appended.add(email.id);
}
+ } else {
+ debug("%s do_replay_appended_message: no new messages in %s", to_string(),
+ msg_set.to_string());
}
- } catch (Error err) {
- debug("%s do_replay_appended_message: Unable to process: %s",
- to_string(), err.message);
}
// store the reported count, *not* the current count (which is updated outside the of
// the queue) to ensure that updates happen serially and reflect committed local changes
- try {
- yield this.owner.local_folder.update_remote_selected_message_count(this.remote_count, null);
- } catch (Error err) {
- debug("%s do_replay_appended_message: Unable to save appended remote count %d: %s",
- to_string(), this.remote_count, err.message);
- }
+ yield this.owner.local_folder.update_remote_selected_message_count(
+ this.remote_count, this.cancellable
+ );
if (appended.size > 0)
email_appended(appended);
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 3984961..cee124d 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
@@ -29,12 +29,16 @@ private class Geary.ImapEngine.ServerSearchEmail : Geary.ImapEngine.AbstractList
// accumulate nothing, nothing unfulfilled (yet)
return ReplayOperation.Status.CONTINUE;
}
-
+
public override async ReplayOperation.Status replay_remote_async() throws Error {
- Gee.SortedSet<Imap.UID>? uids = yield owner.remote_folder.search_async(criteria, cancellable);
+ Imap.FolderSession remote =
+ yield this.owner.claim_remote_session(this.cancellable);
+ Gee.SortedSet<Imap.UID>? uids = yield remote.search_async(
+ criteria, this.cancellable
+ );
if (uids == null || uids.size == 0)
return ReplayOperation.Status.COMPLETED;
-
+
// if the earliest UID is not in the local store, then need to expand vector to it
Geary.EmailIdentifier? first_id = yield owner.local_folder.get_id_async(uids.first(),
ImapDB.Folder.ListFlags.NONE, cancellable);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]