[geary/wip/723104-status] Should fx two bugs, which will need to be broken out into two commits



commit d4474addb0d0195f02410905b2ad6985487e390b
Author: Jim Nelson <jim yorba org>
Date:   Mon Jan 27 16:01:02 2014 -0800

    Should fx two bugs, which will need to be broken out into two commits
    
    First is bgo#723104, due to IMAP STATUS command not being issued
    regularly on folders.  This prevents unseen counts from being
    updated as well as the background fetcher from pulling new messages
    from unopened folders.
    
    Second is the bug where, if an error occurs while listing folders,
    all of them are marked as "local delete required", which fortunately
    doesn't happen right now anyway.

 .../imap-engine/imap-engine-generic-account.vala   |    4 +-
 src/engine/imap/api/imap-account.vala              |   84 +++++++++++---------
 src/engine/imap/api/imap-folder-properties.vala    |   13 +++
 3 files changed, 61 insertions(+), 40 deletions(-)
---
diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala 
b/src/engine/imap-engine/imap-engine-generic-account.vala
index 18e99af..87684bd 100644
--- a/src/engine/imap-engine/imap-engine-generic-account.vala
+++ b/src/engine/imap-engine/imap-engine-generic-account.vala
@@ -360,8 +360,8 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
         try {
             remote_children = yield remote.list_child_folders_async(parent, cancellable);
         } catch (Error err) {
-            // ignore everything but I/O errors
-            if (err is IOError)
+            // ignore everything but I/O and IMAP errors (cancellation is an IOError)
+            if (err is IOError || err is ImapError)
                 throw err;
         }
         
