[evolution-data-server] Bug 719328 - [IMAPx] Fails to update folder content with QResync



commit 4f5658d59317d65250f57e9ef9bea31891a12299
Author: Milan Crha <mcrha redhat com>
Date:   Fri Dec 7 12:48:45 2018 +0100

    Bug 719328 - [IMAPx] Fails to update folder content with QResync
    
    Closes https://bugzilla.gnome.org/show_bug.cgi?id=719328

 src/camel/providers/imapx/camel-imapx-server.c | 132 +++++++++++++++++--------
 src/camel/providers/imapx/camel-imapx-utils.c  |  64 +++++++++---
 src/camel/providers/imapx/camel-imapx-utils.h  |   5 +
 3 files changed, 144 insertions(+), 57 deletions(-)
---
diff --git a/src/camel/providers/imapx/camel-imapx-server.c b/src/camel/providers/imapx/camel-imapx-server.c
index 04d88c51b..91b13609a 100644
--- a/src/camel/providers/imapx/camel-imapx-server.c
+++ b/src/camel/providers/imapx/camel-imapx-server.c
@@ -846,6 +846,43 @@ imapx_untagged_expunge (CamelIMAPXServer *is,
        return TRUE;
 }
 
+typedef struct _GatherExistingUidsData {
+       CamelIMAPXServer *is;
+       CamelFolderSummary *summary;
+       GList *uid_list;
+       guint32 n_uids;
+} GatherExistingUidsData;
+
+static gboolean
+imapx_gather_existing_uids_cb (guint32 uid,
+                              gpointer user_data)
+{
+       GatherExistingUidsData *geud = user_data;
+       gchar *uid_str;
+
+       g_return_val_if_fail (geud != NULL, FALSE);
+       g_return_val_if_fail (geud->is != NULL, FALSE);
+       g_return_val_if_fail (geud->summary != NULL, FALSE);
+
+       geud->n_uids++;
+
+       uid_str = g_strdup_printf ("%u", uid);
+
+       if (camel_folder_summary_check_uid (geud->summary, uid_str)) {
+               e (geud->is->priv->tagprefix, "vanished known UID: %u\n", uid);
+               if (!geud->uid_list)
+                       g_mutex_lock (&geud->is->priv->changes_lock);
+
+               geud->uid_list = g_list_prepend (geud->uid_list, uid_str);
+               camel_folder_change_info_remove_uid (geud->is->priv->changes, uid_str);
+       } else {
+               e (geud->is->priv->tagprefix, "vanished unknown UID: %u\n", uid);
+               g_free (uid_str);
+       }
+
+       return TRUE;
+}
+
 static gboolean
 imapx_untagged_vanished (CamelIMAPXServer *is,
                          GInputStream *input_stream,
@@ -854,10 +891,8 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
 {
        CamelFolder *folder;
        CamelIMAPXMailbox *mailbox;
-       GArray *uids;
-       GList *uid_list = NULL;
+       GatherExistingUidsData geud;
        gboolean unsolicited = TRUE;
-       guint ii = 0;
        guint len = 0;
        guchar *token = NULL;
        gint tok = 0;
@@ -885,59 +920,53 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
                        tok, token, len);
        }
 
-       uids = imapx_parse_uids (
-               CAMEL_IMAPX_INPUT_STREAM (input_stream), cancellable, error);
-       if (uids == NULL)
-               return FALSE;
+       g_return_val_if_fail (is->priv->changes != NULL, FALSE);
 
        mailbox = camel_imapx_server_ref_pending_or_selected (is);
-
        g_return_val_if_fail (mailbox != NULL, FALSE);
 
        folder = imapx_server_ref_folder (is, mailbox);
        g_return_val_if_fail (folder != NULL, FALSE);
 
+       geud.is = is;
+       geud.summary = camel_folder_get_folder_summary (folder);
+       geud.uid_list = NULL;
+       geud.n_uids = 0;
+
+       if (!imapx_parse_uids_with_callback (CAMEL_IMAPX_INPUT_STREAM (input_stream), 
imapx_gather_existing_uids_cb, &geud, cancellable, error)) {
+               g_object_unref (folder);
+               g_object_unref (mailbox);
+               return FALSE;
+       }
+
+       /* It's locked by imapx_gather_existing_uids_cb() when the first known UID is found */
+       if (geud.uid_list)
+               g_mutex_unlock (&is->priv->changes_lock);
+
        if (unsolicited) {
                guint32 messages;
 
                messages = camel_imapx_mailbox_get_messages (mailbox);
 
-               if (messages < uids->len) {
+               if (messages < geud.n_uids) {
                        c (
                                is->priv->tagprefix,
                                "Error: mailbox messages (%u) is "
                                "fewer than vanished %u\n",
-                               messages, uids->len);
+                               messages, geud.n_uids);
                        messages = 0;
                } else {
-                       messages -= uids->len;
+                       messages -= geud.n_uids;
                }
 
                camel_imapx_mailbox_set_messages (mailbox, messages);
        }
 
