From b209f84e5895d7ae3b9ca200f36343d162914932 Mon Sep 17 00:00:00 2001
From: Michael Gratton <mike@vee.net>
Date: Wed, 23 Sep 2020 09:11:50 +1000
Subject: [PATCH 024/124] Geary.Imap.FolderSession: Ensure client session is
 selected when accessed

Ensure the underlying ClientSession object is in the SELECTED state
for the correct mailbox when obtaining it.
---
 src/engine/imap/api/imap-folder-session.vala | 31 ++++++++++++++++----
 src/engine/imap/api/imap-session-object.vala |  2 +-
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/src/engine/imap/api/imap-folder-session.vala b/src/engine/imap/api/imap-folder-session.vala
index 092c06cd..98db3088 100644
--- a/src/engine/imap/api/imap-folder-session.vala
+++ b/src/engine/imap/api/imap-folder-session.vala
@@ -38,6 +38,8 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
     /** Determines if this folder accepts custom IMAP flags. */
     public Trillian accepts_user_flags { get; private set; default = Trillian.UNKNOWN; }
 
+    private MailboxSpecifier mailbox;
+
     private Quirks quirks;
 
     private Nonblocking.Mutex cmd_mutex = new Nonblocking.Mutex();
@@ -107,9 +109,9 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
         session.search.connect(on_search);
         session.status_response_received.connect(on_status_response);
 
-        MailboxSpecifier mailbox = session.get_mailbox_for_path(folder.path);
+        this.mailbox = session.get_mailbox_for_path(folder.path);
         StatusResponse? response = yield session.select_async(
-            mailbox, cancellable
+            this.mailbox, cancellable
         );
         throw_on_not_ok(response, "SELECT " + this.folder.path.to_string());
 
@@ -1107,8 +1109,6 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
                                                            Geary.EmailFlags? flags,
                                                            GLib.DateTime? date_received)
         throws GLib.Error {
-        ClientSession session = claim_session();
-
         MessageFlags? msg_flags = null;
         if (flags != null) {
             Imap.EmailFlags imap_flags = Imap.EmailFlags.from_api_email_flags(flags);
@@ -1121,9 +1121,8 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
         if (date_received != null)
             internaldate = new InternalDate.from_date_time(date_received);
 
-        MailboxSpecifier mailbox = session.get_mailbox_for_path(this.folder.path);
         AppendCommand cmd = new AppendCommand(
-            mailbox,
+            this.mailbox,
             msg_flags,
             internaldate,
             message.get_rfc822_buffer(),
@@ -1161,6 +1160,26 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
         );
     }
 
+    /**
+     * Returns a valid IMAP client session for use by this object.
+     *
+     * In addition to the checks made by {@link
+     * SessionObject.claim_session}, this method also ensures that the
+     * IMAP session is in the SELECTED state for the correct mailbox.
+     */
+    protected override ClientSession claim_session()
+        throws ImapError {
+        var session = base.claim_session();
+        if (session.get_protocol_state() != SELECTED &&
+            !this.mailbox.equal_to(session.selected_mailbox)) {
+            throw new ImapError.NOT_CONNECTED(
+                "IMAP object no longer SELECTED for %s",
+                this.mailbox.to_string()
+            );
+        }
+        return session;
+    }
+
     // HACK: See https://bugzilla.gnome.org/show_bug.cgi?id=714902
     //
     // Detect when a server has returned a BAD response to FETCH
diff --git a/src/engine/imap/api/imap-session-object.vala b/src/engine/imap/api/imap-session-object.vala
index ee1ac09f..d47c6950 100644
--- a/src/engine/imap/api/imap-session-object.vala
+++ b/src/engine/imap/api/imap-session-object.vala
@@ -90,7 +90,7 @@ public abstract class Geary.Imap.SessionObject : BaseObject, Logging.Source {
      * or has been closed, or because the connection to the server was
      * lost.
      */
-    protected ClientSession claim_session()
+    protected virtual ClientSession claim_session()
         throws ImapError {
         if (this.session == null ||
             this.session.get_protocol_state() == NOT_CONNECTED) {
-- 
2.29.2

