[evolution-data-server] Add camel_imapx_command_add_qresync_parameter().



commit 89b3af25c429bb57db9f4e38d31a862c2dca98df
Author: Matthew Barnes <mbarnes redhat com>
Date:   Thu May 30 15:00:58 2013 -0400

    Add camel_imapx_command_add_qresync_parameter().
    
    This splits a big wad of extra logic in imapx_select() out into a nice
    and tidy utility function.
    
    One important change, however, is the message sequence match data stops
    at the lesser message count reported by the IMAP server vs. our summary.
    
    This is to work around a frequent Zimbra IMAP failure where listing a
    message sequence number in a QRESYNC parameter which exceeds the true
    message count results in a so-called "parse error" from Zimbra:
    
       A00010 SELECT INBOX (QRESYNC (... (1,5,10 ...)))
       * 9 EXISTS
       ...
       A00010 BAD parse error: invalid message sequence number: 1,5,10
    
    This scenario can happen if messages have been expunged from the
    folder, but our summary has not yet been updated to reflect that.
    
    Not sure if this is a Zimbra bug.  I certainly would not call it a
    "parse error", but RFC 5162 is not clear on this detail.

 camel/camel-imapx-server.c |   76 +--------------------------
 camel/camel-imapx-utils.c  |  126 ++++++++++++++++++++++++++++++++++++++++++++
 camel/camel-imapx-utils.h  |   10 ++++
 3 files changed, 138 insertions(+), 74 deletions(-)
---
diff --git a/camel/camel-imapx-server.c b/camel/camel-imapx-server.c
index 3fc0e0b..d436bdb 100644
--- a/camel/camel-imapx-server.c
+++ b/camel/camel-imapx-server.c
@@ -3660,80 +3660,8 @@ imapx_select (CamelIMAPXServer *is,
        ic = camel_imapx_command_new (
                is, "SELECT", NULL, "SELECT %f", folder);
 
-       if (is->use_qresync) {
-               CamelIMAPXSummary *isum = (CamelIMAPXSummary *) folder->summary;
-               CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *) folder;
-               gint total = camel_folder_summary_count (folder->summary);
-               gchar *firstuid, *lastuid;
-
-               if (total && isum->modseq && ifolder->uidvalidity_on_server) {
-
-                       firstuid = camel_imapx_dup_uid_from_summary_index (folder, 0);
-                       lastuid = camel_imapx_dup_uid_from_summary_index (folder, total - 1);
-
-                       c (
-                               is->tagprefix, "SELECT QRESYNC %" G_GUINT64_FORMAT
-                               " %" G_GUINT64_FORMAT "\n",
-                               ifolder->uidvalidity_on_server, isum->modseq);
-
-                       camel_imapx_command_add (
-                               ic, " (QRESYNC (%"
-                               G_GUINT64_FORMAT " %"
-                               G_GUINT64_FORMAT " %s:%s",
-                               ifolder->uidvalidity_on_server,
-                               isum->modseq,
-                               firstuid, lastuid);
-
-                       g_free (firstuid);
-                       g_free (lastuid);
-
-                       if (total > 10) {
-                               gint i;
-                               GString *seqs, *uids;
-
-                               seqs = g_string_new (" ");
-                               uids = g_string_new (")");
-
-                               /* Include some seq/uid pairs to avoid a huge VANISHED list
-                                * (see RFC5162 ยง3.1). Work backwards exponentially from the
-                                * end of the mailbox, starting with the message 9 from the
-                                * end, then 27 from the end, then 81 from the end... */
-                               i = 3;
-                               do {
-                                       gchar buf[10];
-                                       gchar *uid;
-                                       i *= 3;
-                                       if (i > total)
-                                               i = total;
-
-                                       if (i != 9) { /* If not the first time */
-                                               g_string_prepend (seqs, ",");
-                                               g_string_prepend (uids, ",");
-                                       }
-
-                                       /* IMAP sequence numbers are one higher than the corresponding
-                                        * indices in our folder summary -- they start from one, while
-                                        * the summary starts from zero. */
-                                       sprintf (buf, "%d", total - i + 1);
-                                       g_string_prepend (seqs, buf);
-                                       uid = camel_imapx_dup_uid_from_summary_index (folder, total - i);
-                                       g_string_prepend (uids, uid);
-                                       g_free (uid);
-                               } while (i < total);
-
-                               g_string_prepend (seqs, " (");
-
-                               c (is->tagprefix, "adding QRESYNC seq/uidset %s%s\n", seqs->str, uids->str);
-                               camel_imapx_command_add (ic, seqs->str);
-                               camel_imapx_command_add (ic, uids->str);
-
-                               g_string_free (seqs, TRUE);
-                               g_string_free (uids, TRUE);
-
-                       }
-                       camel_imapx_command_add (ic, "))");
-               }
-       }
+       if (is->use_qresync)
+               camel_imapx_command_add_qresync_parameter (ic, folder);
 
        ic->complete = imapx_command_select_done;
        imapx_command_start (is, ic, cancellable, error);
diff --git a/camel/camel-imapx-utils.c b/camel/camel-imapx-utils.c
index ddad75a..24fcdd5 100644
--- a/camel/camel-imapx-utils.c
+++ b/camel/camel-imapx-utils.c
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <string.h>
 
+#include "camel-imapx-command.h"
 #include "camel-imapx-folder.h"
 #include "camel-imapx-settings.h"
 #include "camel-imapx-stream.h"
@@ -2045,6 +2046,131 @@ imapx_free_list (struct _list_info *linfo)
 }
 
 gboolean
