[geary/wip/cx-reestablish] Don't require network access to open folder



commit 9cfa626cda2154470921550a919faed18b864f68
Author: Jim Nelson <jim yorba org>
Date:   Thu Jan 22 15:42:37 2015 -0800

    Don't require network access to open folder

 src/engine/imap-db/imap-db-folder.vala             |   35 ++++++++++++++++++++
 .../imap-engine/imap-engine-generic-account.vala   |    4 +-
 .../imap-engine/imap-engine-minimal-folder.vala    |    8 +++-
 src/engine/imap/api/imap-account.vala              |   17 ++++++++-
 4 files changed, 58 insertions(+), 6 deletions(-)
---
diff --git a/src/engine/imap-db/imap-db-folder.vala b/src/engine/imap-db/imap-db-folder.vala
index e1b5abe..1919515 100644
--- a/src/engine/imap-db/imap-db-folder.vala
+++ b/src/engine/imap-db/imap-db-folder.vala
@@ -173,6 +173,41 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics {
         properties.set_select_examine_message_count(count);
     }
     
+    public async Imap.StatusData fetch_status_data(ListFlags flags, Cancellable? cancellable) throws Error {
+        Imap.StatusData? status_data = null;
+        yield db.exec_transaction_async(Db.TransactionType.RO, (cx) => {
+            Db.Statement stmt = cx.prepare("""
+                SELECT uid_next, uid_validity, unread_count
+                FROM FolderTable
+                WHERE id = ?
+            """);
+            stmt.bind_rowid(0, folder_id);
+            
+            Db.Result result = stmt.exec(cancellable);
+            if (result.finished)
+                return Db.TransactionOutcome.DONE;
+            
+            int messages = do_get_email_count(cx, flags, cancellable);
+            Imap.UID? uid_next = !result.is_null_for("uid_next")
+                ? new Imap.UID(result.int64_for("uid_next"))
+                : null;
+            Imap.UIDValidity? uid_validity = !result.is_null_for("uid_validity")
+                ? new Imap.UIDValidity(result.int64_for("uid_validity"))
+                : null;
+            
+            // Note that recent is not stored
+            status_data = new Imap.StatusData(new Imap.MailboxSpecifier.from_folder_path(path, null),
+                messages, 0, uid_next, uid_validity, result.int_for("unread_count"));
+            
+            return Db.TransactionOutcome.DONE;
+        }, cancellable);
+        
+        if (status_data == null)
+            throw new EngineError.NOT_FOUND("%s STATUS not found in database", path.to_string());
+        
+        return status_data;
+    }
+    
     // Returns a Map with the created or merged email as the key and the result of the operation
     // (true if created, false if merged) as the value.  Note that every email
     // object passed in's EmailIdentifier will be fully filled out by this
diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala 
b/src/engine/imap-engine/imap-engine-generic-account.vala
index ff441f2..9c4361c 100644
--- a/src/engine/imap-engine/imap-engine-generic-account.vala
+++ b/src/engine/imap-engine/imap-engine-generic-account.vala
@@ -340,7 +340,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
         
         bool folder_created;
         Imap.Folder remote_folder = yield remote.fetch_folder_async(folder.path,
-            out folder_created, cancellable);
+            out folder_created, null, cancellable);
         
         if (!folder_created) {
             int unseen_count = yield remote.fetch_unseen_count_async(folder.path, cancellable);
@@ -517,7 +517,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
                 continue;
             
             Imap.Folder remote_folder = (Imap.Folder) yield remote.fetch_folder_async(folder,
-                null, cancellable);
+                null, null, cancellable);
             
             yield local.clone_folder_async(remote_folder, cancellable);
         }
diff --git a/src/engine/imap-engine/imap-engine-minimal-folder.vala 
b/src/engine/imap-engine/imap-engine-minimal-folder.vala
index 19a2e37..66d39b7 100644
--- a/src/engine/imap-engine/imap-engine-minimal-folder.vala
+++ b/src/engine/imap-engine/imap-engine-minimal-folder.vala
@@ -608,9 +608,13 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
         // carefully back out and possibly retry
         Imap.Folder? opening_folder = null;
         try {
+            debug("Fetching STATUS for remote %s from local", to_string());
+            Imap.StatusData local_status = yield local_folder.fetch_status_data(
+                ImapDB.Folder.ListFlags.NONE, cancellable);
+            
             debug("Fetching information for remote folder %s", to_string());
-            opening_folder = yield remote.fetch_folder_async(local_folder.get_path(),
-                null, cancellable);
+            opening_folder = yield remote.fetch_folder_async(local_folder.get_path(), null, local_status,
+                cancellable);
             
             debug("Opening remote folder %s", opening_folder.to_string());
             yield opening_folder.open_async(cancellable);
diff --git a/src/engine/imap/api/imap-account.vala b/src/engine/imap/api/imap-account.vala
index b7de768..42bbf71 100644
--- a/src/engine/imap/api/imap-account.vala
+++ b/src/engine/imap/api/imap-account.vala
@@ -219,8 +219,10 @@ private class Geary.Imap.Account : BaseObject {
         }
     }
     
+    // By supplying fallback STATUS, the Folder may be fetched if a network error occurs; if null,
+    // the network error is thrown
     public async Imap.Folder fetch_folder_async(FolderPath path, out bool created,
-        Cancellable? cancellable) throws Error {
+        StatusData? fallback_status_data, Cancellable? cancellable) throws Error {
         check_open();
         
         created = false;
@@ -245,7 +247,18 @@ private class Geary.Imap.Account : BaseObject {
         
         Imap.Folder folder;
         if (!mailbox_info.attrs.is_no_select) {
-            StatusData status = yield fetch_status_async(folder_path, StatusDataType.all(), cancellable);
+            StatusData status;
+            try {
+                status = yield fetch_status_async(folder_path, StatusDataType.all(), cancellable);
+            } catch (Error err) {
+                if (fallback_status_data == null)
+                    throw err;
+                
+                debug("Unable to fetch STATUS for %s, using fallback from local: %s", 
folder_path.to_string(),
+                    err.message);
+                
+                status = fallback_status_data;
+            }
             
             folder = new Imap.Folder(folder_path, session_mgr, status, mailbox_info);
         } else {


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