[evolution-data-server] Add CamelIMAPXListResponse.



commit 999efb956818ec830cd80c8ded4a54b43b23657d
Author: Matthew Barnes <mbarnes redhat com>
Date:   Mon Jul 29 10:40:44 2013 -0400

    Add CamelIMAPXListResponse.
    
    Represents an IMAP LIST response, including LIST-EXTENDED information.
    
    Replaces the "list_info" struct and associated functions.
    
    New functions:
    
      camel_imapx_list_response_new()
      camel_imapx_list_response_hash()
      camel_imapx_list_response_equal()
      camel_imapx_list_response_compare()
      camel_imapx_list_response_get_mailbox()
      camel_imapx_list_response_get_separator()
      camel_imapx_list_response_add_flag()
      camel_imapx_list_response_has_flag()
      camel_imapx_list_response_get_childinfo()
      camel_imapx_list_response_get_summary_flags()
    
    Removed functions:
    
      imapx_parse_list()
      imapx_list_get_path()
      imapx_free_list()

 camel/Makefile.am                       |    2 +
 camel/camel-imapx-list-response.c       |  484 +++++++++++++++++++++++++++++++
 camel/camel-imapx-list-response.h       |  115 ++++++++
 camel/camel-imapx-server.c              |   90 ++----
 camel/camel-imapx-store.c               |   42 ++-
 camel/camel-imapx-utils.c               |  104 -------
 camel/camel-imapx-utils.h               |   17 -
 camel/camel.h                           |    1 +
 docs/reference/camel/camel-docs.sgml    |    1 +
 docs/reference/camel/camel-sections.txt |   35 +++
 docs/reference/camel/camel.types        |    1 +
 11 files changed, 699 insertions(+), 193 deletions(-)
---
diff --git a/camel/Makefile.am b/camel/Makefile.am
index 7483e58..02f8c1e 100644
--- a/camel/Makefile.am
+++ b/camel/Makefile.am
@@ -178,6 +178,7 @@ libcamel_1_2_la_SOURCES =                   \
        camel-imapx-command.c                   \
        camel-imapx-folder.c                    \
        camel-imapx-job.c                       \
+       camel-imapx-list-response.c             \
        camel-imapx-search.c                    \
        camel-imapx-server.c                    \
        camel-imapx-settings.c                  \
@@ -312,6 +313,7 @@ libcamelinclude_HEADERS =                   \
        camel-imapx-command.h                   \
        camel-imapx-folder.h                    \
        camel-imapx-job.h                       \
+       camel-imapx-list-response.h             \
        camel-imapx-search.h                    \
        camel-imapx-server.h                    \
        camel-imapx-settings.h                  \