diff --git a/src/engine/imap/api/imap-account.vala b/src/engine/imap/api/imap-account.vala
index 0cd39c4..691d8d9 100644
--- a/src/engine/imap/api/imap-account.vala
+++ b/src/engine/imap/api/imap-account.vala
@@ -61,22 +61,7 @@ private class Geary.Imap.Account : BaseObject {
         if (!is_open)
             return;
         
-        int token = yield account_session_mutex.claim_async(cancellable);
-        
-        ClientSession? dropped = drop_session();
-        if (dropped != null) {
-            try {
-                yield session_mgr.release_session_async(dropped, cancellable);
-            } catch (Error err) {
-                // ignored
-            }
-        }
-        
-        try {
-            account_session_mutex.release(ref token);
-        } catch (Error err) {
-            // ignored
-        }
+        yield drop_session_async(cancellable);
         
         try {
             yield session_mgr.close_async(cancellable);
@@ -91,6 +76,10 @@ private class Geary.Imap.Account : BaseObject {
     // this is used by the various calls to put off claiming a session until needed (which
     // possibly is long enough for ClientSessionManager to get a few ready).
     private async ClientSession claim_session_async(Cancellable? cancellable) throws Error {
+        // check if available session is in good state
+        if (account_session != null && account_session.get_context(null) != ClientSession.Context.AUTHORIZED)
+            yield drop_session_async(cancellable);
+        
         int token = yield account_session_mutex.claim_async(cancellable);
         
         Error? err = null;
@@ -114,20 +103,35 @@ private class Geary.Imap.Account : BaseObject {
         return account_session;
     }
     
-    // Can be called locked or unlocked, but only unlocked if you know what you're doing -- i.e.
-    // not yielding.
-    private ClientSession? drop_session() {
-        if (account_session == null)
-            return null;
-        
-        account_session.list.disconnect(on_list_data);
-        account_session.status.disconnect(on_status_data);
-        account_session.disconnected.disconnect(on_disconnected);
+    private async void drop_session_async(Cancellable? cancellable) {
+        int token;
+        try {
+            token = yield account_session_mutex.claim_async(cancellable);
+        } catch (Error err) {
+            debug("Unable to claim Imap.Account session mutex: %s", err.message);
+            
+            return;
+        }
         
-        ClientSession dropped = account_session;
-        account_session = null;
+        if (account_session != null) {
+            try {
+                yield session_mgr.release_session_async(account_session, cancellable);
+            } catch (Error err) {
+                // ignored
+            }
+            
+            account_session.list.disconnect(on_list_data);
+            account_session.status.disconnect(on_status_data);
+            account_session.disconnected.disconnect(on_disconnected);
+            
+            account_session = null;
+        }
         
-        return dropped;
+        try {
+            account_session_mutex.release(ref token);
+        } catch (Error err) {
+            // ignored
+        }
     }
     
     private void on_list_data(MailboxInformation mailbox_info) {
@@ -141,7 +145,7 @@ private class Geary.Imap.Account : BaseObject {
     }
     
     private void on_disconnected() {
-        drop_session();
+        drop_session_async.begin(null);
     }
     
     public async bool folder_exists_async(FolderPath path, Cancellable? cancellable) throws Error {
@@ -223,13 +227,6 @@ private class Geary.Imap.Account : BaseObject {
         Gee.Map<StatusCommand, MailboxSpecifier> cmd_map = new Gee.HashMap<
             StatusCommand, MailboxSpecifier>();
         foreach (MailboxInformation mailbox_info in child_info) {
-            // if already have an Imap.Folder for this mailbox, use that
-            if (folders.has_key(mailbox_info.path)) {
-                child_folders.add(folders.get(mailbox_info.path));
-                
-                continue;
-            }
-            
             // if new mailbox is unselectable, don't bother doing a STATUS command
             if (mailbox_info.attrs.contains(MailboxAttribute.NO_SELECT)) {
                 Imap.Folder folder = new Imap.Folder.unselectable(session_mgr, mailbox_info);
@@ -244,6 +241,10 @@ private class Geary.Imap.Account : BaseObject {
                 mailbox_info.mailbox);
         }
         
+        // if no STATUS results are needed, bail out with what's been collected
+        if (cmd_map.size == 0)
+            return child_folders;
+        
         Gee.List<StatusData> status_results = new Gee.ArrayList<StatusData>();
         Gee.Map<Command, StatusResponse> responses = yield send_multiple_async(cmd_map.keys,
             null, status_results, cancellable);
@@ -278,8 +279,15 @@ private class Geary.Imap.Account : BaseObject {
             
             status_results.remove(found_status);
             
-            Imap.Folder folder = new Imap.Folder(session_mgr, found_status, mailbox_info);
-            folders.set(folder.path, folder);
+            // if already have an Imap.Folder for this mailbox, use that
+            Imap.Folder? folder = folders.get(mailbox_info.path);
+            if (folder != null) {
+                folder.properties.update_status(found_status);
+            } else {
+                folder = new Imap.Folder(session_mgr, found_status, mailbox_info);
+                folders.set(folder.path, folder);
+            }
+            
             child_folders.add(folder);
         }
         
diff --git a/src/engine/imap/api/imap-folder-properties.vala b/src/engine/imap/api/imap-folder-properties.vala
index ab99e56..6a3b9b3 100644
--- a/src/engine/imap/api/imap-folder-properties.vala
+++ b/src/engine/imap/api/imap-folder-properties.vala
@@ -169,6 +169,19 @@ public class Geary.Imap.FolderProperties : Geary.FolderProperties {
         is_openable = Trillian.from_boolean(!attrs.contains(MailboxAttribute.NO_SELECT));
     }
     
+    /**
+     * Update an existing { link FolderProperties} with fresh { link StatusData}.
+     *
+     * This will force the { link email_total} property to match the { link status_messages} value.
+     */
+    public void update_status(StatusData status) {
+        set_status_message_count(status.messages, true);
+        set_status_unseen(status.unseen);
+        recent = status.recent;
+        uid_validity = status.uid_validity;
+        uid_next = status.uid_next;
+    }
+    
     public void set_status_message_count(int messages, bool force) {
         if (messages < 0)
             return;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]