From 2c8a232f97dfc4b3a50a36af9b6a6ea3a1795f0c Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Thu, 7 Mar 2019 11:24:06 +1100 Subject: [PATCH] Ensure that cancelled commands throw a cancelled error, not a timeout Commands that were cancelled, e.g. because the network connection was lost and so commands in progress were backed out, were throwing timeout errors to callers of wait_until_complete since they had received no response. This was causing e.g. account operations to fail, and the alleged timeout be reported as problem in the UI. This takes note of whether a command was cancelled and throws an appropriate error in wait_until_complete if so. Callers can then clean up and choose to be more circumspect in their error reporting. Fixes #285 --- src/engine/imap/command/imap-command.vala | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/engine/imap/command/imap-command.vala b/src/engine/imap/command/imap-command.vala index dd6eb18d..76964b17 100644 --- a/src/engine/imap/command/imap-command.vala +++ b/src/engine/imap/command/imap-command.vala @@ -79,6 +79,7 @@ public class Geary.Imap.Command : BaseObject { new Geary.Nonblocking.Semaphore(); private bool timed_out = false; + private bool cancelled = false; private Geary.Nonblocking.Spinlock? literal_spinlock = null; private GLib.Cancellable? literal_cancellable = null; @@ -209,10 +210,12 @@ public class Geary.Imap.Command : BaseObject { * Cancels this command's execution. * * When this method is called, all locks will be released, - * including {@link wait_until_complete}. + * including {@link wait_until_complete}, which will then throw a + * `GLib.IOError.CANCELLED` error. */ internal virtual void cancel_command() { cancel_send(); + this.cancelled = true; this.response_timer.reset(); this.complete_lock.blind_notify(); } @@ -220,17 +223,23 @@ public class Geary.Imap.Command : BaseObject { /** * Yields until the command has been completed or cancelled. * - * Throws an error if cancelled, if the command is cancelled, or - * if the command's response was bad. + * Throws an error if the command or the cancellable argument is + * cancelled, if the command timed out, or if the command's + * response was bad. */ public async void wait_until_complete(GLib.Cancellable cancellable) throws GLib.Error { yield this.complete_lock.wait_async(cancellable); + if (this.cancelled) { + throw new GLib.IOError.CANCELLED( + "%s: Command was cancelled", to_brief_string() + ); + } + if (this.timed_out) { throw new ImapError.TIMED_OUT( - "%s: No command response was received", - to_brief_string() + "%s: Command timed out", to_brief_string() ); }