[geary/wip/improve-claiming-folder-session: 3/9] Tidy up ReplayOperation API
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/improve-claiming-folder-session: 3/9] Tidy up ReplayOperation API
- Date: Mon, 19 Nov 2018 13:35:27 +0000 (UTC)
commit 7b4f30c41b5bced6de32f1f4ad36b6204ae2d8c9
Author: Michael Gratton <mike vee net>
Date: Sun Nov 11 07:52:57 2018 +1100
Tidy up ReplayOperation API
Make most abstract methods virtual and provide appropriate no-op impls
to simplify subclasses. Add a FolderSession arg to replay local_async
since in 90% of the cases the operations needs one and since this makes
the queue itself the only remaining user of
MinimalFolder.claim_remote_session async, pending its removal.
Also tidyied up ListEmailById so there is no chance of the local op
executing a remote call.
.../imap-engine/imap-engine-replay-operation.vala | 57 ++++++++++++----
.../imap-engine/imap-engine-replay-queue.vala | 50 +++++++--------
.../imap-engine-abstract-list-email.vala | 63 ++++--------------
.../replay-ops/imap-engine-copy-email.vala | 46 ++++++-------
.../replay-ops/imap-engine-create-email.vala | 58 +++++++----------
.../replay-ops/imap-engine-empty-folder.vala | 11 +---
.../replay-ops/imap-engine-fetch-email.vala | 22 ++-----
.../replay-ops/imap-engine-list-email-by-id.vala | 75 +++++++++++++---------
.../replay-ops/imap-engine-mark-email.vala | 32 ++++-----
.../replay-ops/imap-engine-move-email-commit.vala | 70 +++++++++-----------
.../replay-ops/imap-engine-move-email-prepare.vala | 13 +---
.../replay-ops/imap-engine-move-email-revoke.vala | 13 +---
.../replay-ops/imap-engine-remove-email.vala | 25 ++++----
.../replay-ops/imap-engine-replay-append.vala | 28 ++------
.../replay-ops/imap-engine-replay-removal.vala | 7 +-
.../replay-ops/imap-engine-replay-update.vala | 16 -----
.../imap-engine-server-search-email.vala | 29 +++++----
.../replay-ops/imap-engine-user-close.vala | 28 +++-----
18 files changed, 264 insertions(+), 379 deletions(-)
---
diff --git a/src/engine/imap-engine/imap-engine-replay-operation.vala
b/src/engine/imap-engine/imap-engine-replay-operation.vala
index 9cecd2b0..8047e389 100644
--- a/src/engine/imap-engine/imap-engine-replay-operation.vala
+++ b/src/engine/imap-engine/imap-engine-replay-operation.vala
@@ -60,7 +60,7 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject, Gee.
this.scope = scope;
this.on_remote_error = on_remote_error;
}
-
+
/**
* Notify the operation that a message has been removed by position (SequenceNumber).
*
@@ -72,8 +72,10 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject, Gee.
*
* This won't be called while replay_local_async() or replay_remote_async() are executing.
*/
- public abstract void notify_remote_removed_position(Imap.SequenceNumber removed);
-
+ public virtual void notify_remote_removed_position(Imap.SequenceNumber removed) {
+ // noop
+ }
+
/**
* Notify the operation that a message has been removed by UID (EmailIdentifier).
*
@@ -90,8 +92,10 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject, Gee.
*
* This won't be called while replay_local_async() or replay_remote_async() are executing.
*/
- public abstract void notify_remote_removed_ids(Gee.Collection<ImapDB.EmailIdentifier> ids);
-
+ public virtual void notify_remote_removed_ids(Gee.Collection<ImapDB.EmailIdentifier> ids) {
+ // noop
+ }
+
/**
* Add to the Collection EmailIdentifiers that will be removed in replay_remote_async().
*
@@ -104,12 +108,16 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject, Gee.
* invocation (i.e. the Folder closed before the server could notify the engine that they were
* removed).
*/
- public abstract void get_ids_to_be_remote_removed(Gee.Collection<ImapDB.EmailIdentifier> ids);
-
+ public virtual void get_ids_to_be_remote_removed(Gee.Collection<ImapDB.EmailIdentifier> ids) {
+ // noop
+ }
+
/**
+ * Executes the local parts of this operation, if any.
+ *
* See Scope for conditions where this method will be called.
*
- * If an error is thrown, {@link backout_local_async} will will
+ * If an error is thrown, {@link backout_local_async} will
* *not* be executed.
*
* @return {@link Status.COMPLETED} if the operation has completed
@@ -118,11 +126,22 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject, Gee.
* remote portion must be executed as well. This is treated as
* `COMPLETED` if get_scope() returns {@link Scope.LOCAL_ONLY}.
*/
- public abstract async Status replay_local_async() throws Error;
+ public virtual async Status replay_local_async()
+ throws GLib.Error {
+ if (this.scope != Scope.REMOTE_ONLY) {
+ throw new GLib.IOError.NOT_SUPPORTED("Local operation is not implemented");
+ }
+ return (this.scope == Scope.LOCAL_ONLY)
+ ? Status.COMPLETED : Status.CONTINUE;
+ }
/**
+ * Executes the remote parts of this operation, if any.
+ *
* See Scope for conditions where this method will be called.
*
+ * Passed a folder session with the current folder selected.
+ *
* If an error is thrown, {@link backout_local_async} will be
* executed only if scope is LOCAL_AND_REMOTE.
*
@@ -131,14 +150,24 @@ private abstract class Geary.ImapEngine.ReplayOperation : Geary.BaseObject, Gee.
* Status.CONTINUE} if treated as `COMPLETED`.
*
*/
- public abstract async Status replay_remote_async() throws Error;
+ public virtual async void replay_remote_async(Imap.FolderSession remote)
+ throws GLib.Error {
+ if (this.scope != Scope.LOCAL_ONLY) {
+ throw new GLib.IOError.NOT_SUPPORTED("Remote operation is not implemented");
+ }
+ }
/**
- * See Scope, replay_local_async(), and replay_remote_async() for conditions for this where this
- * will be called.
+ * Reverts any local effects of this operation.
+ *
+ * See {@link Scope}, {@link replay_local_async}, and {@link
+ * replay_remote_async} for conditions for this where this will be
+ * called.
*/
- public abstract async void backout_local_async() throws Error;
-
+ public virtual async void backout_local_async() throws Error {
+ // noop
+ }
+
/**
* Completes when the operation has completed execution. If the operation threw an error
* during execution, it will be thrown here.
diff --git a/src/engine/imap-engine/imap-engine-replay-queue.vala
b/src/engine/imap-engine/imap-engine-replay-queue.vala
index 6457ef79..b565971d 100644
--- a/src/engine/imap-engine/imap-engine-replay-queue.vala
+++ b/src/engine/imap-engine/imap-engine-replay-queue.vala
@@ -21,36 +21,32 @@ private class Geary.ImapEngine.ReplayQueue : Geary.BaseObject {
CLOSING,
CLOSED
}
-
+
private class CloseReplayQueue : ReplayOperation {
+
+ bool local_closed = false;
+ bool remote_closed = false;
+
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, OnError.IGNORE);
}
-
- public override void notify_remote_removed_position(Imap.SequenceNumber removed) {
- }
-
- public override void notify_remote_removed_ids(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
- public override void get_ids_to_be_remote_removed(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
- public override async ReplayOperation.Status replay_local_async() throws Error {
+
+ public override async ReplayOperation.Status replay_local_async()
+ throws GLib.Error {
+ this.local_closed = true;
return Status.CONTINUE;
}
-
- public override async ReplayOperation.Status replay_remote_async() throws Error {
- return Status.COMPLETED;
- }
-
- public override async void backout_local_async() throws Error {
- // nothing to backout (and should never be called, to boot)
+
+ public override async void replay_remote_async(Imap.FolderSession remote)
+ throws GLib.Error {
+ this.remote_closed = true;
}
-
+
public override string describe_state() {
- return "";
+ return "local_closed: %s, remote_closed: %s".printf(
+ this.local_closed.to_string(), this.remote_closed.to_string()
+ );
}
}
@@ -492,9 +488,13 @@ private class Geary.ImapEngine.ReplayQueue : Geary.BaseObject {
queue_running = false;
// wait until the remote folder is opened (or throws an exception, in which case closed)
+ Imap.FolderSession? remote = null;
try {
- if (!is_close_op && folder_opened && state == State.OPEN)
- yield owner.claim_remote_session(this.remote_wait_cancellable);
+ if (!is_close_op && folder_opened && state == State.OPEN) {
+ remote = yield owner.claim_remote_session(
+ this.remote_wait_cancellable
+ );
+ }
} catch (Error remote_err) {
debug("Folder %s closed or failed to open, remote replay queue closing: %s",
to_string(), remote_err.message);
@@ -511,9 +511,9 @@ private class Geary.ImapEngine.ReplayQueue : Geary.BaseObject {
if (folder_opened || is_close_op) {
if (op.remote_retry_count > 0)
debug("Retrying op %s on %s", op.to_string(), to_string());
-
+
try {
- yield op.replay_remote_async();
+ yield op.replay_remote_async(remote);
} catch (Error replay_err) {
debug("Replay remote error for %s on %s: %s (%s)", op.to_string(), to_string(),
replay_err.message, op.on_remote_error.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 11974947..d58a232a 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
@@ -127,16 +127,14 @@ private abstract class Geary.ImapEngine.AbstractListEmail : Geary.ImapEngine.Sen
unfulfilled.unset(id.uid);
}
}
-
- public override void get_ids_to_be_remote_removed(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
+
// Child class should execute its own calls *before* calling this base method
- public override async ReplayOperation.Status replay_remote_async() throws Error {
+ public override async void replay_remote_async(Imap.FolderSession remote)
+ throws GLib.Error {
// only deal with unfulfilled email, child class must deal with everything else
if (unfulfilled.size == 0)
- return ReplayOperation.Status.COMPLETED;
-
+ return;
+
// since list and search commands ahead of this one in the queue may have fulfilled some of
// the emails thought to be unfulfilled when first checked locally, look for them now
int fetches_avoided = yield remove_fulfilled_uids_async();
@@ -145,12 +143,12 @@ private abstract class Geary.ImapEngine.AbstractListEmail : Geary.ImapEngine.Sen
debug("[%s] %d previously-fulfilled fetches avoided in list operation, %d total",
owner.to_string(), fetches_avoided, total_fetches_avoided);
-
+
// if all fulfilled, emails were added to accumulator in remove call, so done
if (unfulfilled.size == 0)
- return ReplayOperation.Status.COMPLETED;
+ return;
}
-
+
// convert UID -> needed fields mapping to needed fields -> UIDs, as they can be grouped
// and submitted at same time
Gee.HashMultiMap<Geary.Email.Field, Imap.UID> reverse_unfulfilled = new Gee.HashMultiMap<
@@ -158,9 +156,6 @@ private abstract class Geary.ImapEngine.AbstractListEmail : Geary.ImapEngine.Sen
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();
@@ -206,34 +201,6 @@ private abstract class Geary.ImapEngine.AbstractListEmail : Geary.ImapEngine.Sen
owner.replay_notify_email_inserted(created_ids);
owner.replay_notify_email_locally_inserted(created_ids);
}
-
- return ReplayOperation.Status.COMPLETED;
- }
-
- /**
- * Determines if the owning folder's vector is fully expanded.
- */
- protected async Trillian is_fully_expanded_async() throws Error {
- Trillian is_fully_expanded = Trillian.UNKNOWN;
- if (this.owner.account.is_online) {
- Imap.FolderSession remote =
- yield this.owner.claim_remote_session(this.cancellable);
- int remote_count = remote.folder.properties.email_total;
-
- // include marked for removed in the count in case this is
- // being called while a removal is in process, in which
- // case don't want to expand vector this moment because
- // the vector is in flux
- int local_count_with_marked =
- yield owner.local_folder.get_email_count_async(
- ImapDB.Folder.ListFlags.INCLUDE_MARKED_FOR_REMOVE, cancellable
- );
-
- is_fully_expanded = Trillian.from_boolean(
- local_count_with_marked >= remote_count
- );
- }
- return is_fully_expanded;
}
/**
@@ -250,10 +217,11 @@ private abstract class Geary.ImapEngine.AbstractListEmail : Geary.ImapEngine.Sen
* be examined and added to the messages to be fulfilled if
* needed.
*/
- protected async Gee.Set<Imap.UID>? expand_vector_async(Imap.UID? initial_uid, int count) throws Error {
+ protected async Gee.Set<Imap.UID>? expand_vector_async(Imap.FolderSession remote,
+ Imap.UID? initial_uid,
+ int count)
+ throws GLib.Error {
debug("%s: expanding vector...", owner.to_string());
- Imap.FolderSession remote =
- yield this.owner.claim_remote_session(cancellable);
int remote_count = remote.folder.properties.email_total;
// include marked for removed in the count in case this is being called while a removal
@@ -401,14 +369,9 @@ private abstract class Geary.ImapEngine.AbstractListEmail : Geary.ImapEngine.Sen
return fetch_avoided;
}
-
- public override async void backout_local_async() throws Error {
- // R/O, no backout
- }
-
+
public override string describe_state() {
return "required_fields=%Xh local_only=%s force_update=%s".printf(required_fields,
flags.is_local_only().to_string(), flags.is_force_update().to_string());
}
}
-
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 8049714d..b5140525 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
@@ -26,10 +26,7 @@ private class Geary.ImapEngine.CopyEmail : Geary.ImapEngine.SendReplayOperation
public override void notify_remote_removed_ids(Gee.Collection<ImapDB.EmailIdentifier> ids) {
to_copy.remove_all(ids);
}
-
- public override void get_ids_to_be_remote_removed(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
+
public override async ReplayOperation.Status replay_local_async() throws Error {
if (to_copy.size == 0)
return ReplayOperation.Status.COMPLETED;
@@ -38,35 +35,30 @@ private class Geary.ImapEngine.CopyEmail : Geary.ImapEngine.SendReplayOperation
// existing there.
return ReplayOperation.Status.CONTINUE;
}
-
- public override async ReplayOperation.Status replay_remote_async() throws Error {
- if (to_copy.size == 0)
- return ReplayOperation.Status.COMPLETED;
-
- 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 remote.copy_email_async(msg_set, destination, cancellable);
- if (src_dst_uids != null)
- destination_uids.add_all(src_dst_uids.values);
+ public override async void replay_remote_async(Imap.FolderSession remote)
+ throws GLib.Error {
+ if (to_copy.size > 0) {
+ 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);
+ foreach (Imap.MessageSet msg_set in msg_sets) {
+ 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;
- }
-
- public override async void backout_local_async() throws Error {
- // Nothing to undo.
}
public override string describe_state() {
return "%d email IDs to %s".printf(to_copy.size, destination.to_string());
}
-}
+}
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 3a4ea8a8..9cd5a89a 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
@@ -24,32 +24,13 @@ private class Geary.ImapEngine.CreateEmail : Geary.ImapEngine.SendReplayOperatio
this.date_received = date_received;
this.cancellable = cancellable;
}
-
- public override async ReplayOperation.Status replay_local_async() throws Error {
- return ReplayOperation.Status.CONTINUE;
- }
-
- public override void notify_remote_removed_ids(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
- public override void get_ids_to_be_remote_removed(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
- public override async void backout_local_async() throws Error {
- }
-
- public override string describe_state() {
- return "";
- }
-
- public override async ReplayOperation.Status replay_remote_async() throws Error {
+
+ public override async void replay_remote_async(Imap.FolderSession remote)
+ throws GLib.Error {
// 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)
@@ -71,19 +52,24 @@ private class Geary.ImapEngine.CreateEmail : Geary.ImapEngine.SendReplayOperatio
throw new IOError.CANCELLED("CreateEmail op cancelled after create");
}
-
- if (created_id == null)
- return ReplayOperation.Status.COMPLETED;
-
- // TODO: need to prevent gaps that may occur here
- Geary.Email created = new Geary.Email(created_id);
- Gee.Map<Geary.Email, bool> results = yield engine.local_folder.create_or_merge_email_async(
- Geary.iterate<Geary.Email>(created).to_array_list(), cancellable);
- if (results.size > 0)
- created_id = Collection.get_first<Geary.Email>(results.keys).id;
- else
- created_id = null;
-
- return ReplayOperation.Status.COMPLETED;
+
+ if (created_id != null) {
+ // TODO: need to prevent gaps that may occur here
+ Geary.Email created = new Geary.Email(created_id);
+ Gee.Map<Geary.Email, bool> results = yield engine.local_folder.create_or_merge_email_async(
+ Geary.iterate<Geary.Email>(created).to_array_list(), cancellable);
+ if (results.size > 0) {
+ created_id = Collection.get_first<Geary.Email>(results.keys).id;
+ } else {
+ created_id = null;
+ }
+ }
+ }
+
+ public override string describe_state() {
+ return "created_id: %s".printf(
+ this.created_id != null ? this.created_id.to_string() : "none"
+ );
}
+
}
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 e2133dfb..8a045ecc 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
@@ -21,9 +21,6 @@ private class Geary.ImapEngine.EmptyFolder : Geary.ImapEngine.SendReplayOperatio
this.engine = engine;
this.cancellable = cancellable;
}
-
- public override void notify_remote_removed_ids(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
public override async ReplayOperation.Status replay_local_async() throws Error {
this.original_count = this.engine.properties.email_total;
@@ -52,16 +49,12 @@ private class Geary.ImapEngine.EmptyFolder : Geary.ImapEngine.SendReplayOperatio
ids.add_all(removed_ids);
}
- public override async ReplayOperation.Status replay_remote_async() throws Error {
+ public override async void replay_remote_async(Imap.FolderSession remote)
+ throws GLib.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 remote.remove_email_async(msg_set.to_list(), cancellable);
-
- return ReplayOperation.Status.COMPLETED;
}
public override async void backout_local_async() throws Error {
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 a6da5c01..22ae0949 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
@@ -38,10 +38,7 @@ private class Geary.ImapEngine.FetchEmail : Geary.ImapEngine.SendReplayOperation
public override void notify_remote_removed_ids(Gee.Collection<ImapDB.EmailIdentifier> ids) {
remote_removed = ids.contains(id);
}
-
- public override void get_ids_to_be_remote_removed(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
+
public override async ReplayOperation.Status replay_local_async() throws Error {
// If forcing an update, skip local operation and go direct to replay_remote()
if (flags.is_all_set(Folder.ListFlags.FORCE_UPDATE))
@@ -84,16 +81,14 @@ private class Geary.ImapEngine.FetchEmail : Geary.ImapEngine.SendReplayOperation
return ReplayOperation.Status.CONTINUE;
}
-
- public override async ReplayOperation.Status replay_remote_async() throws Error {
+
+ public override async void replay_remote_async(Imap.FolderSession remote)
+ throws GLib.Error {
if (remote_removed) {
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 remote.list_email_async(
@@ -124,17 +119,10 @@ private class Geary.ImapEngine.FetchEmail : Geary.ImapEngine.SendReplayOperation
ImapDB.Folder.ListFlags.NONE, cancellable);
assert(email != null);
}
-
- return ReplayOperation.Status.COMPLETED;
- }
-
- public override async void backout_local_async() throws Error {
- // read-only
}
-
+
public override string describe_state() {
return "id=%s required_fields=%Xh remaining_fields=%Xh flags=%Xh".printf(id.to_string(),
required_fields, remaining_fields, flags);
}
}
-
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-list-email-by-id.vala
b/src/engine/imap-engine/replay-ops/imap-engine-list-email-by-id.vala
index 703e0cc6..22987fb7 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-list-email-by-id.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-list-email-by-id.vala
@@ -81,31 +81,27 @@ private class Geary.ImapEngine.ListEmailByID : Geary.ImapEngine.AbstractListEmai
// an initial_id
finished = (get_unfulfilled_count() == 0 && fulfilled_count >= count);
} else {
- // count == int.MAX
- // This sentinel means "get everything from this point", so this has different meanings
- // depending on direction
- if (flags.is_newest_to_oldest()) {
- // only finished if the folder is entirely normalized
- Trillian is_fully_expanded = yield is_fully_expanded_async();
- finished = (is_fully_expanded == Trillian.TRUE);
- } else {
- // for oldest-to-newest, finished if no unfulfilled items
- finished = (get_unfulfilled_count() == 0);
- }
+ // Here, count == int.MAX, but this sentinel means "get
+ // everything from this point", so this has different
+ // meanings depending on direction. If
+ // flags.is_newest_to_oldest(), only finished if the
+ // folder is entirely normalized, but we don't know here
+ // since we don't have a remote. Else for
+ // oldest-to-newest, finished if no unfulfilled items
+ finished = (
+ !flags.is_newest_to_oldest() && get_unfulfilled_count() == 0
+ );
}
-
- // local-only operations stop here; also, since the local store is normalized from the top
- // of the vector on down, if enough items came back fulfilled, then done
- if (finished)
- return ReplayOperation.Status.COMPLETED;
-
- return ReplayOperation.Status.CONTINUE;
+
+ return finished
+ ? ReplayOperation.Status.COMPLETED
+ : ReplayOperation.Status.CONTINUE;
}
-
- public override async ReplayOperation.Status replay_remote_async() throws Error {
+
+ public override async void replay_remote_async(Imap.FolderSession remote)
+ throws GLib.Error {
bool expansion_required = false;
- Trillian is_fully_expanded = yield is_fully_expanded_async();
- if (is_fully_expanded == Trillian.FALSE) {
+ if (!(yield is_fully_expanded_async(remote))) {
if (flags.is_oldest_to_newest()) {
if (initial_id != null) {
// expand vector if not initial_id not discovered
@@ -130,27 +126,48 @@ private class Geary.ImapEngine.ListEmailByID : Geary.ImapEngine.AbstractListEmai
}
}
}
-
+
// If the vector is too short, expand it now
if (expansion_required) {
- Gee.Set<Imap.UID>? uids = yield expand_vector_async(initial_uid, count);
+ Gee.Set<Imap.UID>? uids = yield expand_vector_async(
+ remote, initial_uid, count
+ );
if (uids != null) {
// add required_fields as well as basic required fields for new email
add_many_unfulfilled_fields(uids, required_fields);
}
}
-
+
// Even after expansion it's possible for the local_list_count + unfulfilled to be less
// than count if the folder has fewer messages or the user is requesting a span near
// either end of the vector, so don't do that kind of sanity checking here
-
- return yield base.replay_remote_async();
+
+ yield base.replay_remote_async(remote);
}
-
+
public override string describe_state() {
return "%s initial_id=%s count=%u incl=%s newest_to_oldest=%s".printf(base.describe_state(),
(initial_id != null) ? initial_id.to_string() : "(null)", count,
flags.is_including_id().to_string(), flags.is_newest_to_oldest().to_string());
}
-}
+ /**
+ * Determines if the owning folder's vector is fully expanded.
+ */
+ private async bool is_fully_expanded_async(Imap.FolderSession remote)
+ throws GLib.Error {
+ int remote_count = remote.folder.properties.email_total;
+
+ // include marked for removed in the count in case this is
+ // being called while a removal is in process, in which case
+ // don't want to expand vector this moment because the vector
+ // is in flux
+ int local_count_with_marked =
+ yield this.owner.local_folder.get_email_count_async(
+ ImapDB.Folder.ListFlags.INCLUDE_MARKED_FOR_REMOVE, cancellable
+ );
+
+ return local_count_with_marked >= remote_count;
+ }
+
+}
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 53686711..2330ecc6 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
@@ -30,10 +30,7 @@ private class Geary.ImapEngine.MarkEmail : Geary.ImapEngine.SendReplayOperation
if (original_flags != null)
Collection.map_unset_all_keys<EmailIdentifier, Geary.EmailFlags>(original_flags, ids);
}
-
- public override void get_ids_to_be_remote_removed(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
+
public override async ReplayOperation.Status replay_local_async() throws Error {
if (to_mark.size == 0)
return ReplayOperation.Status.COMPLETED;
@@ -57,24 +54,19 @@ private class Geary.ImapEngine.MarkEmail : Geary.ImapEngine.SendReplayOperation
return ReplayOperation.Status.CONTINUE;
}
-
- public override async ReplayOperation.Status replay_remote_async() throws Error {
- // 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 remote.mark_email_async(
- msg_sets, flags_to_add, flags_to_remove, cancellable
- );
- return ReplayOperation.Status.COMPLETED;
+ public override async void replay_remote_async(Imap.FolderSession remote)
+ throws GLib.Error {
+ // potentially empty due to writebehind operation
+ if (original_flags.size > 0) {
+ Gee.List<Imap.MessageSet> msg_sets = Imap.MessageSet.uid_sparse(
+ ImapDB.EmailIdentifier.to_uids(original_flags.keys));
+ yield remote.mark_email_async(
+ msg_sets, flags_to_add, flags_to_remove, cancellable
+ );
+ }
}
-
+
public override async void backout_local_async() throws Error {
// Restore original flags (if fetched, which may not have occurred if an error happened
// during transaction)
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 651a8de7..68420cc5 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
@@ -31,54 +31,47 @@ private class Geary.ImapEngine.MoveEmailCommit : Geary.ImapEngine.SendReplayOper
public override void notify_remote_removed_ids(Gee.Collection<ImapDB.EmailIdentifier> ids) {
to_move.remove_all(ids);
}
-
- public override async ReplayOperation.Status replay_local_async() throws Error {
- return ReplayOperation.Status.CONTINUE;
- }
-
+
public override void get_ids_to_be_remote_removed(Gee.Collection<ImapDB.EmailIdentifier> ids) {
ids.add_all(to_move);
}
-
- public override async ReplayOperation.Status replay_remote_async() throws Error {
- if (to_move.size == 0)
- return ReplayOperation.Status.COMPLETED;
-
- // Remaining MessageSets are persisted in case of network retries
- if (remaining_msg_sets == null)
- remaining_msg_sets = Imap.MessageSet.uid_sparse(ImapDB.EmailIdentifier.to_uids(to_move));
-
- 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", this.destination.to_string()
+ public override async void replay_remote_async(Imap.FolderSession remote)
+ throws GLib.Error {
+ if (to_move.size > 0) {
+ // Remaining MessageSets are persisted in case of network retries
+ if (remaining_msg_sets == null)
+ remaining_msg_sets = Imap.MessageSet.uid_sparse(
+ ImapDB.EmailIdentifier.to_uids(to_move)
);
- }
- Imap.MessageSet msg_set = iter.get();
+ if (remaining_msg_sets == null || remaining_msg_sets.size == 0)
+ return;
- 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);
+ 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", this.destination.to_string()
+ );
+ }
- yield remote.remove_email_async(msg_set.to_list(), null);
+ Imap.MessageSet msg_set = iter.get();
- // completed successfully, remove from list in case of retry
- iter.remove();
- }
+ 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);
- return ReplayOperation.Status.COMPLETED;
+ yield remote.remove_email_async(msg_set.to_list(), null);
+
+ // completed successfully, remove from list in case of retry
+ iter.remove();
+ }
+ }
}
public override async void backout_local_async() throws Error {
@@ -99,4 +92,3 @@ private class Geary.ImapEngine.MoveEmailCommit : Geary.ImapEngine.SendReplayOper
return "%d email IDs to %s".printf(to_move.size, destination.to_string());
}
}
-
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-move-email-prepare.vala
b/src/engine/imap-engine/replay-ops/imap-engine-move-email-prepare.vala
index a6d79428..b0efd5d9 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-move-email-prepare.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-move-email-prepare.vala
@@ -54,19 +54,8 @@ private class Geary.ImapEngine.MoveEmailPrepare : Geary.ImapEngine.SendReplayOpe
return ReplayOperation.Status.COMPLETED;
}
-
- public override void get_ids_to_be_remote_removed(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
- public override async ReplayOperation.Status replay_remote_async() throws Error {
- return ReplayOperation.Status.COMPLETED;
- }
-
- public override async void backout_local_async() throws Error {
- }
-
+
public override string describe_state() {
return "%d email IDs".printf(prepared_for_move != null ? prepared_for_move.size : 0);
}
}
-
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-move-email-revoke.vala
b/src/engine/imap-engine/replay-ops/imap-engine-move-email-revoke.vala
index 7526d557..e2e673dc 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-move-email-revoke.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-move-email-revoke.vala
@@ -47,19 +47,8 @@ private class Geary.ImapEngine.MoveEmailRevoke : Geary.ImapEngine.SendReplayOper
return ReplayOperation.Status.COMPLETED;
}
-
- public override void get_ids_to_be_remote_removed(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
- public override async ReplayOperation.Status replay_remote_async() throws Error {
- return ReplayOperation.Status.COMPLETED;
- }
-
- public override async void backout_local_async() throws Error {
- }
-
+
public override string describe_state() {
return "%d email IDs".printf(to_revoke.size);
}
}
-
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 47b3417e..cad3e574 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
@@ -53,20 +53,17 @@ private class Geary.ImapEngine.RemoveEmail : Geary.ImapEngine.SendReplayOperatio
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));
- 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 replay_remote_async(Imap.FolderSession remote)
+ throws GLib.Error {
+ if (removed_ids.size > 0) {
+ // 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 remote.remove_email_async(msg_sets, cancellable);
+ }
}
public override async void backout_local_async() throws Error {
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 b3766378..7fbb05c3 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
@@ -49,26 +49,12 @@ private class Geary.ImapEngine.ReplayAppend : Geary.ImapEngine.ReplayOperation {
// DON'T update remote_count, it is intended to report the remote count at the time the
// appended messages arrived
}
-
- public override void notify_remote_removed_ids(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
- public override void get_ids_to_be_remote_removed(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
- public override async ReplayOperation.Status replay_local_async() throws Error {
- return ReplayOperation.Status.CONTINUE;
- }
-
- public override async void backout_local_async() throws Error {
- }
- public override async ReplayOperation.Status replay_remote_async()
- throws Error {
- if (this.positions.size > 0)
- yield do_replay_appended_messages();
-
- return ReplayOperation.Status.COMPLETED;
+ public override async void replay_remote_async(Imap.FolderSession remote)
+ throws GLib.Error {
+ if (this.positions.size > 0) {
+ yield do_replay_appended_messages(remote);
+ }
}
public override string describe_state() {
@@ -80,7 +66,7 @@ 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(Imap.FolderSession remote)
throws Error {
StringBuilder positions_builder = new StringBuilder("( ");
foreach (Imap.SequenceNumber remote_position in this.positions)
@@ -93,8 +79,6 @@ 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>();
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
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 fc25e10c..1ff5b7c7 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
@@ -42,11 +42,9 @@ private class Geary.ImapEngine.ReplayRemoval : Geary.ImapEngine.ReplayOperation
// processed in-order with ReplayAppend operations
return ReplayOperation.Status.CONTINUE;
}
-
- public override async void backout_local_async() throws Error {
- }
- public override async ReplayOperation.Status replay_remote_async() throws Error {
+ public override async void replay_remote_async(Imap.FolderSession remote)
+ throws GLib.Error {
debug("%s: ReplayRemoval this.position=%s reported_remote_count=%d",
this.owner.to_string(), this.position.value.to_string(), this.remote_count);
@@ -56,7 +54,6 @@ private class Geary.ImapEngine.ReplayRemoval : Geary.ImapEngine.ReplayOperation
debug("%s do_replay_removed_message: ignoring, invalid remote position or count",
to_string());
}
- return ReplayOperation.Status.COMPLETED;
}
public override string describe_state() {
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-replay-update.vala
b/src/engine/imap-engine/replay-ops/imap-engine-replay-update.vala
index d1d95293..574293c4 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-replay-update.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-replay-update.vala
@@ -30,15 +30,6 @@ private class Geary.ImapEngine.ReplayUpdate : Geary.ImapEngine.ReplayOperation {
this.data = data;
}
- public override void notify_remote_removed_position(Imap.SequenceNumber removed) {
- }
-
- public override void notify_remote_removed_ids(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
- public override void get_ids_to_be_remote_removed(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
public override async ReplayOperation.Status replay_local_async()
throws Error {
Imap.MessageFlags? message_flags =
@@ -79,13 +70,6 @@ private class Geary.ImapEngine.ReplayUpdate : Geary.ImapEngine.ReplayOperation {
return ReplayOperation.Status.COMPLETED;
}
- public override async void backout_local_async() throws Error {
- }
-
- public override async ReplayOperation.Status replay_remote_async() {
- return ReplayOperation.Status.CONTINUE;
- }
-
public override string describe_state() {
Imap.MessageData? fetch_flags =
this.data.data_map.get(Imap.FetchDataSpecifier.FLAGS);
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 cee124dd..2615e6bb 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
@@ -24,27 +24,28 @@ private class Geary.ImapEngine.ServerSearchEmail : Geary.ImapEngine.AbstractList
this.criteria = criteria;
}
-
- public override async ReplayOperation.Status replay_local_async() throws Error {
- // accumulate nothing, nothing unfulfilled (yet)
+
+ // XXX Shouldn't need to override this, but AbstractListEmail
+ // won't let us declare it as remote-only
+ public override async ReplayOperation.Status replay_local_async()
+ throws GLib.Error {
return ReplayOperation.Status.CONTINUE;
}
- public override async ReplayOperation.Status replay_remote_async() throws Error {
- Imap.FolderSession remote =
- yield this.owner.claim_remote_session(this.cancellable);
+ public override async void replay_remote_async(Imap.FolderSession remote)
+ throws GLib.Error {
Gee.SortedSet<Imap.UID>? uids = yield remote.search_async(
criteria, this.cancellable
);
if (uids == null || uids.size == 0)
- return ReplayOperation.Status.COMPLETED;
+ return;
// 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);
if (first_id == null)
- yield expand_vector_async(uids.first(), 1);
-
+ yield expand_vector_async(remote, uids.first(), 1);
+
// Convert UIDs into EmailIdentifiers for lookup
Gee.HashSet<ImapDB.EmailIdentifier> local_ids = new Gee.HashSet<ImapDB.EmailIdentifier>();
foreach (Imap.UID uid in uids) {
@@ -78,12 +79,12 @@ private class Geary.ImapEngine.ServerSearchEmail : Geary.ImapEngine.AbstractList
else
accumulator.add(email);
}
-
- // with unfufilled set and fulfilled added to accumulator, let base class do the rest of the
- // work
- return yield base.replay_remote_async();
+
+ // with unfufilled set and fulfilled added to accumulator, let
+ // base class do the rest of the work
+ yield base.replay_remote_async(remote);
}
-
+
public override string describe_state() {
return "criteria=%s".printf(criteria.to_string());
}
diff --git a/src/engine/imap-engine/replay-ops/imap-engine-user-close.vala
b/src/engine/imap-engine/replay-ops/imap-engine-user-close.vala
index 48814ba0..cc0684e8 100644
--- a/src/engine/imap-engine/replay-ops/imap-engine-user-close.vala
+++ b/src/engine/imap-engine/replay-ops/imap-engine-user-close.vala
@@ -1,9 +1,18 @@
-/* Copyright 2016 Software Freedom Conservancy Inc.
+/*
+ * Copyright 2016 Software Freedom Conservancy Inc.
+ * Copyright 2018 Michael Gratton <mike vee net>
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
*/
+/**
+ * Operation to close the folder.
+ *
+ * This is a replay queue operation to allow existing local ops to
+ * complete, and to ease the implementation. See comments in {@link
+ * MinimalFolder.close_async}.
+ */
private class Geary.ImapEngine.UserClose : Geary.ImapEngine.ReplayOperation {
/** Determines the state of the close operation. */
@@ -19,15 +28,6 @@ private class Geary.ImapEngine.UserClose : Geary.ImapEngine.ReplayOperation {
this.cancellable = cancellable;
}
- public override void notify_remote_removed_position(Imap.SequenceNumber removed) {
- }
-
- public override void notify_remote_removed_ids(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
- public override void get_ids_to_be_remote_removed(Gee.Collection<ImapDB.EmailIdentifier> ids) {
- }
-
public override async ReplayOperation.Status replay_local_async() throws Error {
bool closing = yield this.owner.close_internal(
Folder.CloseReason.LOCAL_CLOSE,
@@ -38,14 +38,6 @@ private class Geary.ImapEngine.UserClose : Geary.ImapEngine.ReplayOperation {
return ReplayOperation.Status.COMPLETED;
}
- public override async void backout_local_async() throws Error {
- }
-
- public override async ReplayOperation.Status replay_remote_async() throws Error {
- // should not be called
- return ReplayOperation.Status.COMPLETED;
- }
-
public override string describe_state() {
return "is_closing: %s".printf(this.is_closing.to_string());
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]