[evolution-data-server] [IMAPx] Enhance processing of server IDLE notifications



commit d05386e3adbedd25163933512fc648a2c7bd4022
Author: Milan Crha <mcrha redhat com>
Date:   Tue Feb 20 13:01:41 2018 +0100

    [IMAPx] Enhance processing of server IDLE notifications
    
    It could happen that some IDLE notifications had not been reflected
    in the UI, showing incorrect folder content to the user.

 .../providers/imapx/camel-imapx-conn-manager.c     |   18 +++++
 src/camel/providers/imapx/camel-imapx-server.c     |   66 +++++++++++++++----
 2 files changed, 70 insertions(+), 14 deletions(-)
---
diff --git a/src/camel/providers/imapx/camel-imapx-conn-manager.c 
b/src/camel/providers/imapx/camel-imapx-conn-manager.c
index da7d32d..02bcd8f 100644
--- a/src/camel/providers/imapx/camel-imapx-conn-manager.c
+++ b/src/camel/providers/imapx/camel-imapx-conn-manager.c
@@ -70,6 +70,9 @@ struct _CamelIMAPXConnManagerPrivate {
        GMutex busy_mailboxes_lock; /* used for both busy_mailboxes and idle_mailboxes */
        GHashTable *busy_mailboxes; /* CamelIMAPXMailbox ~> gint */
        GHashTable *idle_mailboxes; /* CamelIMAPXMailbox ~> gint */
+
+       GMutex idle_refresh_lock;
+       GHashTable *idle_refresh_mailboxes; /* not-referenced CamelIMAPXMailbox, just to use for pointer 
comparison ~> NULL */
 };
 
 struct _ConnectionInfo {
@@ -138,6 +141,10 @@ imapx_conn_manager_idle_mailbox_refresh_thread (gpointer user_data)
                        local_error ? local_error->message : "Unknown error");
        }
 
+       g_mutex_lock (&data->conn_man->priv->idle_refresh_lock);
+       g_hash_table_remove (data->conn_man->priv->idle_refresh_mailboxes, data->mailbox);
+       g_mutex_unlock (&data->conn_man->priv->idle_refresh_lock);
+
        mailbox_refresh_data_free (data);
        g_clear_error (&local_error);
 
@@ -157,6 +164,13 @@ imapx_conn_manager_refresh_mailbox_cb (CamelIMAPXServer *is,
        g_return_if_fail (CAMEL_IS_IMAPX_MAILBOX (mailbox));
        g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (conn_man));
 
+       g_mutex_lock (&conn_man->priv->idle_refresh_lock);
+       if (!g_hash_table_insert (conn_man->priv->idle_refresh_mailboxes, mailbox, NULL)) {
+               g_mutex_unlock (&conn_man->priv->idle_refresh_lock);
+               return;
+       }
+       g_mutex_unlock (&conn_man->priv->idle_refresh_lock);
+
        data = g_new0 (MailboxRefreshData, 1);
        data->conn_man = g_object_ref (conn_man);
        data->mailbox = g_object_ref (mailbox);
@@ -627,6 +641,8 @@ imapx_conn_manager_finalize (GObject *object)
        g_mutex_clear (&priv->busy_mailboxes_lock);
        g_hash_table_destroy (priv->busy_mailboxes);
        g_hash_table_destroy (priv->idle_mailboxes);
+       g_mutex_clear (&priv->idle_refresh_lock);
+       g_hash_table_destroy (priv->idle_refresh_mailboxes);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (camel_imapx_conn_manager_parent_class)->finalize (object);
@@ -679,10 +695,12 @@ camel_imapx_conn_manager_init (CamelIMAPXConnManager *conn_man)
        g_cond_init (&conn_man->priv->busy_connections_cond);
        g_weak_ref_init (&conn_man->priv->store, NULL);
        g_mutex_init (&conn_man->priv->busy_mailboxes_lock);
+       g_mutex_init (&conn_man->priv->idle_refresh_lock);
 
        conn_man->priv->last_tagprefix = 'A' - 1;
        conn_man->priv->busy_mailboxes = g_hash_table_new_full (g_direct_hash, g_direct_equal, 
g_object_unref, NULL);
        conn_man->priv->idle_mailboxes = g_hash_table_new_full (g_direct_hash, g_direct_equal, 
g_object_unref, NULL);
+       conn_man->priv->idle_refresh_mailboxes = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, 
NULL);
 }
 
 static gchar
