[evolution-data-server/gnome-3-10] Bug #721286 - IMAPx: read messages become unread when reopening Evolution



commit 18f99668f6cf89cdd625052bc1982e50782c99cd
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jan 29 19:49:14 2014 +0100

    Bug #721286 - IMAPx: read messages become unread when reopening Evolution
    
    Couple things changed here:
    
    a) the camel_folder_summary_get_changed() could return list of changed
       messages only if they were loaded in memory, which is not correct - I
       think it's part of the issue why it failed
    
    b) it could happen that imapx_server_sync_changes() was called to save some
       changes, but then didn't change anything; in such cases, messages marked
       as locally changed were never unmarked, which led to false tests; I added
       a function to unmark the messages as locally changed (this can cause slow
       close of evolution for the first time, due to unsetting of the flag, but
       later ends are fine)
    
    c) state of the message flags on the server is the master state, except of
       the state where locally stored info is marked as locally changed. This
       allows to show proper state of messages on the server (it is influenced
       by a) and b) too, so it might take up to two evolution starts to get
       the same view in evolution as is the state on the server)
    
    d) do not use CamelOperation in the parser thread, because it can be
       cancelled at an application end with camel_operation_cancel_all() call,
       which is done too early, before any pending jobs are properly finished
       (it can be IDLE job, or save of folder changes back to the server)

 camel/camel-folder-summary.c |   44 +++++++++++++++++++++++++++++++----------
 camel/camel-imapx-server.c   |   42 +++++++++++++++++++++++++++++++++++++++-
 camel/camel-imapx-utils.c    |    9 ++++++++
 3 files changed, 83 insertions(+), 12 deletions(-)
---
diff --git a/camel/camel-folder-summary.c b/camel/camel-folder-summary.c
index fc55dfa..232f17f 100644
--- a/camel/camel-folder-summary.c
+++ b/camel/camel-folder-summary.c
@@ -2011,12 +2011,29 @@ perform_content_info_load_from_db (CamelFolderSummary *summary,
 }
 
 static void
-append_changed_uids (gchar *key,
-                     CamelMessageInfoBase *info,
-                     GPtrArray *array)
+gather_dirty_uids (gpointer key,
+                  gpointer value,
+                  gpointer user_data)
 {
-       if (info->dirty || info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)
-               g_ptr_array_add (array, (gpointer) camel_pstring_strdup ((camel_message_info_uid (info))));
+       const gchar *uid = key;
+       CamelMessageInfoBase *info = value;
+       GHashTable *hash = user_data;
+
+       if (info->dirty)
+               g_hash_table_insert (hash, (gpointer) camel_pstring_strdup (uid), GINT_TO_POINTER (1));
+}
+
+static void
+gather_changed_uids (gpointer key,
+                    gpointer value,
+                    gpointer user_data)
+{
+       const gchar *uid = key;
+       guint32 flags = GPOINTER_TO_UINT (value);
+       GHashTable *hash = user_data;
+
+       if ((flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0)
+               g_hash_table_insert (hash, (gpointer) camel_pstring_strdup (uid), GINT_TO_POINTER (1));
 }
 
 /**
@@ -2027,16 +2044,21 @@ append_changed_uids (gchar *key,
 GPtrArray *
 camel_folder_summary_get_changed (CamelFolderSummary *summary)
 {
-       GPtrArray *res = g_ptr_array_new ();
-
-       /* FIXME[disk-summary] sucks, this function returns from memory.
-        * We need to have collate or something to get the modified ones
-        * from DB and merge */
+       GPtrArray *res;
+       GHashTable *hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) 
camel_pstring_free, NULL);
 
        camel_folder_summary_lock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
-       g_hash_table_foreach (summary->priv->loaded_infos, (GHFunc) append_changed_uids, res);
+
+       g_hash_table_foreach (summary->priv->loaded_infos, gather_dirty_uids, hash);
+       g_hash_table_foreach (summary->priv->uids, gather_changed_uids, hash);
+
+       res = g_ptr_array_sized_new (g_hash_table_size (hash));
+       g_hash_table_foreach (hash, folder_summary_dupe_uids_to_array, res);
+
        camel_folder_summary_unlock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
 
