summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2018-12-07 12:48:45 +0100
committerMilan Crha <mcrha@redhat.com>2018-12-07 12:48:45 +0100
commit4f5658d59317d65250f57e9ef9bea31891a12299 (patch)
tree57ca000e952a9a3246e08d5b5abf1e22eeb968ee
parent22e7599537b8dd6894ad1d5e17440ce2810e36e5 (diff)
downloadevolution-data-server-4f5658d59317d65250f57e9ef9bea31891a12299.tar.gz
Bug 719328 - [IMAPx] Fails to update folder content with QResync
Closes https://bugzilla.gnome.org/show_bug.cgi?id=719328
-rw-r--r--src/camel/providers/imapx/camel-imapx-server.c132
-rw-r--r--src/camel/providers/imapx/camel-imapx-utils.c64
-rw-r--r--src/camel/providers/imapx/camel-imapx-utils.h5
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,