+camel_imapx_command_add_qresync_parameter (CamelIMAPXCommand *ic,
+                                           CamelFolder *folder)
+{
+       /* See RFC 5162 Section 3.1 */
+
+       CamelIMAPXFolder *imapx_folder;
+       CamelIMAPXSummary *imapx_summary;
+       guint64 last_known_uidvalidity;
+       guint64 last_known_modsequence;
+       guint32 last_known_message_cnt;
+       guint32 sequence_limit;
+       gchar *known_uid_set = NULL;
+       gint summary_total;
+       gboolean parameter_added = FALSE;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), FALSE);
+       g_return_val_if_fail (CAMEL_IS_IMAPX_FOLDER (folder), FALSE);
+
+       imapx_folder = CAMEL_IMAPX_FOLDER (folder);
+       imapx_summary = CAMEL_IMAPX_SUMMARY (folder->summary);
+
+       last_known_uidvalidity = imapx_folder->uidvalidity_on_server;
+       last_known_modsequence = imapx_summary->modseq;
+       last_known_message_cnt = imapx_folder->exists_on_server;
+
+       /* XXX This should return an unsigned integer to
+        *     avoid the possibility of a negative count. */
+       summary_total = camel_folder_summary_count (folder->summary);
+       g_return_val_if_fail (summary_total >= 0, FALSE);
+
+       if (summary_total > 0) {
+               guint last = summary_total - 1;
+               gchar *begin, *end;
+
+               begin = camel_imapx_dup_uid_from_summary_index (folder, 0);
+               end = camel_imapx_dup_uid_from_summary_index (folder, last);
+
+               if (begin != NULL && end != NULL)
+                       known_uid_set = g_strconcat (begin, ":", end, NULL);
+
+               g_free (begin);
+               g_free (end);
+       }
+
+       /* Make sure we have valid QRESYNC arguments. */
+
+       if (last_known_uidvalidity == 0)
+               goto exit;
+
+       if (last_known_modsequence == 0)
+               goto exit;
+
+       if (known_uid_set == NULL)
+               goto exit;
+
+       camel_imapx_command_add (
+               ic, " (QRESYNC (%"
+               G_GUINT64_FORMAT " %"
+               G_GUINT64_FORMAT " %s",
+               last_known_uidvalidity,
+               last_known_modsequence,
+               known_uid_set);
+
+       /* Add message sequence match data if we have enough messages. */
+
+       /* XXX Some IMAP servers like Zimbra can't handle invalid sequence
+        *     numbers in the optional seq/uid list.  So limit the list to
+        *     the lesser of the last known message count according to the
+        *     server and our own summary count. */
+       sequence_limit = MIN (last_known_message_cnt, summary_total);
+
+       if (sequence_limit > 10) {
+               GString *seqs;
+               GString *uids;
+               guint32 ii = 3;
+
+               seqs = g_string_sized_new (256);
+               uids = g_string_sized_new (256);
+
+               /* Include some seq/uid pairs to avoid a huge VANISHED list.
+                * Work backwards exponentially from the end of the mailbox,
+                * starting with message 9 from the end, then 27 from the
+                * end, then 81 from the end, etc. */
+               do {
+                       guint32 summary_index;
+                       gchar buf[10];
+                       gchar *uid;
+
+                       ii = MIN (ii * 3, sequence_limit);
+                       summary_index = sequence_limit - ii;
+
+                       if (seqs->len > 0)
+                               g_string_prepend_c (seqs, ',');
+
+                       if (uids->len > 0)
+                               g_string_prepend_c (uids, ',');
+
+                       /* IMAP sequence numbers are 1-based,
+                        * but our folder summary is 0-based. */
+                       sprintf (buf, "%" G_GUINT32_FORMAT, summary_index + 1);
+
+                       uid = camel_imapx_dup_uid_from_summary_index (
+                               folder, summary_index);
+                       if (uid != NULL) {
+                               g_string_prepend (seqs, buf);
+                               g_string_prepend (uids, uid);
+                               g_free (uid);
+                       }
+               } while (ii < sequence_limit);
+
+               camel_imapx_command_add (
+                       ic, " (%s %s)", seqs->str, uids->str);
+       }
+
+       camel_imapx_command_add (ic, "))");
+
+       parameter_added = TRUE;
+
+exit:
+       g_free (known_uid_set);
+
+       return parameter_added;
+}
+
+gboolean
 camel_imapx_parse_quota (CamelIMAPXStream *is,
                          GCancellable *cancellable,
                          gchar **out_quota_root_name,
diff --git a/camel/camel-imapx-utils.h b/camel/camel-imapx-utils.h
index 18ec6ab..8c27963 100644
--- a/camel/camel-imapx-utils.h
+++ b/camel/camel-imapx-utils.h
@@ -28,6 +28,10 @@
 
 G_BEGIN_DECLS
 
+/* FIXME Split off a camel-imapx-types.h file with supplemental
+ *       enum/struct definitions and helper macros, so we don't
+ *       have these conflicting header dependencies. */
+struct _CamelIMAPXCommand;
 struct _CamelIMAPXStream;
 struct _CamelFlag;
 struct _CamelIMAPXNamespaceList;
@@ -343,6 +347,12 @@ void               imapx_free_list                 (struct _list_info *linfo);
 
 /* ********************************************************************** */
 
+gboolean       camel_imapx_command_add_qresync_parameter
+                                               (struct _CamelIMAPXCommand *ic,
+                                                CamelFolder *folder);
+
+/* ********************************************************************** */
+
 gboolean       camel_imapx_parse_quota         (struct _CamelIMAPXStream *is,
                                                 GCancellable *cancellable,
                                                 gchar **out_quota_root_name,


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