diff --git a/camel/camel-imapx-list-response.c b/camel/camel-imapx-list-response.c
new file mode 100644
index 0000000..cc42579
--- /dev/null
+++ b/camel/camel-imapx-list-response.c
@@ -0,0 +1,484 @@
+/*
+ * camel-imapx-list-response.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/**
+ * SECTION: camel-imapx-list-response
+ * @include: camel/camel.h
+ * @short_description: Stores an IMAP LIST response
+ *
+ * #CamelIMAPXListResponse encapsulates an IMAP LIST response, which consists
+ * of a set of mailbox attributes, a mailbox separator character, and the
+ * mailbox name.  (Extended information for LIST responses, as described in
+ * <ulink url="http://tools.ietf.org/html/rfc5258";>RFC 5258</ulink>, to be
+ * supported at a later date.)
+ *
+ * #CamelIMAPXListResponse can also convert the mailbox attributes to
+ * a #CamelStoreInfoFlags / #CamelFolderInfoFlags value for use with
+ * camel_store_get_folder_info().
+ **/
+
+#include "camel-imapx-list-response.h"
+
+#define CAMEL_IMAPX_LIST_RESPONSE_GET_PRIVATE(obj) \
+       (G_TYPE_INSTANCE_GET_PRIVATE \
+       ((obj), CAMEL_TYPE_IMAPX_LIST_RESPONSE, CamelIMAPXListResponsePrivate))
+
+struct _CamelIMAPXListResponsePrivate {
+       gchar *mailbox;
+       gchar separator;
+       GQueue attributes;
+};
+
+G_DEFINE_TYPE (
+       CamelIMAPXListResponse,
+       camel_imapx_list_response,
+       G_TYPE_OBJECT)
+
+static void
+imapx_list_response_finalize (GObject *object)
+{
+       CamelIMAPXListResponsePrivate *priv;
+
+       priv = CAMEL_IMAPX_LIST_RESPONSE_GET_PRIVATE (object);
+
+       g_free (priv->mailbox);
+
+       /* Flag strings are interned, so don't free them. */
+       g_queue_clear (&priv->attributes);
+
+       /* Chain up to parent's finalize() method. */
+       G_OBJECT_CLASS (camel_imapx_list_response_parent_class)->
+               finalize (object);
+}
+
+static void
+camel_imapx_list_response_class_init (CamelIMAPXListResponseClass *class)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (
+               class, sizeof (CamelIMAPXListResponsePrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->finalize = imapx_list_response_finalize;
+}
+
+static void
+camel_imapx_list_response_init (CamelIMAPXListResponse *response)
+{
+       response->priv = CAMEL_IMAPX_LIST_RESPONSE_GET_PRIVATE (response);
+}
+
+/**
+ * camel_imapx_list_response_new:
+ * @stream: a #CamelIMAPXStream
+ * @cancellable: a #GCancellable
+ * @error: return location for a #GError, or %NULL
+ *
+ * Attempts to parse an IMAP LIST response from @stream and, if successful,
+ * stores the response data in a new #CamelIMAPXListResponse.  If an error
+ * occurs, the function sets @error and returns %NULL.
+ *
+ * Returns: a #CamelIMAPXListResponse, or %NULL
+ *
+ * Since: 3.10
+ **/
+CamelIMAPXListResponse *
+camel_imapx_list_response_new (CamelIMAPXStream *stream,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+       CamelIMAPXListResponse *response;
+       camel_imapx_token_t tok;
+       guchar *token;
+       guint len;
+       const gchar *attribute;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (stream), NULL);
+
+       response = g_object_new (CAMEL_TYPE_IMAPX_LIST_RESPONSE, NULL);
+
+       /* Parse attributes. */
+
+       tok = camel_imapx_stream_token (
+               stream, &token, &len, cancellable, error);
+       if (tok == IMAPX_TOK_ERROR)
+               goto fail;
+       if (tok != '(') {
+               g_set_error (
+                       error, CAMEL_IMAPX_ERROR, 1,
+                       "list: expecting '('");
+               goto fail;
+       }
+
+       tok = camel_imapx_stream_token (
+               stream, &token, &len, cancellable, error);
+       while (tok == IMAPX_TOK_STRING || tok == IMAPX_TOK_TOKEN) {
+               camel_imapx_list_response_add_attribute (
+                       response, (gchar *) token);
+               tok = camel_imapx_stream_token (
+                       stream, &token, &len, cancellable, error);
+       }
+
+       if (tok == IMAPX_TOK_ERROR)
+               goto fail;
+       if (tok != ')') {
+               g_set_error (
+                       error, CAMEL_IMAPX_ERROR, 1,
+                       "list: expecting ')'");
+               goto fail;
+       }
+
+       /* Add implied attributes (see RFC 5258 section 3.4). */
+
+       /* "\NoInferiors" implies "\HasNoChildren" */
+       attribute = CAMEL_IMAPX_LIST_ATTR_NOINFERIORS;
+       if (camel_imapx_list_response_has_attribute (response, attribute)) {
+               attribute = CAMEL_IMAPX_LIST_ATTR_HASNOCHILDREN;
+               camel_imapx_list_response_add_attribute (response, attribute);
+       }
+
+       /* "\NonExistent" implies "\NoSelect" */
+       attribute = CAMEL_IMAPX_LIST_ATTR_NONEXISTENT;
+       if (camel_imapx_list_response_has_attribute (response, attribute)) {
+               attribute = CAMEL_IMAPX_LIST_ATTR_NOSELECT;
+               camel_imapx_list_response_add_attribute (response, attribute);
+       }
+
+       /* Parse separator. */
+
+       if (!camel_imapx_stream_nstring (stream, &token, cancellable, error))
+               goto fail;
+
+       if (token != NULL)
+               response->priv->separator = *token;
+       else
+               response->priv->separator = '\0';
+
+       /* Parse mailbox. */
+
+       response->priv->mailbox =
+               camel_imapx_parse_mailbox (stream, cancellable, error);
+       if (response->priv->mailbox == NULL)
+               goto fail;
+
+       /* Parse extended info (optional). */
+
+       /* FIXME Actually implement this. */
+
+       return response;
+
+fail:
+       g_clear_object (&response);
+
+       return NULL;
+}
+
+/**
+ * camel_imapx_list_response_hash:
+ * @response: a #CamelIMAPXListResponse
+ *
+ * Generates a hash value for @response based on the mailbox name.  This
+ * function is intended for easily hashing a #CamelIMAPXListResponse to
+ * add to a #GHashTable or similar data structure.
+ *
+ * Returns: a hash value for @response
+ *
+ * Since: 3.10
+ **/
+guint
+camel_imapx_list_response_hash (CamelIMAPXListResponse *response)
+{
+       const gchar *mailbox;
+
+       mailbox = camel_imapx_list_response_get_mailbox (response);
+
+       return g_str_hash (mailbox);
+}
+
+/**
+ * camel_imapx_list_response_equal:
+ * @response_a: the first #CamelIMAPXListResponse
+ * @response_b: the second #CamelIMAPXListResponse
+ *
+ * Checks two #CamelIMAPXListResponse instances for equality based on
+ * their mailbox names.
+ *
+ * Returns: %TRUE if @response_a and @response_b are equal
+ *
+ * Since: 3.10
+ **/
+gboolean
+camel_imapx_list_response_equal (CamelIMAPXListResponse *response_a,
+                                 CamelIMAPXListResponse *response_b)
+{
+       const gchar *mailbox_a;
+       const gchar *mailbox_b;
+
+       mailbox_a = camel_imapx_list_response_get_mailbox (response_a);
+       mailbox_b = camel_imapx_list_response_get_mailbox (response_b);
+
+       return g_str_equal (mailbox_a, mailbox_b);
+}
+
+/**
+ * camel_imapx_list_response_compare:
+ * @response_a: the first #CamelIMAPXListResponse
+ * @response_b: the second #CamelIMAPXListResponse
+ *
+ * Compares two #CamelIMAPXListResponse instances by their mailbox names.
+ *
+ * Returns: a negative value if @response_a compares before @response_b,
+ *          zero if they compare equal, or a positive value if @response_a
+ *          compares after @response_b
+ *
+ * Since: 3.10
+ **/
+gint
+camel_imapx_list_response_compare (CamelIMAPXListResponse *response_a,
+                                   CamelIMAPXListResponse *response_b)
+{
+       const gchar *mailbox_a;
+       const gchar *mailbox_b;
+
+       mailbox_a = camel_imapx_list_response_get_mailbox (response_a);
+       mailbox_b = camel_imapx_list_response_get_mailbox (response_b);
+
+       return g_strcmp0 (mailbox_a, mailbox_b);
+}
+
+/**
+ * camel_imapx_list_response_get_mailbox:
+ * @response: a #CamelIMAPXListResponse
+ *
+ * Returns the mailbox name for @response.
+ *
+ * Returns: the mailbox name
+ *
+ * Since: 3.10
+ **/
+const gchar *
+camel_imapx_list_response_get_mailbox (CamelIMAPXListResponse *response)
+{
+       g_return_val_if_fail (CAMEL_IS_IMAPX_LIST_RESPONSE (response), NULL);
+
+       return response->priv->mailbox;
+}
+
+/**
+ * camel_imapx_list_response_get_separator:
+ * @response: a #CamelIMAPXListResponse
+ *
+ * Returns the mailbox path separator character for @response.
+ *
+ * Returns: the mailbox patch separator character
+ *
+ * Since: 3.10
+ **/
+gchar
+camel_imapx_list_response_get_separator (CamelIMAPXListResponse *response)
+{
+       g_return_val_if_fail (CAMEL_IS_IMAPX_LIST_RESPONSE (response), '\0');
+
+       return response->priv->separator;
+}
+
+/* Flag macros appear here in the reference manual,
+ * so also documenting them here in the source code
+ * since the documentation is so repetitive. */
+
+/**
+ * CAMEL_IMAPX_LIST_ATTR_NOINFERIORS:
+ *
+ * Refer to <ulink url="http://tools.ietf.org/html/rfc3501#section-7.2.2";>
+ * RFC 3501 section 7.2.2</ulink>.
+ *
+ * Since: 3.10
+ **/
+
+/**
+ * CAMEL_IMAPX_LIST_ATTR_NOSELECT:
+ *
+ * Refer to <ulink url="http://tools.ietf.org/html/rfc3501#section-7.2.2";>
+ * RFC 3501 section 7.2.2</ulink>.
+ *
+ * Since: 3.10
+ **/
+
+/**
+ * CAMEL_IMAPX_LIST_ATTR_MARKED:
+ *
+ * Refer to <ulink url="http://tools.ietf.org/html/rfc3501#section-7.2.2";>
+ * RFC 3501 section 7.2.2</ulink>.
+ *
+ * Since: 3.10
+ **/
+
+/**
+ * CAMEL_IMAPX_LIST_ATTR_UNMARKED:
+ *
+ * Refer to <ulink url="http://tools.ietf.org/html/rfc3501#section-7.2.2";>
+ * RFC 3501 section 7.2.2</ulink>.
+ *
+ * Since: 3.10
+ **/
+
+/**
+ * CAMEL_IMAPX_LIST_ATTR_NONEXISTENT:
+ *
+ * Refer to <ulink url="http://tools.ietf.org/html/rfc5258#section-3";>
+ * RFC 5258 section 3</ulink>.
+ *
+ * Since: 3.10
+ **/
+
+/**
+ * CAMEL_IMAPX_LIST_ATTR_SUBSCRIBED:
+ *
+ * Refer to <ulink url="http://tools.ietf.org/html/rfc5258#section-3.1";>
+ * RFC 5258 section 3.1</ulink>.
+ *
+ * Since: 3.10
+ **/
+
+/**
+ * CAMEL_IMAPX_LIST_ATTR_REMOTE:
+ *
+ * Refer to <ulink url="http://tools.ietf.org/html/rfc5258#section-3.1";>
+ * RFC 5258 section 3.1</ulink>.
+ *
+ * Since: 3.10
+ **/
+
+/**
+ * CAMEL_IMAPX_LIST_ATTR_HASCHILDREN:
+ *
+ * Refer to <ulink url="http://tools.ietf.org/html/rfc5258#section-4";>
+ * RFC 5258 section 4</ulink>.
+ *
+ * Since: 3.10
+ **/
+
+/**
+ * CAMEL_IMAPX_LIST_ATTR_HASNOCHILDREN:
+ *
+ * Refer to <ulink url="http://tools.ietf.org/html/rfc5258#section-4";>
+ * RFC 5258 section 4</ulink>.
+ *
+ * Since: 3.10
+ **/
+
+/**
+ * camel_imapx_list_response_add_attribute:
+ * @response: a #CamelIMAPXListResponse
+ * @attribute: a mailbox attribute
+ *
+ * Adds a mailbox attribute to @response.  The @attribute should be one of
+ * the LIST attribute macros defined above.
+ *
+ * Since: 3.10
+ **/
+void
+camel_imapx_list_response_add_attribute (CamelIMAPXListResponse *response,
+                                         const gchar *attribute)
+{
+       g_return_if_fail (CAMEL_IS_IMAPX_LIST_RESPONSE (response));
+       g_return_if_fail (attribute != NULL);
+
+       /* Avoid duplicates. */
+       if (camel_imapx_list_response_has_attribute (response, attribute))
+               return;
+
+       g_queue_push_tail (
+               &response->priv->attributes,
+               (gpointer) g_intern_string (attribute));
+}
+
+/**
+ * camel_imapx_list_response_has_attribute:
+ * @response: a #CamelIMAPXListResponse
+ * @attribute: a mailbox attribute
+ *
+ * Returns whether @response includes the given mailbox attribute.  The
+ * @attribute should be one of the LIST attribute macros defined above.
+ *
+ * Returns: %TRUE if @response has @attribute, or else %FALSE
+ *
+ * Since: 3.10
+ **/
+gboolean
+camel_imapx_list_response_has_attribute (CamelIMAPXListResponse *response,
+                                         const gchar *attribute)
+{
+       GList *match;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_LIST_RESPONSE (response), FALSE);
+       g_return_val_if_fail (attribute != NULL, FALSE);
+
+       match = g_queue_find_custom (
+               &response->priv->attributes, attribute,
+               (GCompareFunc) g_ascii_strcasecmp);
+
+       return (match != NULL);
+}
+
+/**
+ * camel_imapx_list_response_get_summary_flags:
+ * @response: a #CamelIMAPXListResponse
+ *
+ * Converts the relevant mailbox attribute flags in @response to a
+ * #CamelStoreInfoFlags value.
+ *
+ * Returns: a #CamelStoreInfoFlags value
+ *
+ * Since: 3.10
+ **/
+CamelStoreInfoFlags
+camel_imapx_list_response_get_summary_flags (CamelIMAPXListResponse *response)
+{
+       CamelStoreInfoFlags store_info_flags = 0;
+       const gchar *flag;
+
+       g_return_val_if_fail (CAMEL_IS_IMAPX_LIST_RESPONSE (response), 0);
+
+       flag = CAMEL_IMAPX_LIST_ATTR_NOSELECT;
+       if (camel_imapx_list_response_has_attribute (response, flag))
+               store_info_flags |= CAMEL_STORE_INFO_FOLDER_NOSELECT;
+
+       flag = CAMEL_IMAPX_LIST_ATTR_NOINFERIORS;
+       if (camel_imapx_list_response_has_attribute (response, flag))
+               store_info_flags |= CAMEL_STORE_INFO_FOLDER_NOINFERIORS;
+
+       flag = CAMEL_IMAPX_LIST_ATTR_HASCHILDREN;
+       if (camel_imapx_list_response_has_attribute (response, flag))
+               store_info_flags |= CAMEL_STORE_INFO_FOLDER_CHILDREN;
+
+       flag = CAMEL_IMAPX_LIST_ATTR_HASNOCHILDREN;
+       if (camel_imapx_list_response_has_attribute (response, flag))
+               store_info_flags |= CAMEL_STORE_INFO_FOLDER_NOCHILDREN;
+
+       flag = CAMEL_IMAPX_LIST_ATTR_SUBSCRIBED;
+       if (camel_imapx_list_response_has_attribute (response, flag))
+               store_info_flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+
+       /* XXX Does "\Marked" mean CAMEL_STORE_INFO_FOLDER_FLAGGED?
+        *     Who the heck knows; the enum value is undocumented. */
+
+       return store_info_flags;
+}
+
diff --git a/camel/camel-imapx-list-response.h b/camel/camel-imapx-list-response.h
new file mode 100644
index 0000000..a9e8db7
--- /dev/null
+++ b/camel/camel-imapx-list-response.h
@@ -0,0 +1,115 @@
+/*
+ * camel-imapx-list-response.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#if !defined (__CAMEL_H_INSIDE__) && !defined (CAMEL_COMPILATION)
+#error "Only <camel/camel.h> can be included directly."
+#endif
+
+#ifndef CAMEL_IMAPX_LIST_RESPONSE_H
+#define CAMEL_IMAPX_LIST_RESPONSE_H
+
+#include <camel/camel.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_IMAPX_LIST_RESPONSE \
+       (camel_imapx_list_response_get_type ())
+#define CAMEL_IMAPX_LIST_RESPONSE(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), CAMEL_TYPE_IMAPX_LIST_RESPONSE, CamelIMAPXResponse))
+#define CAMEL_IMAPX_LIST_RESPONSE_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), CAMEL_TYPE_IMAPX_LIST_RESPONSE, CamelIMAPXResponseClass))
+#define CAMEL_IS_IMAPX_LIST_RESPONSE(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), CAMEL_TYPE_IMAPX_LIST_RESPONSE))
+#define CAMEL_IS_IMAPX_LIST_RESPONSE_CLASS(cls) \
+       (G_TYPE_CHECK_INSTANCE_CLASS \
+       ((cls), CAMEL_TYPE_IMAPX_LIST_RESPONSE))
+#define CAMEL_IMAPX_LIST_RESPONSE_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), CAMEL_TYPE_IMAPX_LIST_RESPONSE, CamelIMAPXResponseClass))
+
+/* RFC 3501 Standard Flags */
+#define CAMEL_IMAPX_LIST_ATTR_MARKED           "\\Marked"
+#define CAMEL_IMAPX_LIST_ATTR_NOINFERIORS      "\\NoInferiors"
+#define CAMEL_IMAPX_LIST_ATTR_NOSELECT         "\\NoSelect"
+#define CAMEL_IMAPX_LIST_ATTR_UNMARKED         "\\Unmarked"
+
+/* RFC 5258 "LIST-EXTENDED" Flags */
+#define CAMEL_IMAPX_LIST_ATTR_HASCHILDREN      "\\HasChildren"
+#define CAMEL_IMAPX_LIST_ATTR_HASNOCHILDREN    "\\HasNoChildren"
+#define CAMEL_IMAPX_LIST_ATTR_NONEXISTENT      "\\NonExistent"
+#define CAMEL_IMAPX_LIST_ATTR_REMOTE           "\\Remote"
+#define CAMEL_IMAPX_LIST_ATTR_SUBSCRIBED       "\\Subscribed"
+
+G_BEGIN_DECLS
+
+typedef struct _CamelIMAPXListResponse CamelIMAPXListResponse;
+typedef struct _CamelIMAPXListResponseClass CamelIMAPXListResponseClass;
+typedef struct _CamelIMAPXListResponsePrivate CamelIMAPXListResponsePrivate;
+
+/**
+ * CamelIMAPXListResponse:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.10
+ **/
+struct _CamelIMAPXListResponse {
+       GObject parent;
+       CamelIMAPXListResponsePrivate *priv;
+};
+
+struct _CamelIMAPXListResponseClass {
+       GObjectClass parent_class;
+};
+
+GType          camel_imapx_list_response_get_type
+                                       (void) G_GNUC_CONST;
+CamelIMAPXListResponse *
+               camel_imapx_list_response_new
+                                       (CamelIMAPXStream *stream,
+                                        GCancellable *cancellable,
+                                        GError **error);
+guint          camel_imapx_list_response_hash
+                                       (CamelIMAPXListResponse *response);
+gboolean       camel_imapx_list_response_equal
+                                       (CamelIMAPXListResponse *response_a,
+                                        CamelIMAPXListResponse *response_b);
+gint           camel_imapx_list_response_compare
+                                       (CamelIMAPXListResponse *response_a,
+                                        CamelIMAPXListResponse *response_b);
+const gchar *  camel_imapx_list_response_get_mailbox
+                                       (CamelIMAPXListResponse *response);
+gchar          camel_imapx_list_response_get_separator
+                                       (CamelIMAPXListResponse *response);
+void           camel_imapx_list_response_add_attribute
+                                       (CamelIMAPXListResponse *response,
+                                        const gchar *attribute);
+gboolean       camel_imapx_list_response_has_attribute
+                                       (CamelIMAPXListResponse *response,
+                                        const gchar *attribute);
+CamelStoreInfoFlags
+               camel_imapx_list_response_get_summary_flags
+                                       (CamelIMAPXListResponse *response);
+
+G_END_DECLS
+
+#endif /* CAMEL_IMAPX_LIST_RESPONSE_H */
+
diff --git a/camel/camel-imapx-server.c b/camel/camel-imapx-server.c
index 09b5872..c8519df 100644
--- a/camel/camel-imapx-server.c
+++ b/camel/camel-imapx-server.c
@@ -2026,17 +2026,22 @@ imapx_untagged_list (CamelIMAPXServer *is,
                      GCancellable *cancellable,
                      GError **error)
 {
-       struct _list_info *linfo = NULL;
+       CamelIMAPXListResponse *response;
        CamelIMAPXJob *job = NULL;
        ListData *data = NULL;
+       const gchar *mailbox;
+       gchar separator;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
-       linfo = imapx_parse_list (stream, cancellable, error);
-       if (linfo == NULL)
+       response = camel_imapx_list_response_new (stream, cancellable, error);
+       if (response == NULL)
                return FALSE;
 
-       job = imapx_match_active_job (is, IMAPX_JOB_LIST, linfo->name);
+       mailbox = camel_imapx_list_response_get_mailbox (response);
+       separator = camel_imapx_list_response_get_separator (response);
+
+       job = imapx_match_active_job (is, IMAPX_JOB_LIST, mailbox);
 
        data = camel_imapx_job_get_data (job);
        g_return_val_if_fail (data != NULL, FALSE);
@@ -2044,20 +2049,22 @@ imapx_untagged_list (CamelIMAPXServer *is,
        // TODO: we want to make sure the names match?
 
        if (data->flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) {
-               c (is->tagprefix, "lsub: '%s' (%c)\n", linfo->name, linfo->separator);
+               c (is->tagprefix, "lsub: '%s' (%c)\n", mailbox, separator);
        } else {
-               c (is->tagprefix, "list: '%s' (%c)\n", linfo->name, linfo->separator);
+               c (is->tagprefix, "list: '%s' (%c)\n", mailbox, separator);
        }
 
-       if (job && g_hash_table_lookup (data->folders, linfo->name) == NULL) {
+       if (job && !g_hash_table_contains (data->folders, response)) {
                if (is->priv->context->lsub)
-                       linfo->flags |= CAMEL_FOLDER_SUBSCRIBED;
-               g_hash_table_insert (data->folders, linfo->name, linfo);
+                       camel_imapx_list_response_add_attribute (
+                               response, CAMEL_IMAPX_LIST_ATTR_SUBSCRIBED);
+               g_hash_table_add (data->folders, g_object_ref (response));
        } else {
                g_warning ("got list response but no current listing job happening?\n");
-               imapx_free_list (linfo);
        }
 
+       g_object_unref (response);
+
        return TRUE;
 }
 
@@ -7976,48 +7983,6 @@ camel_imapx_server_expunge (CamelIMAPXServer *is,
        return success;
 }
 
-static guint
-imapx_name_hash (gconstpointer key)
-{
-       if (g_ascii_strcasecmp (key, "INBOX") == 0)
-               return g_str_hash ("INBOX");
-       else
-               return g_str_hash (key);
-}
-
-static gint
-imapx_name_equal (gconstpointer a,
-                  gconstpointer b)
-{
-       gconstpointer aname = a, bname = b;
-
-       if (g_ascii_strcasecmp (a, "INBOX") == 0)
-               aname = "INBOX";
-       if (g_ascii_strcasecmp (b, "INBOX") == 0)
-               bname = "INBOX";
-       return g_str_equal (aname, bname);
-}
-
-static void
-imapx_list_flatten (gpointer k,
-                    gpointer v,
-                    gpointer d)
-{
-       GPtrArray *folders = d;
-
-       g_ptr_array_add (folders, v);
-}
-
-static gint
-imapx_list_cmp (gconstpointer ap,
-                gconstpointer bp)
-{
-       struct _list_info *a = ((struct _list_info **) ap)[0];
-       struct _list_info *b = ((struct _list_info **) bp)[0];
-
-       return strcmp (a->name, b->name);
-}
-
 GPtrArray *
 camel_imapx_server_list (CamelIMAPXServer *is,
                          const gchar *top,
@@ -8036,7 +8001,11 @@ camel_imapx_server_list (CamelIMAPXServer *is,
        data = g_slice_new0 (ListData);
        data->flags = flags;
        data->ext = g_strdup (ext);
-       data->folders = g_hash_table_new (imapx_name_hash, imapx_name_equal);
+       data->folders = g_hash_table_new_full (
+               (GHashFunc) camel_imapx_list_response_hash,
+               (GEqualFunc) camel_imapx_list_response_equal,
+               (GDestroyNotify) g_object_unref,
+               (GDestroyNotify) NULL);
 
        if (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)
                data->pattern = g_strdup_printf ("%s*", encoded_name);
@@ -8057,11 +8026,18 @@ camel_imapx_server_list (CamelIMAPXServer *is,
                job->pri += 300;
 
        if (imapx_submit_job (is, job, error)) {
+               GList *list, *link;
+
+               /* Transfer LIST responses from a GHashTable
+                * to a sorted GPtrArray by way of a GList. */
                folders = g_ptr_array_new_with_free_func (
-                       (GDestroyNotify) imapx_free_list);
-               g_hash_table_foreach (
-                       data->folders, imapx_list_flatten, folders);
-               g_ptr_array_sort (folders, imapx_list_cmp);
+                       (GDestroyNotify) g_object_unref);
+               list = g_list_sort (
+                       g_hash_table_get_keys (data->folders),
+                       (GCompareFunc) camel_imapx_list_response_compare);
+               for (link = list; link != NULL; link = g_list_next (link))
+                       g_ptr_array_add (folders, g_object_ref (link->data));
+               g_list_free (list);
        }
 
        g_free (encoded_name);
diff --git a/camel/camel-imapx-store.c b/camel/camel-imapx-store.c
index 02b4094..55bd2cf 100644
--- a/camel/camel-imapx-store.c
+++ b/camel/camel-imapx-store.c
@@ -1054,19 +1054,30 @@ get_folder_info_offline (CamelStore *store,
 static void
 add_folder_to_summary (CamelIMAPXStore *imapx_store,
                        CamelIMAPXServer *server,
-                       struct _list_info *li,
+                       CamelIMAPXListResponse *response,
                        GHashTable *table,
                        gboolean update_for_lsub)
 {
        CamelIMAPXStoreInfo *si;
-       guint32 new_flags;
        CamelFolderInfo *fi;
+       const gchar *mailbox;
+       gchar separator;
+       CamelStoreInfoFlags flags;
+       CamelStoreInfoFlags new_flags;
+
+       mailbox = camel_imapx_list_response_get_mailbox (response);
+       separator = camel_imapx_list_response_get_separator (response);
+
+       /* XXX The flags type transforms from CamelStoreInfoFlags
+        *     to CamelFolderInfoFlags about half-way through this.
+        *     We should really eliminate the confusing redundancy. */
+       flags = camel_imapx_list_response_get_summary_flags (response);
 
        if (update_for_lsub) {
                gchar *full_name;
 
                full_name = camel_imapx_store_summary_path_to_full (
-                       imapx_store->summary, li->name, li->separator);
+                       imapx_store->summary, mailbox, separator);
                fi = g_hash_table_lookup (table, full_name);
                if (fi != NULL)
                        fi->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
@@ -1076,16 +1087,16 @@ add_folder_to_summary (CamelIMAPXStore *imapx_store,
        }
 
        si = camel_imapx_store_summary_add_from_full (
-               imapx_store->summary, li->name, li->separator);
+               imapx_store->summary, mailbox, separator);
        if (si == NULL)
                return;
 
        new_flags =
                (si->info.flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) |
-               (li->flags & ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED);
+               (flags & ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED);
 
        if (CAMEL_IMAPX_LACK_CAPABILITY (server->cinfo, NAMESPACE))
-               imapx_store->dir_sep = li->separator;
+               imapx_store->dir_sep = separator;
 
        if (si->info.flags != new_flags) {
                si->info.flags = new_flags;
@@ -1097,8 +1108,8 @@ add_folder_to_summary (CamelIMAPXStore *imapx_store,
        fi->full_name = g_strdup (camel_store_info_path (
                imapx_store->summary, si));
        if (g_ascii_strcasecmp (fi->full_name, "inbox") == 0) {
-               li->flags |= CAMEL_FOLDER_SYSTEM;
-               li->flags |= CAMEL_FOLDER_TYPE_INBOX;
+               flags |= CAMEL_FOLDER_SYSTEM;
+               flags |= CAMEL_FOLDER_TYPE_INBOX;
                fi->display_name = g_strdup (_("Inbox"));
        } else {
                fi->display_name = g_strdup (
@@ -1109,12 +1120,12 @@ add_folder_to_summary (CamelIMAPXStore *imapx_store,
        /* HACK: Some servers report noinferiors for all folders (uw-imapd).
         *       We just translate this into nochildren, and let the imap
         *       layer enforce it.  See create folder. */
-       if (li->flags & CAMEL_FOLDER_NOINFERIORS) {
-               li->flags &= ~CAMEL_FOLDER_NOINFERIORS;
-               li->flags |= CAMEL_FOLDER_NOCHILDREN;
+       if (flags & CAMEL_FOLDER_NOINFERIORS) {
+               flags &= ~CAMEL_FOLDER_NOINFERIORS;
+               flags |= CAMEL_FOLDER_NOCHILDREN;
        }
 
-       fi->flags |= li->flags;
+       fi->flags |= flags;
 
        fi->total = -1;
        fi->unread = -1;
@@ -1149,12 +1160,13 @@ fetch_folders_for_pattern (CamelIMAPXStore *imapx_store,
                update_for_lsub = FALSE;
 
        for (ii = 0; ii < folders->len; ii++) {
-               struct _list_info *li;
+               CamelIMAPXListResponse *response;
 
-               li = g_ptr_array_index (folders, ii);
+               response = g_ptr_array_index (folders, ii);
 
                add_folder_to_summary (
-                       imapx_store, server, li, table, update_for_lsub);
+                       imapx_store, server, response,
+                       table, update_for_lsub);
        }
 
        g_ptr_array_unref (folders);
diff --git a/camel/camel-imapx-utils.c b/camel/camel-imapx-utils.c
index 86dbd91..7ae683e 100644
--- a/camel/camel-imapx-utils.c
+++ b/camel/camel-imapx-utils.c
@@ -2491,110 +2491,6 @@ imapx_free_status (struct _status_info *sinfo)
        g_free (sinfo);
 }
 
-/* FIXME: use tokeniser? */
-/* FIXME: real flags */
-static struct {
-       const gchar *name;
-       guint32 flag;
-} list_flag_table[] = {
-       { "\\NOINFERIORS", CAMEL_FOLDER_NOINFERIORS },
-       { "\\NOSELECT", CAMEL_FOLDER_NOSELECT },
-       { "\\MARKED", 1<< 16},
-       { "\\UNMARKED", 1<< 17},
-       { "\\SUBSCRIBED", CAMEL_FOLDER_SUBSCRIBED },
-};
-
-struct _list_info *
-imapx_parse_list (CamelIMAPXStream *is,
-                  GCancellable *cancellable,
-                  GError **error)
-/* throws io, parse */
-{
-       gint tok, i;
-       guint len;
-       guchar *token, *p, c;
-       struct _list_info * linfo;
-
-       /* mailbox_list    ::= "(" #("\Marked" / "\Noinferiors" /
-        * "\Noselect" / "\Unmarked" / flag_extension) ")"
-        * SPACE (<"> QUOTED_CHAR <"> / nil) SPACE mailbox */
-
-       tok = camel_imapx_stream_token (is, &token, &len, cancellable, NULL);
-       if (tok != '(') {
-               g_set_error (error, CAMEL_IMAPX_ERROR, 1, "list: expecting '('");
-               return NULL;
-       }
-
-       linfo = g_malloc0 (sizeof (*linfo));
-
-       while ((tok = camel_imapx_stream_token (is, &token, &len, cancellable, NULL)) != ')') {
-               if (tok == IMAPX_TOK_STRING || tok == IMAPX_TOK_TOKEN) {
-                       p = token;
-                       while ((c=*p))
-                               *p++ = toupper(c);
-                       for (i = 0; i < G_N_ELEMENTS (list_flag_table); i++)
-                               if (!strcmp ((gchar *) token, list_flag_table[i].name))
-                                       linfo->flags |= list_flag_table[i].flag;
-               } else {
-                       g_set_error (error, CAMEL_IMAPX_ERROR, 1, "list: execting flag or ')'");
-                       goto fail;
-               }
-       }
-
-       if (!camel_imapx_stream_nstring (is, &token, cancellable, error))
-               goto fail;
-
-       linfo->separator = token != NULL ? *token : 0;
-
-       if (!camel_imapx_stream_astring (is, &token, cancellable, error))
-               goto fail;
-
-       linfo->name = camel_utf7_utf8 ((gchar *) token);
-
-       goto exit;
-
-fail:
-       imapx_free_list (linfo);
-       linfo = NULL;
-
-exit:
-       return linfo;
-}
-
-gchar *
-imapx_list_get_path (struct _list_info *li)
-{
-       gchar *path, *p;
-       gint c;
-       const gchar *f;
-
-       if (li->separator != 0 && li->separator != '/') {
-               p = path = alloca (strlen (li->name) * 3 + 1);
-               f = li->name;
-               while ((c = *f++ & 0xff)) {
-                       if (c == li->separator)
-                               *p++ = '/';
-                       else if (c == '/' || c == '%')
-                               p += sprintf (p, "%%%02X", c);
-                       else
-                               *p++ = c;
-               }
-               *p = 0;
-       } else
-               path = li->name;
-
-       return camel_utf7_utf8 (path);
-}
-
-void
-imapx_free_list (struct _list_info *linfo)
-{
-       if (linfo) {
-               g_free (linfo->name);
-               g_free (linfo);
-       }
-}
-
 gboolean
 camel_imapx_command_add_qresync_parameter (CamelIMAPXCommand *ic,
                                            CamelFolder *folder)
diff --git a/camel/camel-imapx-utils.h b/camel/camel-imapx-utils.h
index 8a02a44..cd974d9 100644
--- a/camel/camel-imapx-utils.h
+++ b/camel/camel-imapx-utils.h
@@ -330,23 +330,6 @@ struct _state_info *
 
 /* ********************************************************************** */
 
-/* should this just return a FolderInfo?
- * should this just return the name & flags & separator by reference? */
-struct _list_info {
-       guint32 flags : 24;
-       gchar separator;
-       gchar *name;
-};
-
-struct _list_info *
-               imapx_parse_list                (struct _CamelIMAPXStream *is,
-                                                GCancellable *cancellable,
-                                                GError **error);
-gchar *                imapx_list_get_path             (struct _list_info *linfo);
-void           imapx_free_list                 (struct _list_info *linfo);
-
-/* ********************************************************************** */
-
 gboolean       camel_imapx_command_add_qresync_parameter
                                                (struct _CamelIMAPXCommand *ic,
                                                 CamelFolder *folder);
diff --git a/camel/camel.h b/camel/camel.h
index c38229d..1684185 100644
--- a/camel/camel.h
+++ b/camel/camel.h
@@ -145,6 +145,7 @@
 #include <camel/camel-imapx-command.h>
 #include <camel/camel-imapx-job.h>
 #include <camel/camel-imapx-folder.h>
+#include <camel/camel-imapx-list-response.h>
 #include <camel/camel-imapx-search.h>
 #include <camel/camel-imapx-server.h>
 #include <camel/camel-imapx-store-summary.h>
diff --git a/docs/reference/camel/camel-docs.sgml b/docs/reference/camel/camel-docs.sgml
index a11b143..c7047db 100644
--- a/docs/reference/camel/camel-docs.sgml
+++ b/docs/reference/camel/camel-docs.sgml
@@ -204,6 +204,7 @@
       <xi:include href="xml/camel-imapx-command.xml"/>
       <xi:include href="xml/camel-imapx-folder.xml"/>
       <xi:include href="xml/camel-imapx-job.xml"/>
+      <xi:include href="xml/camel-imapx-list-response.xml"/>
       <xi:include href="xml/camel-imapx-search.xml"/>
       <xi:include href="xml/camel-imapx-server.xml"/>
       <xi:include href="xml/camel-imapx-settings.xml"/>
diff --git a/docs/reference/camel/camel-sections.txt b/docs/reference/camel/camel-sections.txt
index c812079..2304c14 100644
--- a/docs/reference/camel/camel-sections.txt
+++ b/docs/reference/camel/camel-sections.txt
@@ -816,6 +816,41 @@ uidset_state
 </SECTION>
 
 <SECTION>
+<FILE>camel-imapx-list-response</FILE>
+<TITLE>CamelIMAPXListResponse</TITLE>
+CamelIMAPXListResponse
+camel_imapx_list_response_new
+camel_imapx_list_response_hash
+camel_imapx_list_response_equal
+camel_imapx_list_response_compare
+camel_imapx_list_response_get_mailbox
+camel_imapx_list_response_get_separator
+CAMEL_IMAPX_LIST_ATTR_NOINFERIORS
+CAMEL_IMAPX_LIST_ATTR_NOSELECT
+CAMEL_IMAPX_LIST_ATTR_MARKED
+CAMEL_IMAPX_LIST_ATTR_UNMARKED
+CAMEL_IMAPX_LIST_ATTR_NONEXISTENT
+CAMEL_IMAPX_LIST_ATTR_SUBSCRIBED
+CAMEL_IMAPX_LIST_ATTR_REMOTE
+CAMEL_IMAPX_LIST_ATTR_HASCHILDREN
+CAMEL_IMAPX_LIST_ATTR_HASNOCHILDREN
+camel_imapx_list_response_add_attribute
+camel_imapx_list_response_has_attribute
+camel_imapx_list_response_get_summary_flags
+<SUBSECTION Standard>
+CAMEL_IMAPX_LIST_RESPONSE
+CAMEL_IS_IMAPX_LIST_RESPONSE
+CAMEL_TYPE_IMAPX_LIST_RESPONSE
+CAMEL_IMAPX_LIST_RESPONSE_CLASS
+CAMEL_IS_IMAPX_LIST_RESPONSE_CLASS
+CAMEL_IMAPX_LIST_RESPONSE_GET_CLASS
+CamelIMAPXListResponseClass
+camel_imapx_list_response_get_type
+<SUBSECTION Private>
+CamelIMAPXListResponsePrivate
+</SECTION>
+
+<SECTION>
 <FILE>camel-imapx-search</FILE>
 <TITLE>CamelIMAPXSearch</TITLE>
 CamelIMAPXSearch
diff --git a/docs/reference/camel/camel.types b/docs/reference/camel/camel.types
index 1c71e7a..424905e 100644
--- a/docs/reference/camel/camel.types
+++ b/docs/reference/camel/camel.types
@@ -17,6 +17,7 @@ camel_folder_summary_get_type
 camel_gpg_context_get_type
 camel_html_parser_get_type
 camel_imapx_folder_get_type
+camel_imapx_list_response_get_type
 camel_imapx_search_get_type
 camel_imapx_server_get_type
 camel_imapx_settings_get_type


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