-       g_return_val_if_fail (is->priv->changes != NULL, FALSE);
-
-       g_mutex_lock (&is->priv->changes_lock);
-
-       for (ii = 0; ii < uids->len; ii++) {
-               guint32 uid;
-               gchar *str;
-
-               uid = g_array_index (uids, guint32, ii);
-
-               e (is->priv->tagprefix, "vanished: %u\n", uid);
-
-               str = g_strdup_printf ("%u", uid);
-               uid_list = g_list_prepend (uid_list, str);
-               camel_folder_change_info_remove_uid (is->priv->changes, str);
+       if (geud.uid_list) {
+               geud.uid_list = g_list_reverse (geud.uid_list);
+               camel_folder_summary_remove_uids (geud.summary, geud.uid_list);
        }
 
-       g_mutex_unlock (&is->priv->changes_lock);
-
-       uid_list = g_list_reverse (uid_list);
-       camel_folder_summary_remove_uids (camel_folder_get_folder_summary (folder), uid_list);
-
        /* If the response is truly unsolicited (e.g. via NOTIFY)
         * then go ahead and emit the change notification now. */
        COMMAND_LOCK (is);
@@ -954,7 +983,7 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
 
                        g_mutex_unlock (&is->priv->changes_lock);
 
-                       camel_folder_summary_save (camel_folder_get_folder_summary (folder), NULL);
+                       camel_folder_summary_save (geud.summary, NULL);
                        imapx_update_store_summary (folder);
 
                        camel_folder_changed (folder, changes);
@@ -966,9 +995,7 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
                COMMAND_UNLOCK (is);
        }
 
-       g_list_free_full (uid_list, (GDestroyNotify) g_free);
-       g_array_free (uids, TRUE);
-
+       g_list_free_full (geud.uid_list, g_free);
        g_object_unref (folder);
        g_object_unref (mailbox);
 
@@ -1215,7 +1242,10 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
 
                        c (is->priv->tagprefix, "flag changed: %lu\n", is->priv->context->id);
 
-                       select_folder = imapx_server_ref_folder (is, select_mailbox);
+                       if (select_pending)
+                               select_folder = imapx_server_ref_folder (is, select_pending);
+                       else
+                               select_folder = imapx_server_ref_folder (is, select_mailbox);
                        if (!select_folder) {
                                g_warn_if_fail (select_folder != NULL);
 
@@ -1246,14 +1276,30 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
                                                camel_imapx_mailbox_get_permanentflags (select_mailbox),
                                                select_folder,
                                                (select_pending == NULL));
+                                       c (is->priv->tagprefix, "found uid %s in '%s', changed:%d\n", uid,
+                                               camel_folder_get_full_name (select_folder), changed);
                                } else {
                                        /* This (UID + FLAGS for previously unknown message) might
                                         * happen during a SELECT (QRESYNC). We should use it. */
-                                       c (is->priv->tagprefix, "flags changed for unknown uid %s\n.", uid);
+                                       c (is->priv->tagprefix, "flags changed for unknown uid %s in '%s'\n", 
uid,
+                                               camel_folder_get_full_name (select_folder));
                                }
                        }
 
                        if (changed) {
+                               CamelIMAPXSummary *imapx_summary;
+
+                               imapx_summary = CAMEL_IMAPX_SUMMARY (camel_folder_get_folder_summary 
(select_folder));
+
+                               if (imapx_summary && (finfo->got & FETCH_MODSEQ) != 0 &&
+                                   imapx_summary->modseq < finfo->modseq) {
+                                       c (is->priv->tagprefix, "updating summary modseq %" G_GUINT64_FORMAT 
"~>%" G_GUINT64_FORMAT " in '%s'\n",
+                                               imapx_summary->modseq, finfo->modseq, 
camel_folder_get_full_name (select_folder));
+                                       imapx_summary->modseq = finfo->modseq;
+
+                                       camel_folder_summary_touch (CAMEL_FOLDER_SUMMARY (imapx_summary));
+                               }
+
                                g_mutex_lock (&is->priv->changes_lock);
                                if (is->priv->changes)
                                        camel_folder_change_info_change_uid (is->priv->changes, uid);
@@ -2487,7 +2533,7 @@ imapx_completion (CamelIMAPXServer *is,
 
                        g_mutex_unlock (&is->priv->changes_lock);
 
-                       mailbox = camel_imapx_server_ref_selected (is);
+                       mailbox = camel_imapx_server_ref_pending_or_selected (is);
 
                        g_warn_if_fail (mailbox != NULL);
 
@@ -5501,12 +5547,13 @@ camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
                                is->priv->tagprefix,
                                "Eep, after QRESYNC we're out of sync. "
                                "total %u / %u, unread %u / %u, modseq %"
-                               G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
+                               G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT " in folder:'%s'\n",
                                total, messages,
                                camel_folder_summary_get_unread_count (CAMEL_FOLDER_SUMMARY (imapx_summary)),
                                unseen,
                                imapx_summary->modseq,
-                               highestmodseq);
+                               highestmodseq,
+                               camel_folder_get_full_name (folder));
                } else {
                        imapx_summary->uidnext = uidnext;
 
@@ -5518,12 +5565,13 @@ camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
                                is->priv->tagprefix,
                                "OK, after QRESYNC we're still in sync. "
                                "total %u / %u, unread %u / %u, modseq %"
-                               G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "\n",
+                               G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT " in folder:'%s'\n",
                                total, messages,
                                camel_folder_summary_get_unread_count (CAMEL_FOLDER_SUMMARY (imapx_summary)),
                                unseen,
                                imapx_summary->modseq,
-                               highestmodseq);
+                               highestmodseq,
+                               camel_folder_get_full_name (folder));
                        g_object_unref (folder);
                        return TRUE;
                }
