IMAPX: (utils) made capabilities flags extensible
authorChristian Hilberg <chilberg@src.gnome.org>
Fri, 22 Jun 2012 15:16:50 +0000 (17:16 +0200)
committerMatthew Barnes <mbarnes@redhat.com>
Tue, 26 Jun 2012 15:20:28 +0000 (11:20 -0400)
* added a hash table as an IMAP capabilities flags
  lookup mechanism for the capabilities parser util
  function
* added a capabilities strings registration function
  (to add new capabilities flags, which will then be
  known to the parser and assigned a new flag bit.
  This is returned by the registration function so
  the caller can test whether the bit is set in the
  CamelIMAPXServer capabilities bitstring)

camel/camel-imapx-utils.c
camel/camel-imapx-utils.h

index 856600a..4a7f2cc 100644 (file)
@@ -354,7 +354,7 @@ imapx_update_store_summary (CamelFolder *folder)
 struct {
        const gchar *name;
        guint32 flag;
-} capa_table[] = {
+} capa_table[] = { /* used to create capa_htable only */
        { "IMAP4", IMAPX_CAPABILITY_IMAP4 },
        { "IMAP4REV1", IMAPX_CAPABILITY_IMAP4REV1 },
        { "STATUS",  IMAPX_CAPABILITY_STATUS } ,
@@ -369,14 +369,42 @@ struct {
        { "LIST-STATUS", IMAPX_CAPABILITY_LIST_STATUS },
 };
 
+static GMutex capa_htable_lock;         /* capabilities lookup table lock */
+static GHashTable *capa_htable = NULL;  /* capabilities lookup table (extensible) */
+
+static void
+create_initial_capabilities_table (void)
+{
+       gint i = 0;
+
+       /* call within g_init_once() only,
+        * or require table lock
+        */
+
+       /* TODO add imapx_utils_uninit()
+        *      to free hash table
+        */
+       capa_htable = g_hash_table_new_full (g_str_hash,
+                                            g_str_equal,
+                                            g_free,
+                                            NULL);
+
+       for (i = 0; i < G_N_ELEMENTS (capa_table); i++) {
+               g_hash_table_insert (capa_htable,
+                                    g_strdup (capa_table[i].name),
+                                    GUINT_TO_POINTER (capa_table[i].flag));
+       }
+}
+
 struct _capability_info *
 imapx_parse_capability (CamelIMAPXStream *stream,
                         GCancellable *cancellable,
                         GError **error)
 {
-       gint tok, i;
+       gint tok;
        guint len;
        guchar *token, *p, c;
+       gpointer pp = NULL;
        gboolean free_token = FALSE;
        struct _capability_info * cinfo;
        GError *local_error = NULL;
@@ -408,9 +436,14 @@ imapx_parse_capability (CamelIMAPXStream *stream,
                                }
                        case IMAPX_TOK_INT:
                                d(stream->tagprefix, " cap: '%s'\n", token);
-                               for (i = 0; i < G_N_ELEMENTS (capa_table); i++)
-                                       if (!strcmp ((gchar *) token, capa_table[i].name))
-                                               cinfo->capa |= capa_table[i].flag;
+                               g_mutex_lock (&capa_htable_lock);
+                               pp = g_hash_table_lookup (capa_htable,
+                                                         (gchar*) token);
+                               g_mutex_unlock (&capa_htable_lock);
+                               if (pp != NULL) {
+                                       guint32 capa_id = GPOINTER_TO_UINT (pp);
+                                       cinfo->capa |= capa_id;
+                               }
                                if (free_token) {
                                        g_free (token);
                                        token = NULL;
@@ -438,6 +471,53 @@ void imapx_free_capability (struct _capability_info *cinfo)
        g_free (cinfo);
 }
 
+guint32
+imapx_register_capability (const gchar *capability)
+{
+       guint32 capa_id = 0;
+       guint64 check_id = 0;
+       GList *keys = NULL;
+       GList *tmp_keys = NULL;
+
+       g_assert (capability != NULL);
+
+       g_mutex_lock (&capa_htable_lock);
+
+       /* we rely on IMAP being the first flag, non-zero value
+        * (1 << 0), so we can use GPOINTER_TO_UINT (NULL) as
+        * invalid value
+        */
+       capa_id = GPOINTER_TO_UINT (g_hash_table_lookup (capa_htable,
+                                                        capability));
+       if (capa_id > 0)
+               goto exit;
+
+       /* not yet there, find biggest flag so far */
+       keys = g_hash_table_get_keys (capa_htable);
+       tmp_keys = keys;
+       while (tmp_keys != NULL) {
+               guint32 tmp_id = GPOINTER_TO_UINT (tmp_keys->data);
+               if (capa_id < tmp_id)
+                       capa_id = tmp_id;
+               tmp_keys = g_list_next (tmp_keys);
+       }
+
+       /* shift-left biggest-so-far, sanity-check */
+       check_id = (capa_id << 1);
+       g_assert (check_id <= (guint64) G_MAXUINT32);
+       capa_id = (guint32) check_id;
+
+       /* insert */
+       g_hash_table_insert (capa_htable,
+                            g_strdup (capability),
+                            GUINT_TO_POINTER (capa_id));
+
+ exit:
+       g_mutex_unlock (&capa_htable_lock);
+
+       return capa_id;
+}
+
 struct _CamelIMAPXNamespaceList *
 imapx_parse_namespace_list (CamelIMAPXStream *stream,
                             GCancellable *cancellable,
@@ -1993,6 +2073,7 @@ imapx_utils_init (void)
                        imapx_specials[i] = v;
                }
 
+               create_initial_capabilities_table ();
                camel_imapx_set_debug_flags ();
 
                g_once_init_leave (&imapx_utils_initialized, 1);
index d8bd6aa..b777065 100644 (file)
@@ -135,6 +135,7 @@ struct _capability_info {
 
 struct _capability_info *imapx_parse_capability (struct _CamelIMAPXStream *stream, GCancellable *cancellable, GError **error);
 void imapx_free_capability (struct _capability_info *);
+guint32 imapx_register_capability (const gchar *capability);
 
 gboolean imapx_parse_param_list (struct _CamelIMAPXStream *is, struct _camel_header_param **plist, GCancellable *cancellable, GError **error) /* IO,PARSE */;
 struct _CamelContentDisposition *imapx_parse_ext_optional (struct _CamelIMAPXStream *is, GCancellable *cancellable, GError **error) /* IO,PARSE */;