[geary/wip/721828-undo-2] Account for messages marked as removed in folder properties



commit 299049492f6af31c9f3626e535847d031c1615d0
Author: Jim Nelson <jim yorba org>
Date:   Wed Feb 4 18:24:05 2015 -0800

    Account for messages marked as removed in folder properties
    
    This is more of an issue with undo because moved messages are "held"
    marked as removed until the delayed undo is committed.

 src/engine/imap-db/imap-db-account.vala            |   47 ++++++++++++++++++--
 .../imap-engine/imap-engine-generic-account.vala   |   37 ++++++++++-----
 src/engine/imap/api/imap-account.vala              |   10 +++--
 3 files changed, 73 insertions(+), 21 deletions(-)
---
diff --git a/src/engine/imap-db/imap-db-account.vala b/src/engine/imap-db/imap-db-account.vala
index b09685e..06cec3a 100644
--- a/src/engine/imap-db/imap-db-account.vala
+++ b/src/engine/imap-db/imap-db-account.vala
@@ -250,12 +250,17 @@ private class Geary.ImapDB.Account : BaseObject {
      * update_uid_info is true.
      */
     public async void update_folder_status_async(Geary.Imap.Folder imap_folder, bool update_uid_info,
-        Cancellable? cancellable) throws Error {
+        bool respect_marked_for_remove, Cancellable? cancellable) throws Error {
         check_open();
         
         Geary.Imap.FolderProperties properties = imap_folder.properties;
         Geary.FolderPath path = imap_folder.path;
         
+        // adjust for marked remove, but don't write these adjustments to the database -- they're
+        // only reflected in memory via the properties
+        int adjust_unseen = 0;
+        int adjust_total = 0;
+        
         yield db.exec_transaction_async(Db.TransactionType.RW, (cx) => {
             int64 parent_id;
             if (!do_fetch_parent_id(cx, path, true, out parent_id, cancellable)) {
@@ -264,6 +269,36 @@ private class Geary.ImapDB.Account : BaseObject {
                 return Db.TransactionOutcome.ROLLBACK;
             }
             
+            int64 folder_id;
+            if (!do_fetch_folder_id(cx, path, false, out folder_id, cancellable))
+                folder_id = Db.INVALID_ROWID;
+            
+            if (respect_marked_for_remove && folder_id != Db.INVALID_ROWID) {
+                Db.Statement stmt = cx.prepare("""
+                    SELECT flags
+                    FROM MessageTable
+                    WHERE id IN (
+                        SELECT message_id
+                        FROM MessageLocationTable
+                        WHERE folder_id = ? AND remove_marker = ?
+                    )
+                """);
+                stmt.bind_rowid(0, folder_id);
+                stmt.bind_bool(1, true);
+                
+                Db.Result results = stmt.exec(cancellable);
+                while (!results.finished) {
+                    adjust_total++;
+                    
+                    Imap.EmailFlags flags = new Imap.EmailFlags(Imap.MessageFlags.deserialize(
+                        results.string_at(0)));
+                    if (flags.contains(EmailFlags.UNREAD))
+                        adjust_unseen++;
+                    
+                    results.next(cancellable);
+                }
+            }
+            
             Db.Statement stmt;
             if (parent_id != Db.INVALID_ROWID) {
                 stmt = cx.prepare(
@@ -298,7 +333,7 @@ private class Geary.ImapDB.Account : BaseObject {
         if (db_folder != null) {
             Imap.FolderProperties local_properties = db_folder.get_properties();
             
-            local_properties.set_status_unseen(properties.unseen);
+            local_properties.set_status_unseen(Numeric.int_floor(properties.unseen - adjust_unseen, 0));
             local_properties.recent = properties.recent;
             local_properties.attrs = properties.attrs;
             
@@ -307,8 +342,12 @@ private class Geary.ImapDB.Account : BaseObject {
                 local_properties.uid_next = properties.uid_next;
             }
             
-            if (properties.status_messages >= 0)
-                local_properties.set_status_message_count(properties.status_messages, false);
+            // only update STATUS MESSAGES count if previously set, but use this count as the
+            // "authoritative" value until another SELECT/EXAMINE or MESSAGES response
+            if (properties.status_messages >= 0) {
+                local_properties.set_status_message_count(
+                    Numeric.int_floor(properties.status_messages - adjust_total, 0), true);
+            }
         }
     }
     
diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala 
b/src/engine/imap-engine/imap-engine-generic-account.vala
index b549875..8d04ccf 100644
--- a/src/engine/imap-engine/imap-engine-generic-account.vala
+++ b/src/engine/imap-engine/imap-engine-generic-account.vala
@@ -319,6 +319,9 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
         if (in_refresh_unseen.contains(folder))
             return true;
         
+        // add here, remove in completed callback
+        in_refresh_unseen.add(folder);
+        
         refresh_unseen_async.begin(folder, null, on_refresh_unseen_completed);
         
         refresh_unseen_timeout_ids.unset(folder.path);
@@ -334,21 +337,29 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
     }
     
     private async void refresh_unseen_async(Geary.Folder folder, Cancellable? cancellable) throws Error {
-        in_refresh_unseen.add(folder);
-        
         debug("Refreshing unseen counts for %s", folder.to_string());
         
-        bool folder_created;
-        Imap.Folder remote_folder = yield remote.fetch_folder_async(folder.path,
-            out folder_created, null, cancellable);
-        
-        if (!folder_created) {
-            int unseen_count = yield remote.fetch_unseen_count_async(folder.path, cancellable);
-            remote_folder.properties.set_status_unseen(unseen_count);
-            yield local.update_folder_status_async(remote_folder, false, cancellable);
+        try {
+            bool folder_created;
+            Imap.Folder remote_folder = yield remote.fetch_folder_async(folder.path,
+                out folder_created, null, cancellable);
+            
+            // if created, don't need to fetch count because it was fetched when it was created
+            int unseen, total;
+            if (!folder_created) {
+                yield remote.fetch_counts_async(folder.path, out unseen, out total, cancellable);
+                remote_folder.properties.set_status_unseen(unseen);
+                remote_folder.properties.set_status_message_count(total, false);
+            } else {
+                unseen = remote_folder.properties.unseen;
+                total = remote_folder.properties.email_total;
+            }
+            
+            yield local.update_folder_status_async(remote_folder, false, true, cancellable);
+        } finally {
+            // added when call scheduled (above)
+            in_refresh_unseen.remove(folder);
         }
-        
-        in_refresh_unseen.remove(folder);
     }
     
     private void reschedule_folder_refresh(bool immediate) {
@@ -707,7 +718,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
             // always update, openable or not; have the folder update the UID info the next time
             // it's opened
             try {
-                yield local.update_folder_status_async(remote_folder, false, cancellable);
+                yield local.update_folder_status_async(remote_folder, false, false, cancellable);
             } catch (Error update_error) {
                 debug("Unable to update local folder %s with remote properties: %s",
                     remote_folder.to_string(), update_error.message);
diff --git a/src/engine/imap/api/imap-account.vala b/src/engine/imap/api/imap-account.vala
index 42bbf71..3a0a7f6 100644
--- a/src/engine/imap/api/imap-account.vala
+++ b/src/engine/imap/api/imap-account.vala
@@ -308,8 +308,8 @@ private class Geary.Imap.Account : BaseObject {
         }
     }
     
-    public async int fetch_unseen_count_async(FolderPath path, Cancellable? cancellable)
-        throws Error {
+    public async void fetch_counts_async(FolderPath path, out int unseen, out int total,
+        Cancellable? cancellable) throws Error {
         check_open();
         
         MailboxInformation? mailbox_info = path_to_mailbox.get(path);
@@ -320,8 +320,10 @@ private class Geary.Imap.Account : BaseObject {
                 path.to_string());
         }
         
-        StatusData data = yield fetch_status_async(path, { StatusDataType.UNSEEN }, cancellable);
-        return data.unseen;
+        StatusData data = yield fetch_status_async(path, { StatusDataType.UNSEEN, StatusDataType.MESSAGES },
+            cancellable);
+        unseen = data.unseen;
+        total = data.messages;
     }
     
     private async StatusData fetch_status_async(FolderPath path, StatusDataType[] status_types,


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