diff --git a/src/camel/providers/imapx/camel-imapx-utils.c b/src/camel/providers/imapx/camel-imapx-utils.c
index dad33a7a3..a77a634af 100644
--- a/src/camel/providers/imapx/camel-imapx-utils.c
+++ b/src/camel/providers/imapx/camel-imapx-utils.c
@@ -2232,37 +2232,51 @@ exit:
        return finfo;
 }
 
-GArray *
-imapx_parse_uids (CamelIMAPXInputStream *stream,
-                  GCancellable *cancellable,
-                  GError **error)
+static gboolean
+imapx_fill_uids_array_cb (guint32 uid,
+                         gpointer user_data)
 {
-       GArray *array;
+       GArray *array = user_data;
+
+       g_return_val_if_fail (array != NULL, FALSE);
+
+       g_array_append_val (array, uid);
+
+       return TRUE;
+}
+
+gboolean
+imapx_parse_uids_with_callback (CamelIMAPXInputStream *stream,
+                               gboolean (* func) (guint32 uid, gpointer user_data),
+                               gpointer user_data,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+       gboolean can_continue = TRUE;
        guchar *token = NULL;
        gchar **splits;
-       guint len, str_len;
+       guint len;
        gint tok, ii;
 
-       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (stream), NULL);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (stream), FALSE);
+       g_return_val_if_fail (func != NULL, FALSE);
 
        tok = camel_imapx_input_stream_token (
                stream, &token, &len, cancellable, error);
        if (tok < 0)
-               return NULL;
+               return FALSE;
 
        if (!token) {
                g_set_error (error, CAMEL_IMAPX_ERROR, CAMEL_IMAPX_ERROR_IGNORE, "server response truncated");
 
                camel_imapx_input_stream_ungettoken (stream, tok, token, len);
 
-               return NULL;
+               return FALSE;
        }
 
-       array = g_array_new (FALSE, FALSE, sizeof (guint32));
        splits = g_strsplit ((gchar *) token, ",", -1);
-       str_len = g_strv_length (splits);
 
-       for (ii = 0; ii < str_len; ii++) {
+       for (ii = 0; can_continue && splits[ii]; ii++) {
                guint32 uid;
 
                if (g_strstr_len (splits[ii], -1, ":")) {
@@ -2270,18 +2284,38 @@ imapx_parse_uids (CamelIMAPXInputStream *stream,
                        guint32 first = strtoul (seq[0], NULL, 10);
                        guint32 last = strtoul (seq[1], NULL, 10);
 
-                       for (uid = first; uid <= last; uid++)
-                               g_array_append_val (array, uid);
+                       for (uid = first; uid <= last && can_continue; uid++) {
+                               can_continue = func (uid, user_data);
+                       }
 
                        g_strfreev (seq);
                } else {
                        uid = strtoul (splits[ii], NULL, 10);
-                       g_array_append_val (array, uid);
+                       can_continue = func (uid, user_data);
                }
        }
 
        g_strfreev (splits);
 
+       return TRUE;
+}
+
+GArray *
+imapx_parse_uids (CamelIMAPXInputStream *stream,
+                  GCancellable *cancellable,
+                  GError **error)
+{
+       GArray *array;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (stream), NULL);
+
+       array = g_array_new (FALSE, FALSE, sizeof (guint32));
+
+       if (!imapx_parse_uids_with_callback (stream, imapx_fill_uids_array_cb, array, cancellable, error)) {
+               g_array_free (array, TRUE);
+               array = NULL;
+       }
+
        return array;
 }
 
diff --git a/src/camel/providers/imapx/camel-imapx-utils.h b/src/camel/providers/imapx/camel-imapx-utils.h
index 202b40e7e..a379b075b 100644
--- a/src/camel/providers/imapx/camel-imapx-utils.h
+++ b/src/camel/providers/imapx/camel-imapx-utils.h
@@ -136,6 +136,11 @@ enum {
 GArray *       imapx_parse_uids                (CamelIMAPXInputStream *stream,
                                                 GCancellable *cancellable,
                                                 GError **error);
+gboolean       imapx_parse_uids_with_callback  (CamelIMAPXInputStream *stream,
+                                                gboolean (* func) (guint32 uid, gpointer user_data),
+                                                gpointer user_data,
+                                                GCancellable *cancellable,
+                                                GError **error);
 gboolean       imapx_parse_flags               (CamelIMAPXInputStream *stream,
                                                 guint32 *flagsp,
                                                 CamelNamedFlags *user_flags,


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