diff --git a/src/camel/providers/imapx/camel-imapx-server.c b/src/camel/providers/imapx/camel-imapx-server.c
index d6969a6..d94a4f7 100644
--- a/src/camel/providers/imapx/camel-imapx-server.c
+++ b/src/camel/providers/imapx/camel-imapx-server.c
@@ -796,9 +796,36 @@ imapx_untagged_expunge (CamelIMAPXServer *is,
        /* Ignore EXPUNGE responses when not running a COPY(MOVE)_MESSAGE job */
        if (!is->priv->current_command || (is->priv->current_command->job_kind != 
CAMEL_IMAPX_JOB_COPY_MESSAGE &&
            is->priv->current_command->job_kind != CAMEL_IMAPX_JOB_MOVE_MESSAGE)) {
+               gboolean ignored = TRUE;
+               gboolean is_idle_command = is->priv->current_command && is->priv->current_command->job_kind 
== CAMEL_IMAPX_JOB_IDLE;
+
                COMMAND_UNLOCK (is);
 
-               c (is->priv->tagprefix, "ignoring untagged expunge: %lu\n", expunged_idx);
+               /* Process only untagged EXPUNGE responses within ongoing IDLE command */
+               if (is_idle_command) {
+                       CamelIMAPXMailbox *mailbox;
+
+                       mailbox = camel_imapx_server_ref_selected (is);
+                       if (mailbox) {
+                               guint32 messages;
+
+                               messages = camel_imapx_mailbox_get_messages (mailbox);
+                               if (messages > 0) {
+                                       camel_imapx_mailbox_set_messages (mailbox, messages - 1);
+
+                                       ignored = FALSE;
+                                       c (is->priv->tagprefix, "going to refresh mailbox '%s' due to 
untagged expunge: %lu\n", camel_imapx_mailbox_get_name (mailbox), expunged_idx);
+
+                                       g_signal_emit (is, signals[REFRESH_MAILBOX], 0, mailbox);
+                               }
+
+                               g_object_unref (mailbox);
+                       }
+               }
+
+               if (ignored)
+                       c (is->priv->tagprefix, "ignoring untagged expunge: %lu\n", expunged_idx);
+
                return TRUE;
        }
 
@@ -973,10 +1000,9 @@ imapx_untagged_exists (CamelIMAPXServer *is,
                        GCancellable *cancellable,
                        GError **error)
 {
-       CamelFolder *folder;
        CamelIMAPXMailbox *mailbox;
        guint32 exists;
-       gboolean success = TRUE;
+       gboolean success = TRUE, changed;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
@@ -994,20 +1020,12 @@ imapx_untagged_exists (CamelIMAPXServer *is,
                camel_imapx_mailbox_get_messages (mailbox),
                exists);
 
+       changed = camel_imapx_mailbox_get_messages (mailbox) != exists;
        camel_imapx_mailbox_set_messages (mailbox, exists);
 
-       folder = imapx_server_ref_folder (is, mailbox);
-       g_return_val_if_fail (folder != NULL, FALSE);
-
-       if (camel_imapx_server_is_in_idle (is)) {
-               guint count;
+       if (changed && camel_imapx_server_is_in_idle (is))
+               g_signal_emit (is, signals[REFRESH_MAILBOX], 0, mailbox);
 
-               count = camel_folder_summary_count (camel_folder_get_folder_summary (folder));
-               if (count < exists)
-                       g_signal_emit (is, signals[REFRESH_MAILBOX], 0, mailbox);
-       }
-
-       g_object_unref (folder);
        g_object_unref (mailbox);
 
        return success;
@@ -1340,6 +1358,26 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
 
                        if (free_user_flags)
                                camel_named_flags_free (server_user_flags);
+
+                       if (camel_imapx_server_is_in_idle (is) && !camel_folder_is_frozen (folder)) {
+                               CamelFolderChangeInfo *changes = NULL;
+
+                               g_mutex_lock (&is->priv->changes_lock);
+
+                               if (camel_folder_change_info_changed (is->priv->changes)) {
+                                       changes = is->priv->changes;
+                                       is->priv->changes = camel_folder_change_info_new ();
+                               }
+
+                               g_mutex_unlock (&is->priv->changes_lock);
+
+                               if (changes) {
+                                       imapx_update_store_summary (folder);
+                                       camel_folder_changed (folder, changes);
+
+                                       camel_folder_change_info_free (changes);
+                               }
+                       }
                }
 
                g_clear_object (&mailbox);


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