+       g_hash_table_destroy (hash);
+
        return res;
 }
 
diff --git a/camel/camel-imapx-server.c b/camel/camel-imapx-server.c
index cbc8e6c..2081b14 100644
--- a/camel/camel-imapx-server.c
+++ b/camel/camel-imapx-server.c
@@ -6892,7 +6892,12 @@ imapx_parser_thread (gpointer user_data)
 
        is = CAMEL_IMAPX_SERVER (user_data);
 
-       cancellable = camel_operation_new ();
+       /* Do not use CamelOperation here, because it can be cancelled at
+          an application end with camel_operation_cancel_all() call, which
+          is done too early, before any pending jobs are properly finished
+          (it can be IDLE job, or save of folder changes back to the server).
+        */
+       cancellable = g_cancellable_new ();
        g_weak_ref_set (&is->priv->parser_cancellable, cancellable);
 
        while (local_error == NULL) {
@@ -7699,6 +7704,40 @@ imapx_sync_free_user (GArray *user_set)
        g_array_free (user_set, TRUE);
 }
 
+static void
+imapx_unset_folder_flagged_flag (CamelFolderSummary *summary,
+                                GPtrArray *changed_uids)
+{
+       CamelMessageInfo *info;
+       gboolean changed = FALSE;
+       gint ii;
+
+       g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary));
+       g_return_if_fail (changed_uids != NULL);
+
+       for (ii = 0; ii < changed_uids->len; ii++) {
+               info = camel_folder_summary_get (summary, changed_uids->pdata[ii]);
+
+               if (info) {
+                       CamelMessageInfoBase *mi = (CamelMessageInfoBase *) info;
+
+                       /* some infos could be only 'dirty' (needed to save into summary) */
+                       if ((mi->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0) {
+                               mi->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
+                               mi->dirty = TRUE;
+                               changed = TRUE;
+                       }
+
+                       camel_message_info_free (info);
+               }
+       }
+
+       if (changed) {
+               camel_folder_summary_touch (summary);
+               camel_folder_summary_save_to_db (summary, NULL);
+       }
+}
+
 static gboolean
 imapx_server_sync_changes (CamelIMAPXServer *is,
                            CamelFolder *folder,
@@ -7857,6 +7896,7 @@ imapx_server_sync_changes (CamelIMAPXServer *is,
        if (nothing_to_do) {
                imapx_sync_free_user (on_user);
                imapx_sync_free_user (off_user);
+               imapx_unset_folder_flagged_flag (folder->summary, changed_uids);
                camel_folder_free_uids (folder, changed_uids);
                return TRUE;
        }
diff --git a/camel/camel-imapx-utils.c b/camel/camel-imapx-utils.c
index 0caef23..1e17d45 100644
--- a/camel/camel-imapx-utils.c
+++ b/camel/camel-imapx-utils.c
@@ -284,6 +284,15 @@ imapx_update_message_info_flags (CamelMessageInfo *info,
        gboolean changed = FALSE;
        CamelIMAPXMessageInfo *xinfo = (CamelIMAPXMessageInfo *) info;
 
+       /* This makes sure that server flags has precedence from locally stored flags,
+          thus a user actually sees what is stored on the server, but only if the message
+          was not changed locally and is ready to be saved */
+       if (!(camel_message_info_flags (info) & CAMEL_MESSAGE_FOLDER_FLAGGED) &&
+           (camel_message_info_flags (info) & CAMEL_IMAPX_SERVER_FLAGS) != (server_flags & 
CAMEL_IMAPX_SERVER_FLAGS)) {
+               xinfo->server_flags = (xinfo->server_flags & ~CAMEL_IMAPX_SERVER_FLAGS) |
+                                     (camel_message_info_flags (info) & CAMEL_IMAPX_SERVER_FLAGS);
+       }
+
        if (server_flags != xinfo->server_flags) {
                guint32 server_set, server_cleared;
 


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