Bug #413422 - IMAP Subscribing/Viewing of Shared Folders does not work
authorMilan Crha <mcrha@redhat.com>
Fri, 16 Oct 2009 11:50:58 +0000 (13:50 +0200)
committerMilan Crha <mcrha@redhat.com>
Fri, 16 Oct 2009 11:50:58 +0000 (13:50 +0200)
camel/providers/imap/camel-imap-folder.c
camel/providers/imap/camel-imap-store-summary.c
camel/providers/imap/camel-imap-store-summary.h
camel/providers/imap/camel-imap-store.c
camel/providers/imap/camel-imap-store.h
camel/providers/imap/camel-imap-utils.c

index 4f79f3a..0b1abb0 100644 (file)
@@ -4021,7 +4021,9 @@ imap_get_quota_info (CamelFolder *folder)
                goto done;
 
        if (imap_store->capabilities & IMAP_CAPABILITY_QUOTA) {
-               gchar *folder_name = camel_imap_store_summary_path_to_full (imap_store->summary, camel_folder_get_full_name (folder), imap_store->dir_sep);
+               const gchar *full_name = camel_folder_get_full_name (folder);
+               CamelImapStoreNamespace *ns = camel_imap_store_summary_namespace_find_full (imap_store->summary, full_name);
+               gchar *folder_name = camel_imap_store_summary_path_to_full (imap_store->summary, full_name, ns ? ns->sep : '/');
 
                response = camel_imap_command (imap_store, NULL, NULL, "GETQUOTAROOT \"%s\"", folder_name);
 
index cdd3bf0..7737200 100644 (file)
@@ -45,8 +45,6 @@
 
 #define _PRIVATE(o) (((CamelImapStoreSummary *)(o))->priv)
 
-static void namespace_clear(CamelStoreSummary *s);
-
 static gint summary_header_load(CamelStoreSummary *, FILE *);
 static gint summary_header_save(CamelStoreSummary *, FILE *);
 
@@ -363,8 +361,8 @@ camel_imap_store_summary_full_from_path(CamelImapStoreSummary *s, const gchar *p
        return name;
 }
 
-/* TODO: this api needs some more work */
-CamelImapStoreNamespace *camel_imap_store_summary_namespace_new(CamelImapStoreSummary *s, const gchar *full_name, gchar dir_sep)
+static CamelImapStoreNamespace *
+namespace_new (CamelImapStoreSummary *s, const gchar *full_name, gchar dir_sep)
 {
        CamelImapStoreNamespace *ns;
        gchar *p, *o, c;
@@ -390,12 +388,96 @@ CamelImapStoreNamespace *camel_imap_store_summary_namespace_new(CamelImapStoreSu
        return ns;
 }
 
-void camel_imap_store_summary_namespace_set(CamelImapStoreSummary *s, CamelImapStoreNamespace *ns)
+static CamelImapStoreNamespace *
+namespace_find (CamelImapStoreNamespace *ns, const gchar *full_name, gchar dir_sep)
 {
-       d(printf("Setting namesapce to '%s' '%c' -> '%s'\n", ns->full_name, ns->sep, ns->path));
-       namespace_clear((CamelStoreSummary *)s);
-       s->namespace = ns;
-       camel_store_summary_touch((CamelStoreSummary *)s);
+       if (!ns || !full_name)
+               return NULL;
+
+       while (ns) {
+               gint len = strlen (ns->full_name);
+
+               if ((g_ascii_strcasecmp (ns->full_name, full_name) == 0 ||
+                   (g_ascii_strncasecmp (ns->full_name, full_name, len) == 0
+                   && len + 1 == strlen (full_name) && full_name [len] == ns->sep))&& (!dir_sep || ns->sep == dir_sep)) {
+                       break;
+               }
+               ns = ns->next;
+       }
+
+       return ns;
+}
+
+void
+camel_imap_store_summary_namespace_set_main (CamelImapStoreSummary *s, const gchar *full_name, gchar dir_sep)
+{
+       CamelImapStoreNamespace *ns;
+
+       g_return_if_fail (s != NULL);
+       g_return_if_fail (full_name != NULL);
+
+       ns = namespace_find (s->namespace, full_name, dir_sep);
+
+       if (ns) {
+               /* is in the list of known namespaces already */
+               if (ns != s->namespace) {
+                       CamelImapStoreNamespace *prev = s->namespace;
+
+                       while (prev && prev->next != ns)
+                               prev = prev->next;
+
+                       g_return_if_fail (prev != NULL);
+
+                       /* move it to the first */
+                       prev->next = ns->next;
+                       ns->next = s->namespace;
+                       s->namespace = ns;
+
+                       /* fix a dir separator, for the inherit/guess option */
+                       if (dir_sep != 0)
+                               s->namespace->sep = dir_sep;
+               } else
+                       return;
+       } else {
+               if (!dir_sep && s->namespace)
+                       dir_sep = s->namespace->sep; /* inherit */
+               else if (!dir_sep)
+                       dir_sep = '/'; /* guess */
+
+               ns = namespace_new (s, full_name, dir_sep);
+               if (ns) {
+                       ns->next = s->namespace;
+                       s->namespace = ns;
+               }
+       }
+
+       camel_store_summary_touch ((CamelStoreSummary *)s);
+}
+
+void
+camel_imap_store_summary_namespace_add_secondary (CamelImapStoreSummary *s, const gchar *full_name, gchar dir_sep)
+{
+       CamelImapStoreNamespace **tail;
+
+       g_return_if_fail (s != NULL);
+       g_return_if_fail (full_name != NULL);
+
+       if (namespace_find (s->namespace, full_name, dir_sep))
+               return;
+
+       for (tail = &s->namespace; *tail; tail = &((*tail)->next)) {
+               /* do nothing, just keep moving to the last */
+       }
+
+       *tail = namespace_new (s, full_name, dir_sep);
+}
+
+CamelImapStoreNamespace *
+camel_imap_store_summary_get_main_namespace (CamelImapStoreSummary *s)
+{
+       g_return_val_if_fail (s != NULL, NULL);
+
+       return s->namespace;
 }
 
 CamelImapStoreNamespace *
@@ -404,7 +486,6 @@ camel_imap_store_summary_namespace_find_path(CamelImapStoreSummary *s, const gch
        gint len;
        CamelImapStoreNamespace *ns;
 
-       /* NB: this currently only compares against 1 namespace, in future compare against others */
        ns = s->namespace;
        while (ns) {
                len = strlen(ns->path);
@@ -412,10 +493,10 @@ camel_imap_store_summary_namespace_find_path(CamelImapStoreSummary *s, const gch
                    || (strncmp(ns->path, path, len) == 0
                        && (path[len] == '/' || path[len] == 0)))
                        break;
-               ns = NULL;
+               ns = ns->next;
        }
 
-       /* have a default? */
+       /* NULL indicates not found */
        return ns;
 }
 
@@ -425,7 +506,6 @@ camel_imap_store_summary_namespace_find_full(CamelImapStoreSummary *s, const gch
        gint len;
        CamelImapStoreNamespace *ns;
 
-       /* NB: this currently only compares against 1 namespace, in future compare against others */
        ns = s->namespace;
        while (ns) {
                len = strlen(ns->full_name);
@@ -434,15 +514,15 @@ camel_imap_store_summary_namespace_find_full(CamelImapStoreSummary *s, const gch
                    || (strncmp(ns->full_name, full, len) == 0
                        && (full[len] == ns->sep || full[len] == 0)))
                        break;
-               ns = NULL;
+               ns = ns->next;
        }
 
-       /* have a default? */
+       /* NULL indicates not found */
        return ns;
 }
 
 static void
-namespace_free(CamelStoreSummary *s, CamelImapStoreNamespace *ns)
+namespace_free (CamelImapStoreSummary *is, CamelImapStoreNamespace *ns)
 {
        g_free(ns->path);
        g_free(ns->full_name);
@@ -450,43 +530,59 @@ namespace_free(CamelStoreSummary *s, CamelImapStoreNamespace *ns)
 }
 
 static void
-namespace_clear(CamelStoreSummary *s)
+namespace_clear (CamelImapStoreSummary *is)
 {
-       CamelImapStoreSummary *is = (CamelImapStoreSummary *)s;
+       while (is->namespace) {
+               CamelImapStoreNamespace *next = is->namespace->next;
 
-       if (is->namespace)
-               namespace_free(s, is->namespace);
-       is->namespace = NULL;
+               namespace_free (is, is->namespace);
+               is->namespace = next;
+       }
 }
 
-static CamelImapStoreNamespace *
-namespace_load(CamelStoreSummary *s, FILE *in)
+static gboolean
+namespaces_load (CamelImapStoreSummary *s, FILE *in, guint count)
 {
-       CamelImapStoreNamespace *ns;
+       CamelImapStoreNamespace *ns, **tail;
        guint32 sep = '/';
 
-       ns = g_malloc0(sizeof(*ns));
-       if (camel_file_util_decode_string(in, &ns->path) == -1
-           || camel_file_util_decode_string(in, &ns->full_name) == -1
-           || camel_file_util_decode_uint32(in, &sep) == -1) {
-               namespace_free(s, ns);
-               ns = NULL;
-       } else {
-               ns->sep = sep;
+       namespace_clear (s);
+
+       tail = &s->namespace;
+
+       while (count > 0) {
+               ns = g_malloc0 (sizeof(*ns));
+               if (camel_file_util_decode_string (in, &ns->path) == -1
+                   || camel_file_util_decode_string (in, &ns->full_name) == -1
+                   || camel_file_util_decode_uint32 (in, &sep) == -1) {
+                       namespace_free (s, ns);
+                       return FALSE;
+               } else {
+                       ns->sep = sep;
+
+                       *tail = ns;
+                       tail = &ns->next;
+               }
+
+               count --;
        }
 
-       return ns;
+       return count == 0;
 }
 
-static gint
-namespace_save(CamelStoreSummary *s, FILE *in, CamelImapStoreNamespace *ns)
+static gboolean
+namespaces_save (CamelImapStoreSummary *s, FILE *in, CamelImapStoreNamespace *ns)
 {
-       if (camel_file_util_encode_string(in, ns->path) == -1
-           || camel_file_util_encode_string(in, ns->full_name) == -1
-           || camel_file_util_encode_uint32(in, (guint32)ns->sep) == -1)
-               return -1;
+       while (ns) {
+               if (camel_file_util_encode_string(in, ns->path) == -1
+                   || camel_file_util_encode_string(in, ns->full_name) == -1
+                   || camel_file_util_encode_uint32(in, (guint32)ns->sep) == -1)
+                       return FALSE;
 
-       return 0;
+               ns = ns->next;
+       }
+
+       return TRUE;
 }
 
 static gint
@@ -495,7 +591,7 @@ summary_header_load(CamelStoreSummary *s, FILE *in)
        CamelImapStoreSummary *is = (CamelImapStoreSummary *)s;
        gint32 version, capabilities, count;
 
-       namespace_clear(s);
+       namespace_clear (is);
 
        if (camel_imap_store_summary_parent->summary_header_load((CamelStoreSummary *)s, in) == -1
            || camel_file_util_decode_fixed_int32(in, &version) == -1)
@@ -508,15 +604,13 @@ summary_header_load(CamelStoreSummary *s, FILE *in)
                return -1;
        }
 
-       /* note file format can be expanded to contain more namespaces, but only 1 at the moment */
        if (camel_file_util_decode_fixed_int32(in, &capabilities) == -1
-           || camel_file_util_decode_fixed_int32(in, &count) == -1
-           || count > 1)
+           || camel_file_util_decode_fixed_int32(in, &count) == -1)
                return -1;
 
        is->capabilities = capabilities;
-       if (count == 1) {
-               if ((is->namespace = namespace_load(s, in)) == NULL)
+       if (count >= 1) {
+               if (!namespaces_load (is, in, count))
                        return -1;
        }
 
@@ -527,9 +621,12 @@ static gint
 summary_header_save(CamelStoreSummary *s, FILE *out)
 {
        CamelImapStoreSummary *is = (CamelImapStoreSummary *)s;
-       guint32 count;
+       guint32 count = 0;
+       CamelImapStoreNamespace *ns;
 
-       count = is->namespace?1:0;
+       for (ns = is->namespace; ns; ns = ns->next) {
+               count++;
+       }
 
        /* always write as latest version */
        if (camel_imap_store_summary_parent->summary_header_save((CamelStoreSummary *)s, out) == -1
@@ -538,7 +635,7 @@ summary_header_save(CamelStoreSummary *s, FILE *out)
            || camel_file_util_encode_fixed_int32(out, count) == -1)
                return -1;
 
-       if (is->namespace && namespace_save(s, out, is->namespace) == -1)
+       if (!namespaces_save (is, out, is->namespace))
                return -1;
 
        return 0;
index 1987200..fe5123a 100644 (file)
@@ -52,6 +52,8 @@ struct _CamelImapStoreNamespace {
        gchar *path;            /* display path */
        gchar *full_name;       /* real name */
        gchar sep;              /* directory separator */
+
+       struct _CamelImapStoreNamespace *next;
 };
 
 struct _CamelImapStoreSummary {
@@ -62,7 +64,7 @@ struct _CamelImapStoreSummary {
        /* header info */
        guint32 version;        /* version of base part of file */
        guint32 capabilities;
-       CamelImapStoreNamespace *namespace; /* eventually to be a list */
+       CamelImapStoreNamespace *namespace; /* list of namespaces, the first is always main namespace */
 };
 
 struct _CamelImapStoreSummaryClass {
@@ -72,9 +74,9 @@ struct _CamelImapStoreSummaryClass {
 CamelType                       camel_imap_store_summary_get_type      (void);
 CamelImapStoreSummary      *camel_imap_store_summary_new       (void);
 
-/* TODO: this api needs some more work, needs to support lists */
-CamelImapStoreNamespace *camel_imap_store_summary_namespace_new(CamelImapStoreSummary *s, const gchar *full_name, gchar dir_sep);
-void camel_imap_store_summary_namespace_set(CamelImapStoreSummary *s, CamelImapStoreNamespace *ns);
+void camel_imap_store_summary_namespace_set_main (CamelImapStoreSummary *s, const gchar *full_name, gchar dir_sep);
+void camel_imap_store_summary_namespace_add_secondary (CamelImapStoreSummary *s, const gchar *full_name, gchar dir_sep);
+CamelImapStoreNamespace *camel_imap_store_summary_get_main_namespace (CamelImapStoreSummary *s);
 CamelImapStoreNamespace *camel_imap_store_summary_namespace_find_path(CamelImapStoreSummary *s, const gchar *path);
 CamelImapStoreNamespace *camel_imap_store_summary_namespace_find_full(CamelImapStoreSummary *s, const gchar *full_name);
 
index a5eb640..5523a78 100644 (file)
@@ -185,8 +185,8 @@ camel_imap_store_finalize (CamelObject *object)
        if (imap_store->storage_path)
                g_free (imap_store->storage_path);
 
-       g_free (imap_store->namespace);
-       imap_store->namespace = NULL;
+       g_free (imap_store->users_namespace);
+       imap_store->users_namespace = NULL;
 
        g_free (imap_store->custom_headers);
 }
@@ -199,6 +199,7 @@ camel_imap_store_init (gpointer object, gpointer klass)
        imap_store->istream = NULL;
        imap_store->ostream = NULL;
 
+       /* TODO: support dir_sep per namespace */
        imap_store->dir_sep = '\0';
        imap_store->current_folder = NULL;
        imap_store->connected = FALSE;
@@ -258,8 +259,8 @@ construct (CamelService *service, CamelSession *session,
                imap_store->parameters |= IMAP_PARAM_SUBSCRIPTIONS;
        if (camel_url_get_param (url, "override_namespace") && camel_url_get_param (url, "namespace")) {
                imap_store->parameters |= IMAP_PARAM_OVERRIDE_NAMESPACE;
-               g_free(imap_store->namespace);
-               imap_store->namespace = g_strdup (camel_url_get_param (url, "namespace"));
+               g_free(imap_store->users_namespace);
+               imap_store->users_namespace = g_strdup (camel_url_get_param (url, "namespace"));
        }
        if (camel_url_get_param (url, "check_all"))
                imap_store->parameters |= IMAP_PARAM_CHECK_ALL;
@@ -297,11 +298,8 @@ construct (CamelService *service, CamelSession *session,
 
                if (is->namespace) {
                        /* if namespace has changed, clear folder list */
-                       if (imap_store->namespace && strcmp(imap_store->namespace, is->namespace->full_name) != 0) {
+                       if (imap_store->users_namespace && strcmp(imap_store->users_namespace, is->namespace->full_name) != 0) {
                                camel_store_summary_clear((CamelStoreSummary *)is);
-                       } else {
-                               imap_store->namespace = g_strdup(is->namespace->full_name);
-                               imap_store->dir_sep = is->namespace->sep;
                        }
                }
 
@@ -327,9 +325,9 @@ imap_setv (CamelObject *object, CamelException *ex, CamelArgV *args)
 
                switch (tag) {
                case CAMEL_IMAP_STORE_NAMESPACE:
-                       if (strcmp (store->namespace, args->argv[i].ca_str) != 0) {
-                               g_free (store->namespace);
-                               store->namespace = g_strdup (args->argv[i].ca_str);
+                       if (strcmp (store->users_namespace, args->argv[i].ca_str) != 0) {
+                               g_free (store->users_namespace);
+                               store->users_namespace = g_strdup (args->argv[i].ca_str);
                                /* the current imap code will need to do a reconnect for this to take effect */
                                /*reconnect = TRUE;*/
                        }
@@ -401,7 +399,7 @@ imap_getv (CamelObject *object, CamelException *ex, CamelArgGetV *args)
 
                switch (tag) {
                case CAMEL_IMAP_STORE_NAMESPACE:
-                       *args->argv[i].ca_str = store->namespace;
+                       *args->argv[i].ca_str = store->users_namespace;
                        break;
                case CAMEL_IMAP_STORE_OVERRIDE_NAMESPACE:
                        *args->argv[i].ca_int = store->parameters & IMAP_PARAM_OVERRIDE_NAMESPACE ? TRUE : FALSE;
@@ -1400,10 +1398,8 @@ imap_connect (CamelService *service, CamelException *ex)
 {
        CamelImapStore *store = CAMEL_IMAP_STORE (service);
        CamelImapResponse *response;
-       /*struct _namespaces *namespaces;*/
        gchar *result, *name;
        gsize len;
-       CamelImapStoreNamespace *ns;
 
        if (((CamelOfflineStore *) store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL)
                return TRUE;
@@ -1417,8 +1413,9 @@ imap_connect (CamelService *service, CamelException *ex)
        }
 
        /* Get namespace and hierarchy separator */
-       if ((store->capabilities & IMAP_CAPABILITY_NAMESPACE) &&
-           !(store->parameters & IMAP_PARAM_OVERRIDE_NAMESPACE)) {
+       if (store->capabilities & IMAP_CAPABILITY_NAMESPACE) {
+               struct _namespaces *namespaces;
+
                response = camel_imap_command (store, NULL, ex, "NAMESPACE");
                if (!response)
                        goto done;
@@ -1427,41 +1424,85 @@ imap_connect (CamelService *service, CamelException *ex)
                if (!result)
                        goto done;
 
-#if 0
-               /* new code... */
                namespaces = imap_parse_namespace_response (result);
+
+               if (!(store->parameters & IMAP_PARAM_OVERRIDE_NAMESPACE)) {
+                       g_free (store->users_namespace);
+                       store->users_namespace = NULL;
+               }
+
+               if (namespaces && !store->users_namespace) {
+                       struct _namespace *np = NULL;
+
+                       if (namespaces->personal)
+                               np = namespaces->personal;
+                       else if (namespaces->other)
+                               np = namespaces->other;
+                       else if (namespaces->shared)
+                               np = namespaces->shared;
+
+                       if (np) {
+                               store->users_namespace = g_strdup (np->prefix);
+                       }
+               }
+
+               if (namespaces) {
+                       #define add_all(_ns)                                                                    \
+                               if (_ns) {                                                                      \
+                                       struct _namespace *ns;                                                  \
+                                                                                                               \
+                                       for (ns = _ns; ns; ns = ns->next) {                                     \
+                                               if (ns->prefix)                                                 \
+                                                       camel_imap_store_summary_namespace_add_secondary        \
+                                                               (store->summary, ns->prefix, ns->delim);        \
+                                       }                                                                       \
+                               }
+
+                       add_all (namespaces->personal);
+                       add_all (namespaces->other);
+                       add_all (namespaces->shared);
+
+                       #undef add_all
+               }
+
                imap_namespaces_destroy (namespaces);
-               /* end new code */
-#endif
 
-               name = camel_strstrcase (result, "NAMESPACE ((");
-               if (name) {
-                       gchar *sep;
-
-                       name += 12;
-                       store->namespace = imap_parse_string ((const gchar **) &name, &len);
-                       if (name && *name++ == ' ') {
-                               sep = imap_parse_string ((const gchar **) &name, &len);
-                               if (sep) {
-                                       store->dir_sep = *sep;
-                                       g_free (sep);
+               if (!store->users_namespace) {
+                       /* fallback for a broken result */
+                       name = camel_strstrcase (result, "NAMESPACE ((");
+                       if (name) {
+                               gchar *sep;
+
+                               name += 12;
+                               store->users_namespace = imap_parse_string ((const gchar **) &name, &len);
+                               if (name && *name++ == ' ') {
+                                       sep = imap_parse_string ((const gchar **) &name, &len);
+                                       if (sep) {
+                                               store->dir_sep = *sep;
+                                               g_free (sep);
+                                       }
                                }
                        }
                }
                g_free (result);
        }
 
-       if (!store->namespace)
-               store->namespace = g_strdup ("");
+       if (!store->users_namespace)
+               store->users_namespace = g_strdup ("");
 
        if (!store->dir_sep) {
+               const gchar *use_namespace = store->summary->namespace ? store->summary->namespace->full_name : NULL;
+
+               if (!use_namespace)
+                       use_namespace = store->users_namespace;
+
                if (store->server_level >= IMAP_LEVEL_IMAP4REV1) {
                        /* This idiom means "tell me the hierarchy separator
                         * for the given path, even if that path doesn't exist.
                         */
                        response = camel_imap_command (store, NULL, ex,
                                                       "LIST %G \"\"",
-                                                      store->namespace);
+                                                      use_namespace);
                } else {
                        /* Plain IMAP4 doesn't have that idiom, so we fall back
                         * to "tell me about this folder", which will fail if
@@ -1469,7 +1510,7 @@ imap_connect (CamelService *service, CamelException *ex)
                         */
                        response = camel_imap_command (store, NULL, ex,
                                                       "LIST \"\" %G",
-                                                      store->namespace);
+                                                      use_namespace);
                }
                if (!response)
                        goto done;
@@ -1485,30 +1526,19 @@ imap_connect (CamelService *service, CamelException *ex)
 
        }
 
-       /* canonicalize the namespace to end with dir_sep */
-       len = strlen (store->namespace);
-       if (len && store->namespace[len - 1] != store->dir_sep) {
-               gchar *tmp;
+       /* canonicalize the namespace to not end with dir_sep */
+       len = strlen (store->users_namespace);
+       if (len && store->users_namespace[len - 1] == store->dir_sep)
+               store->users_namespace[len - 1] = 0;
 
-               tmp = g_strdup_printf ("%s%c", store->namespace, store->dir_sep);
-               g_free (store->namespace);
-               store->namespace = tmp;
-       }
-
-       ns = camel_imap_store_summary_namespace_new(store->summary, store->namespace, store->dir_sep);
-       camel_imap_store_summary_namespace_set(store->summary, ns);
+       camel_imap_store_summary_namespace_set_main (store->summary, store->users_namespace, store->dir_sep);
 
        if ((store->parameters & IMAP_PARAM_SUBSCRIPTIONS)
            && camel_store_summary_count((CamelStoreSummary *)store->summary) == 0) {
                CamelStoreInfo *si;
-               gchar *pattern;
 
-               get_folders_sync(store, store->namespace, ex);
-               if (camel_exception_is_set(ex))
-                       goto done;
-               pattern = imap_concat(store, store->namespace, "*");
-               get_folders_sync(store, pattern, ex);
-               g_free (pattern);
+               /* look in all namespaces */
+               get_folders_sync (store, NULL, ex);
                if (camel_exception_is_set(ex))
                        goto done;
 
@@ -1578,9 +1608,9 @@ imap_disconnect (CamelService *service, gboolean clean, CamelException *ex)
                store->authtypes = NULL;
        }
 
-       if (store->namespace && !(store->parameters & IMAP_PARAM_OVERRIDE_NAMESPACE)) {
-               g_free (store->namespace);
-               store->namespace = NULL;
+       if (store->users_namespace && !(store->parameters & IMAP_PARAM_OVERRIDE_NAMESPACE)) {
+               g_free (store->users_namespace);
+               store->users_namespace = NULL;
        }
 
        return TRUE;
@@ -2424,9 +2454,14 @@ parse_list_response_as_folder_info (CamelImapStore *imap_store,
        return fi;
 }
 
-static gint imap_match_pattern(gchar dir_sep, const gchar *pattern, const gchar *name)
+static gint imap_match_pattern (CamelImapStoreNamespace *ns, const gchar *pattern, const gchar *name)
 {
-       gchar p, n;
+       gchar p, n, dir_sep;
+
+       if (!ns)
+               return TRUE;
+
+       dir_sep = ns->sep;
 
        p = *pattern++;
        n = *name++;
@@ -2481,7 +2516,7 @@ get_folders_free(gpointer k, gpointer v, gpointer d)
 }
 
 static void
-get_folders_sync(CamelImapStore *imap_store, const gchar *pattern, CamelException *ex)
+get_folders_sync (CamelImapStore *imap_store, const gchar *ppattern, CamelException *ex)
 {
        CamelImapResponse *response;
        CamelFolderInfo *fi, *hfi;
@@ -2489,40 +2524,64 @@ get_folders_sync(CamelImapStore *imap_store, const gchar *pattern, CamelExceptio
        gint i, count, j;
        GHashTable *present;
        CamelStoreInfo *si;
+       const gchar *pattern = ppattern;
+       CamelImapStoreNamespace *ns;
 
        /* We do a LIST followed by LSUB, and merge the results.  LSUB may not be a strict
           subset of LIST for some servers, so we can't use either or separately */
        present = g_hash_table_new(folder_hash, folder_eq);
 
-       for (j=0;j<2;j++) {
-               response = camel_imap_command (imap_store, NULL, ex,
-                                              "%s \"\" %G", j==1 ? "LSUB" : "LIST",
-                                              pattern);
-               if (!response)
-                       goto fail;
+       if (!pattern)
+               pattern = "";
+
+       for (ns = imap_store->summary->namespace; ns; ns = ns->next) {
+               gchar *tmp = NULL;
+
+               if (!ppattern) {
+                       if (!ns->full_name || !*ns->full_name)
+                               tmp = g_strdup ("*");
+                       else
+                               tmp = g_strdup_printf ("%s%c*", ns->full_name, ns->sep);
+                       pattern = tmp;
+               }
+
+               for (j = 0; j < 2; j++) {
+                       response = camel_imap_command (imap_store, NULL, ex,
+                                                       "%s \"\" %G", j==1 ? "LSUB" : "LIST",
+                                                       pattern);
+                       if (!response)
+                               goto fail;
 
-               for (i = 0; i < response->untagged->len; i++) {
-                       list = response->untagged->pdata[i];
-                       fi = parse_list_response_as_folder_info (imap_store, list);
-                       if (fi && fi->full_name && *fi->full_name) {
-                               hfi = g_hash_table_lookup(present, fi->full_name);
-                               if (hfi == NULL) {
-                                       if (j == 1) {
-                                               fi->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
-                                               if ((fi->flags & (CAMEL_IMAP_FOLDER_MARKED | CAMEL_IMAP_FOLDER_UNMARKED)))
-                                                       imap_store->capabilities |= IMAP_CAPABILITY_useful_lsub;
+                       for (i = 0; i < response->untagged->len; i++) {
+                               list = response->untagged->pdata[i];
+                               fi = parse_list_response_as_folder_info (imap_store, list);
+                               if (fi && *fi->full_name) {
+                                       hfi = g_hash_table_lookup(present, fi->full_name);
+                                       if (hfi == NULL) {
+                                               if (j == 1) {
+                                                       fi->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+                                                       if ((fi->flags & (CAMEL_IMAP_FOLDER_MARKED | CAMEL_IMAP_FOLDER_UNMARKED)))
+                                                               imap_store->capabilities |= IMAP_CAPABILITY_useful_lsub;
+                                               }
+                                               g_hash_table_insert(present, fi->full_name, fi);
+                                       } else {
+                                               if (j == 1)
+                                                       hfi->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+                                               camel_folder_info_free(fi);
                                        }
-                                       g_hash_table_insert(present, fi->full_name, fi);
-                               } else {
-                                       if (j == 1)
-                                               hfi->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
-                                       camel_folder_info_free(fi);
+                               } else if (fi) {
+                                       camel_folder_info_free (fi);
                                }
-                       } else if (fi) {
-                               camel_folder_info_free (fi);
                        }
+
+                       camel_imap_response_free (imap_store, response);
                }
-               camel_imap_response_free (imap_store, response);
+
+               g_free (tmp);
+
+               /* look for matching only, if ppattern was non-NULL */
+               if (ppattern)
+                       break;
        }
 
        /* Sync summary to match */
@@ -2543,7 +2602,7 @@ get_folders_sync(CamelImapStore *imap_store, const gchar *pattern, CamelExceptio
                        continue;
                }
 
-               if (imap_match_pattern (imap_store->dir_sep, pattern, full_name)) {
+               if (!ppattern || imap_match_pattern (camel_imap_store_summary_namespace_find_full (imap_store->summary, full_name), pattern, full_name)) {
                        if ((fi = g_hash_table_lookup(present, camel_store_info_path(imap_store->summary, si))) != NULL) {
                                if (((fi->flags ^ si->flags) & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)) {
                                        si->flags = (si->flags & ~CAMEL_FOLDER_SUBSCRIBED) | (fi->flags & CAMEL_FOLDER_SUBSCRIBED);
@@ -2564,8 +2623,9 @@ get_folders_sync(CamelImapStore *imap_store, const gchar *pattern, CamelExceptio
 
                                        g_free (dup_folder_name);
                                        camel_exception_clear (&eex);
-                               } else
+                               } else {
                                        camel_store_summary_remove ((CamelStoreSummary *)imap_store->summary, si);
+                               }
 
                                count--;
                                i--;
@@ -2595,10 +2655,10 @@ dumpfi(CamelFolderInfo *fi)
        }
 
        while (fi) {
-               printf("%-40s %-30s %*s\n", fi->path, fi->full_name, depth*2+strlen(fi->url), fi->url);
+               printf("%-25s %-25s %*s\n", fi->name, fi->full_name, (gint)(depth*2+strlen(fi->uri)), fi->uri);
                if (fi->child)
                        dumpfi(fi->child);
-               fi = fi->sibling;
+               fi = fi->next;
        }
 }
 #endif
@@ -2637,28 +2697,14 @@ static void
 refresh_refresh(CamelSession *session, CamelSessionThreadMsg *msg)
 {
        struct _refresh_msg *m = (struct _refresh_msg *)msg;
-       CamelImapStore *store = (CamelImapStore *)m->store;
 
        CAMEL_SERVICE_REC_LOCK(m->store, connect_lock);
 
        if (!camel_imap_store_connected((CamelImapStore *)m->store, &m->ex))
                goto done;
 
-       if (store->namespace && store->namespace[0]) {
-               gchar *pattern;
-
-               get_folders_sync(store, "INBOX", &m->ex);
-               if (camel_exception_is_set(&m->ex))
-                       goto done;
-               get_folders_sync(store, store->namespace, &m->ex);
-               if (camel_exception_is_set(&m->ex))
-                       goto done;
-               pattern = imap_concat(store, store->namespace, "*");
-               get_folders_sync(store, pattern, &m->ex);
-               g_free(pattern);
-       } else {
-               get_folders_sync((CamelImapStore *)m->store, "*", &m->ex);
-       }
+       /* look in all namespaces */
+       get_folders_sync((CamelImapStore *)m->store, NULL, &m->ex);
        camel_store_summary_save((CamelStoreSummary *)((CamelImapStore *)m->store)->summary);
 done:
        CAMEL_SERVICE_REC_UNLOCK(m->store, connect_lock);
@@ -2725,6 +2771,7 @@ get_folder_info (CamelStore *store, const gchar *top, guint32 flags, CamelExcept
        } else {
                gchar *pattern;
                gint i;
+               CamelImapStoreNamespace *ns;
 
                CAMEL_SERVICE_REC_LOCK(store, connect_lock);
 
@@ -2732,23 +2779,10 @@ get_folder_info (CamelStore *store, const gchar *top, guint32 flags, CamelExcept
                        goto fail;
 
                if (top[0] == 0) {
-                       if (imap_store->namespace && imap_store->namespace[0]) {
-                               get_folders_sync(imap_store, "INBOX", ex);
-                               if (camel_exception_is_set(ex))
-                                       goto fail;
-
-                               i = strlen(imap_store->namespace)-1;
-                               pattern = g_alloca(i+5);
-                               strcpy(pattern, imap_store->namespace);
-                               while (i>0 && pattern[i] == imap_store->dir_sep)
-                                       pattern[i--] = 0;
-                               i++;
-                       } else {
-                               pattern = g_alloca(2);
-                               pattern[0] = '*';
-                               pattern[1] = 0;
-                               i=0;
-                       }
+                       pattern = g_alloca (2);
+                       pattern[0] = '*';
+                       pattern[1] = 0;
+                       i = 0;
                } else {
                        gchar *name;
 
@@ -2762,11 +2796,12 @@ get_folder_info (CamelStore *store, const gchar *top, guint32 flags, CamelExcept
                        g_free(name);
                }
 
+               ns = camel_imap_store_summary_get_main_namespace (imap_store->summary);
                get_folders_sync(imap_store, pattern, ex);
                if (camel_exception_is_set(ex))
                        goto fail;
-               if (pattern[0] != '*' && imap_store->dir_sep) {
-                       pattern[i] = imap_store->dir_sep;
+               if (pattern[0] != '*' && ns) {
+                       pattern[i] = ns->sep;
                        pattern[i+1] = (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)?'*':'%';
                        pattern[i+2] = 0;
                        get_folders_sync(imap_store, pattern, ex);
@@ -2793,6 +2828,7 @@ get_folder_info_offline (CamelStore *store, const gchar *top,
        GPtrArray *folders;
        gchar *pattern, *name;
        gint i;
+       CamelImapStoreNamespace *main_ns, *ns;
 
        if (camel_debug("imap:folder_info"))
                printf("get folder info offline\n");
@@ -2808,17 +2844,14 @@ get_folder_info_offline (CamelStore *store, const gchar *top,
 
        /* get starting point */
        if (top[0] == 0) {
-               if (imap_store->namespace && imap_store->namespace[0]) {
-                       name = g_strdup(imap_store->summary->namespace->full_name);
-                       top = imap_store->summary->namespace->path;
-               } else
-                       name = g_strdup("");
+               name = g_strdup("");
        } else {
                name = camel_imap_store_summary_full_from_path(imap_store->summary, top);
                if (name == NULL)
                        name = camel_imap_store_summary_path_to_full(imap_store->summary, top, imap_store->dir_sep);
        }
 
+       main_ns = camel_imap_store_summary_get_main_namespace (imap_store->summary);
        pattern = imap_concat(imap_store, name, "*");
 
        /* folder_info_build will insert parent nodes as necessary and mark
@@ -2839,12 +2872,16 @@ get_folder_info_offline (CamelStore *store, const gchar *top,
                        continue;
                }
 
-               if ((!strcmp(name, full_name)
-                    || imap_match_pattern(imap_store->dir_sep, pattern, full_name)
+               ns = camel_imap_store_summary_namespace_find_full (imap_store->summary, full_name);
+
+               if ((g_str_equal (name, full_name)
+                    || imap_match_pattern (ns, pattern, full_name)
                     || (include_inbox && !g_ascii_strcasecmp (full_name, "INBOX")))
-                   && ((imap_store->parameters & IMAP_PARAM_SUBSCRIPTIONS) == 0
-                       || (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) == 0
-                       || (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED))) {
+                   && ((ns == main_ns && 
+                       ((imap_store->parameters & IMAP_PARAM_SUBSCRIPTIONS) == 0
+                          || (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) == 0))
+                       || (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)
+                       || (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0)) {
 
                        fi = imap_build_folder_info(imap_store, camel_store_info_path((CamelStoreSummary *)imap_store->summary, si));
                        fi->unread = si->unread;
index 4206bfe..03d8da8 100644 (file)
@@ -138,8 +138,7 @@ struct _CamelImapStore {
        /* Information about the server */
        CamelImapServerLevel server_level;
        guint32 capabilities, parameters;
-       /* NB: namespace should be handled by summary->namespace */
-       gchar *namespace, dir_sep, *base_url, *storage_path;
+       gchar *users_namespace, dir_sep, *base_url, *storage_path;
        GHashTable *authtypes;
 
        time_t refresh_stamp;
index 5ab4750..e6f6a3c 100644 (file)
@@ -42,6 +42,7 @@
 
 #include "camel-imap-store.h"
 #include "camel-imap-summary.h"
+#include "camel-imap-store-summary.h"
 #include "camel-imap-utils.h"
 
 #define d(x)
@@ -1347,12 +1348,13 @@ gchar *
 imap_concat (CamelImapStore *imap_store, const gchar *prefix, const gchar *suffix)
 {
        gsize len;
+       CamelImapStoreNamespace *ns = camel_imap_store_summary_get_main_namespace (imap_store->summary);
 
        len = strlen (prefix);
-       if (len == 0 || prefix[len - 1] == imap_store->dir_sep)
+       if (len == 0 || !ns || prefix[len - 1] == ns->sep)
                return g_strdup_printf ("%s%s", prefix, suffix);
        else
-               return g_strdup_printf ("%s%c%s", prefix, imap_store->dir_sep, suffix);
+               return g_strdup_printf ("%s%c%s", prefix, ns->sep, suffix);
 }
 
 gchar *