From d91b5bb03431dc5477cacfd2b922a68a1ec623c5 Mon Sep 17 00:00:00 2001 From: Not Zed Date: Thu, 24 Oct 2002 14:01:53 +0000 Subject: ** For bug #31647 and bug #31456. 2002-10-24 Not Zed ** For bug #31647 and bug #31456. * camel-store-summary.c (store_info_string): for STORE_INFO_NAME, skip the leading /. * providers/imap/camel-imap-store.c (parse_list_response_as_folder_info): Remove jeff's last patch, and use the store summary to create the name and path of the folderinfo so it manages namespace issues. (get_folder_info_online): Just pass @top directly to build_folder_info always, since namespace is mapped to 1 tree level. (imap_build_folder_info): Remove jeff's last patch, dont strip leading /'s, they shouldn't exist. (imap_connect_online): Remove adding the INBOX here, we add it later. (get_subscribed_folders): Make sure INBOX is always in the list. some imap servers dont seem to let you subscribe to it(?), so always have it act as subscribed. * camel-store.c (camel_folder_info_build): back out the last 2 patches from Jeff (for #31456) to get the original behaviour. (camel_folder_info_build): When creating a fake parent, dont strip the namespace from the full_name. malloc keys in hash since we dont have them anymore. (free_name): Helper to free names. * providers/imap/camel-imap-store-summary.c (camel_imap_store_summary_namespace_new): Canonicalise the namespace (strip trailing dir_sep), and change the path to remove any /'s. (camel_imap_store_summary_namespace_find_path): (camel_imap_store_summary_namespace_find_full): new, find namespace by path/full name. (camel_imap_store_summary_full_from_path): Changed to a simple wrapper around path_to_full, after checking namespace. (camel_imap_store_summary_add_from_full): map the namespace if present. (camel_imap_store_summary_path_to_full): If namespace exists, unmap it. svn path=/trunk/; revision=18424 --- camel/ChangeLog | 43 +++++++++ camel/camel-store-summary.c | 2 +- camel/camel-store.c | 38 ++++++-- camel/providers/imap/camel-imap-store-summary.c | 114 +++++++++++++++++++++--- camel/providers/imap/camel-imap-store-summary.h | 4 +- camel/providers/imap/camel-imap-store.c | 100 ++++++++------------- camel/providers/imap/camel-imap-store.h | 1 + 7 files changed, 215 insertions(+), 87 deletions(-) (limited to 'camel') diff --git a/camel/ChangeLog b/camel/ChangeLog index 410266a4ef..5c7fe65570 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,46 @@ +2002-10-24 Not Zed + + ** For bug #31647 and bug #31456. + + * camel-store-summary.c (store_info_string): for STORE_INFO_NAME, + skip the leading /. + + * providers/imap/camel-imap-store.c + (parse_list_response_as_folder_info): Remove jeff's last patch, + and use the store summary to create the name and path of the + folderinfo so it manages namespace issues. + (get_folder_info_online): Just pass @top directly to + build_folder_info always, since namespace is mapped to 1 tree + level. + (imap_build_folder_info): Remove jeff's last patch, dont strip + leading /'s, they shouldn't exist. + (imap_connect_online): Remove adding the INBOX here, we add it + later. + (get_subscribed_folders): Make sure INBOX is always in the list. + some imap servers dont seem to let you subscribe to it(?), so + always have it act as subscribed. + + * camel-store.c (camel_folder_info_build): back out the last 2 + patches from Jeff (for #31456) to get the original behaviour. + (camel_folder_info_build): When creating a fake + parent, dont strip the namespace from the full_name. malloc keys + in hash since we dont have them anymore. + (free_name): Helper to free names. + + * providers/imap/camel-imap-store-summary.c + (camel_imap_store_summary_namespace_new): Canonicalise the + namespace (strip trailing dir_sep), and change the path to remove + any /'s. + (camel_imap_store_summary_namespace_find_path): + (camel_imap_store_summary_namespace_find_full): new, find + namespace by path/full name. + (camel_imap_store_summary_full_from_path): Changed to a simple + wrapper around path_to_full, after checking namespace. + (camel_imap_store_summary_add_from_full): map the namespace if + present. + (camel_imap_store_summary_path_to_full): If namespace exists, + unmap it. + 2002-10-18 Jeffrey Stedfast * camel-filter-driver.c (camel_filter_driver_filter_folder): diff --git a/camel/camel-store-summary.c b/camel/camel-store-summary.c index fc839dfed7..f33205dd50 100644 --- a/camel/camel-store-summary.c +++ b/camel/camel-store-summary.c @@ -870,7 +870,7 @@ store_info_string(CamelStoreSummary *s, const CamelStoreInfo *mi, int type) case CAMEL_STORE_INFO_NAME: p = strrchr(mi->path, '/'); if (p) - return p; + return p+1; else return mi->path; case CAMEL_STORE_INFO_URI: diff --git a/camel/camel-store.c b/camel/camel-store.c index 43528a8353..d76af40e60 100644 --- a/camel/camel-store.c +++ b/camel/camel-store.c @@ -843,6 +843,12 @@ folder_info_cmp (const void *ap, const void *bp) return strcmp (a->full_name, b->full_name); } +static void +free_name(void *key, void *data, void *user) +{ + g_free(key); +} + /** * camel_folder_info_build: * @folders: an array of CamelFolderInfo @@ -873,25 +879,36 @@ camel_folder_info_build (GPtrArray *folders, const char *namespace, if (!namespace) namespace = ""; nlen = strlen (namespace); - + qsort (folders->pdata, folders->len, sizeof (folders->pdata[0]), folder_info_cmp); /* Hash the folders. */ hash = g_hash_table_new (g_str_hash, g_str_equal); for (i = 0; i < folders->len; i++) { fi = folders->pdata[i]; - g_hash_table_insert (hash, fi->full_name, fi); + if (!strncmp (namespace, fi->full_name, nlen)) + name = fi->full_name + nlen; + else + name = fi->full_name; + if (*name == separator) + name++; + g_hash_table_insert (hash, g_strdup(name), fi); } /* Now find parents. */ for (i = 0; i < folders->len; i++) { fi = folders->pdata[i]; - name = fi->full_name; - + if (!strncmp (namespace, fi->full_name, nlen)) + name = fi->full_name + nlen; + else + name = fi->full_name; + if (*name == separator) + name++; + /* set the path if it isn't already set */ if (!fi->path) camel_folder_info_build_path (fi, separator); - + p = strrchr (name, separator); if (p) { pname = g_strndup (name, p - name); @@ -903,9 +920,8 @@ camel_folder_info_build (GPtrArray *folders, const char *namespace, create a fake folder node */ CamelURL *url; char *sep; - + pfi = g_new0 (CamelFolderInfo, 1); - pfi->full_name = pname; if (short_names) { pfi->name = strrchr (pname, separator); if (pfi->name) @@ -914,7 +930,8 @@ camel_folder_info_build (GPtrArray *folders, const char *namespace, pfi->name = g_strdup (pname); } else pfi->name = g_strdup (pname); - + + /* FIXME: url's with fragments should have the fragment truncated, not path */ url = camel_url_new (fi->url, NULL); sep = strrchr (url->path, separator); if (sep) @@ -922,11 +939,13 @@ camel_folder_info_build (GPtrArray *folders, const char *namespace, else d(g_warning ("huh, no \"%c\" in \"%s\"?", separator, fi->url)); + pfi->full_name = g_strdup(url->path+1); + /* since this is a "fake" folder node, it is not selectable */ camel_url_set_param (url, "noselect", "yes"); pfi->url = camel_url_to_string (url, 0); camel_url_free (url); - + g_hash_table_insert (hash, pname, pfi); g_ptr_array_add (folders, pfi); } @@ -936,6 +955,7 @@ camel_folder_info_build (GPtrArray *folders, const char *namespace, } else if (!top) top = fi; } + g_hash_table_foreach(hash, free_name, NULL); g_hash_table_destroy (hash); /* Link together the top-level folders */ diff --git a/camel/providers/imap/camel-imap-store-summary.c b/camel/providers/imap/camel-imap-store-summary.c index 4ba5bb9b68..9cdebba3e9 100644 --- a/camel/providers/imap/camel-imap-store-summary.c +++ b/camel/providers/imap/camel-imap-store-summary.c @@ -214,6 +214,7 @@ camel_imap_store_summary_path_to_full(CamelImapStoreSummary *s, const char *path int state=0; char *subpath, *last = NULL; CamelStoreInfo *si; + CamelImapStoreNamespace *ns; /* check to see if we have a subpath of path already defined */ subpath = alloca(strlen(path)+1); @@ -234,11 +235,16 @@ camel_imap_store_summary_path_to_full(CamelImapStoreSummary *s, const char *path return f; } + ns = camel_imap_store_summary_namespace_find_path(s, path); + f = full = alloca(strlen(path)*2+1); if (si) p = path + strlen(subpath); + else if (ns) + p = path + strlen(ns->path); else p = path; + while ( (c = camel_utf8_getc((const unsigned char **)&p)) ) { switch(state) { case 0: @@ -270,18 +276,31 @@ camel_imap_store_summary_path_to_full(CamelImapStoreSummary *s, const char *path g_free(f); camel_store_summary_info_free((CamelStoreSummary *)s, si); f = full; + } else if (ns) { + full = g_strdup_printf("%s%s", ns->full_name, f); + g_free(f); + f = full; } return f; } CamelImapStoreInfo * -camel_imap_store_summary_add_from_full(CamelImapStoreSummary *s, const char *full_name, char dir_sep) +camel_imap_store_summary_add_from_full(CamelImapStoreSummary *s, const char *full, char dir_sep) { CamelImapStoreInfo *info; - char *pathu8; + char *pathu8, *prefix; + int len; + char *full_name; + CamelImapStoreNamespace *ns; + + d(printf("adding full name '%s' '%c'\n", full, dir_sep)); - d(printf("adding full name '%s' '%c'\n", full_name, dir_sep)); + len = strlen(full); + full_name = alloca(len+1); + strcpy(full_name, full); + if (full_name[len-1] == dir_sep) + full_name[len-1] = 0; info = camel_imap_store_summary_full_name(s, full_name); if (info) { @@ -290,7 +309,24 @@ camel_imap_store_summary_add_from_full(CamelImapStoreSummary *s, const char *ful return info; } - pathu8 = camel_imap_store_summary_full_to_path(s, full_name, dir_sep); + ns = camel_imap_store_summary_namespace_find_full(s, full_name); + if (ns) { + d(printf("(found namespace for '%s' ns '%s') ", full_name, ns->path)); + len = strlen(ns->full_name); + if (len >= strlen(full_name)) { + pathu8 = g_strdup(ns->path); + } else { + if (full_name[len] == ns->sep) + len++; + prefix = camel_imap_store_summary_full_to_path(s, full_name+len, ns->sep); + pathu8 = g_strdup_printf("%s/%s", ns->path, prefix); + g_free(prefix); + } + d(printf(" (pathu8 = '%s')", pathu8)); + } else { + d(printf("(Cannot find namespace for '%s')\n", full_name)); + pathu8 = camel_imap_store_summary_full_to_path(s, full_name, dir_sep); + } info = (CamelImapStoreInfo *)camel_store_summary_add_from_path((CamelStoreSummary *)s, pathu8); if (info) { @@ -303,30 +339,44 @@ camel_imap_store_summary_add_from_full(CamelImapStoreSummary *s, const char *ful } /* should this be const? */ +/* TODO: deprecate/merge this function with path_to_full */ char * camel_imap_store_summary_full_from_path(CamelImapStoreSummary *s, const char *path) { CamelImapStoreInfo *si; + CamelImapStoreNamespace *ns; + char *name = NULL; - si = (CamelImapStoreInfo *)camel_store_summary_path((CamelStoreSummary *)s, path); + ns = camel_imap_store_summary_namespace_find_path(s, path); + if (ns) + name = camel_imap_store_summary_path_to_full(s, path, ns->sep); - d(printf("looking up path %s -> %s\n", path, si?si->full_name:"not found")); + d(printf("looking up path %s -> %s\n", path, name?name:"not found")); - if (si) - return g_strdup(si->full_name); - - return NULL; + return name; } /* TODO: this api needs some more work */ CamelImapStoreNamespace *camel_imap_store_summary_namespace_new(CamelImapStoreSummary *s, const char *full_name, char dir_sep) { CamelImapStoreNamespace *ns; + char *p; + int len; + GString *tmp; ns = g_malloc0(sizeof(*ns)); ns->full_name = g_strdup(full_name); + len = strlen(ns->full_name)-1; + if (len >= 0 && ns->full_name[len] == dir_sep) + ns->full_name[len] = 0; ns->sep = dir_sep; - ns->path = camel_imap_store_summary_full_to_path(s, full_name, dir_sep); + + p = ns->path = camel_imap_store_summary_full_to_path(s, ns->full_name, dir_sep); + while (*p) { + if (*p == '/') + *p = '.'; + p++; + } return ns; } @@ -335,11 +385,53 @@ void camel_imap_store_summary_namespace_set(CamelImapStoreSummary *s, CamelImapS { static void namespace_clear(CamelStoreSummary *s); + 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); } +CamelImapStoreNamespace * +camel_imap_store_summary_namespace_find_path(CamelImapStoreSummary *s, const char *path) +{ + int 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); + if (strncmp(ns->path, path, len) == 0 + && (path[len] == '/' || path[len] == 0)) + break; + ns = NULL; + } + + /* have a default? */ + return ns; +} + +CamelImapStoreNamespace * +camel_imap_store_summary_namespace_find_full(CamelImapStoreSummary *s, const char *full) +{ + int 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); + d(printf("find_full: comparing namespace '%s' to name '%s'\n", ns->full_name, full)); + if (strncmp(ns->full_name, full, len) == 0 + && (full[len] == ns->sep || full[len] == 0)) + break; + ns = NULL; + } + + /* have a default? */ + return ns; +} + static void namespace_free(CamelStoreSummary *s, CamelImapStoreNamespace *ns) { diff --git a/camel/providers/imap/camel-imap-store-summary.h b/camel/providers/imap/camel-imap-store-summary.h index 013283b5c1..0fa6be0df3 100644 --- a/camel/providers/imap/camel-imap-store-summary.h +++ b/camel/providers/imap/camel-imap-store-summary.h @@ -76,9 +76,11 @@ struct _CamelImapStoreSummaryClass { CamelType camel_imap_store_summary_get_type (void); CamelImapStoreSummary *camel_imap_store_summary_new (void); -/* TODO: this api needs some more work */ +/* TODO: this api needs some more work, needs to support lists */ CamelImapStoreNamespace *camel_imap_store_summary_namespace_new(CamelImapStoreSummary *s, const char *full_name, char dir_sep); void camel_imap_store_summary_namespace_set(CamelImapStoreSummary *s, CamelImapStoreNamespace *ns); +CamelImapStoreNamespace *camel_imap_store_summary_namespace_find_path(CamelImapStoreSummary *s, const char *path); +CamelImapStoreNamespace *camel_imap_store_summary_namespace_find_full(CamelImapStoreSummary *s, const char *full_name); /* converts to/from utf8 canonical nasmes */ char *camel_imap_store_summary_full_to_path(CamelImapStoreSummary *s, const char *full_name, char dir_sep); diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c index 1da03ffdef..ac8d3e93ab 100644 --- a/camel/providers/imap/camel-imap-store.c +++ b/camel/providers/imap/camel-imap-store.c @@ -816,31 +816,26 @@ imap_build_folder_info(CamelImapStore *imap_store, const char *folder_name) CamelURL *url; const char *name; CamelFolderInfo *fi; - + fi = g_malloc0(sizeof(*fi)); - + fi->full_name = g_strdup(folder_name); fi->unread_message_count = 0; - + url = camel_url_new (imap_store->base_url, NULL); g_free (url->path); url->path = g_strdup_printf ("/%s", folder_name); fi->url = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); camel_url_free(url); - - /* strip extranious leading /'s */ - while (*folder_name == '/') - folder_name++; - fi->path = g_strdup_printf("/%s", folder_name); name = strrchr (fi->path, '/'); if (name) name++; else name = fi->path; - + fi->name = g_strdup (name); - + return fi; } @@ -1271,33 +1266,29 @@ imap_connect_online (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) { - char *tmp; + gchar *tmp; 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); if (CAMEL_STORE (store)->flags & CAMEL_STORE_SUBSCRIPTIONS) { GPtrArray *folders; char *pattern; - + /* this pre-fills the summary, and checks that lsub is useful */ - folders = g_ptr_array_new (); - pattern = g_strdup_printf ("%s*", store->namespace); - get_folders_online (store, pattern, folders, TRUE, ex); - g_free (pattern); - - /* if we have a namespace, then our LSUB won't include INBOX so LSUB for the INBOX too */ - if (*store->namespace && !camel_exception_is_set (ex)) - get_folders_online (store, "INBOX", folders, TRUE, ex); - + folders = g_ptr_array_new(); + pattern = g_strdup_printf("%s*", store->namespace); + get_folders_online(store, pattern, folders, TRUE, ex); + g_free(pattern); + for (i=0;ilen;i++) { CamelFolderInfo *fi = folders->pdata[i]; - + if (fi->flags & (CAMEL_IMAP_FOLDER_MARKED | CAMEL_IMAP_FOLDER_UNMARKED)) store->capabilities |= IMAP_CAPABILITY_useful_lsub; camel_folder_info_free(fi); @@ -1312,7 +1303,7 @@ imap_connect_online (CamelService *service, CamelException *ex) done: /* save any changes we had */ camel_store_summary_save((CamelStoreSummary *)store->summary); - + CAMEL_SERVICE_UNLOCK (store, connect_lock); if (camel_exception_is_set (ex)) @@ -1926,19 +1917,17 @@ parse_list_response_as_folder_info (CamelImapStore *imap_store, const char *response) { CamelFolderInfo *fi; - int flags; - char sep, *dir, *name = NULL, *path, *p; + int flags, i; + char sep, *dir, *name = NULL, *path; CamelURL *url; CamelImapStoreInfo *si; guint32 newflags; - + if (!imap_parse_list_response (imap_store, response, &flags, &sep, &dir)) return NULL; - + /* FIXME: should use imap_build_folder_info, note the differences with param setting tho */ - path = camel_utf7_utf8(dir); - - /* hack: pokes in value from any list response */ + si = camel_imap_store_summary_add_from_full(imap_store->summary, dir, sep?sep:'/'); newflags = (si->info.flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) | (flags & ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED); if (si->info.flags != newflags) { @@ -1946,45 +1935,24 @@ parse_list_response_as_folder_info (CamelImapStore *imap_store, camel_store_summary_touch((CamelStoreSummary *)imap_store->summary); } - if (sep && sep != '/') { - for (p = path; *p; p++) { - if (*p == sep) - *p = '/'; - } - } - - if ((name = strrchr (path, '/'))) { - name++; - if (!*name) { - g_free(dir); - g_free(path); - return NULL; - } - } else - name = path; - fi = g_new0 (CamelFolderInfo, 1); fi->flags = flags; - fi->name = g_strdup (name); - fi->full_name = path; - - while (*path == '/') - path++; - fi->path = g_strdup_printf ("/%s", path); + fi->name = g_strdup(camel_store_info_name(imap_store->summary, si)); + fi->path = g_strdup_printf("/%s", camel_store_info_path(imap_store->summary, si)); + fi->full_name = g_strdup(fi->path+1); url = camel_url_new (imap_store->base_url, NULL); - g_free (url->path); - url->path = g_strdup_printf ("/%s", fi->full_name); - + camel_url_set_path(url, fi->path); + if (flags & CAMEL_FOLDER_NOSELECT || fi->name[0] == 0) camel_url_set_param (url, "noselect", "yes"); fi->url = camel_url_to_string (url, 0); camel_url_free (url); - + /* FIXME: redundant */ if (flags & CAMEL_IMAP_FOLDER_UNMARKED) fi->unread_message_count = -1; - + return fi; } @@ -1998,16 +1966,19 @@ get_subscribed_folders (CamelImapStore *imap_store, const char *top, CamelExcept CamelImapResponse *response; CamelFolderInfo *fi; char *result; + int haveinbox = FALSE; folders = g_ptr_array_new (); names = g_ptr_array_new (); for (i=0;(si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i));i++) { - if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) + if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) { g_ptr_array_add(names, (char *)camel_imap_store_info_full_name(imap_store->summary, si)); + haveinbox = haveinbox || strcasecmp(camel_imap_store_info_full_name(imap_store->summary, si), "INBOX") == 0; + } camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si); } - - if (names->len == 0) + + if (!haveinbox) g_ptr_array_add (names, "INBOX"); for (i = 0; i < names->len; i++) { @@ -2399,14 +2370,13 @@ get_folder_info_online (CamelStore *store, const char *top, guint32 flags, Camel if (folders == NULL) return NULL; - /* note the weird top stuff, it is so a namespace based list "" is properly tree-ised */ - tree = camel_folder_info_build(folders, top[0] == 0 && imap_store->namespace?"":top, '/', TRUE); + tree = camel_folder_info_build(folders, top, '/', TRUE); g_ptr_array_free(folders, TRUE); if (!(flags & CAMEL_STORE_FOLDER_INFO_FAST)) get_folder_counts(imap_store, tree, ex); - dumpfi(tree); + d(dumpfi(tree)); camel_store_summary_save((CamelStoreSummary *)imap_store->summary); return tree; diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h index 38df1880a0..d461b51440 100644 --- a/camel/providers/imap/camel-imap-store.h +++ b/camel/providers/imap/camel-imap-store.h @@ -114,6 +114,7 @@ struct _CamelImapStore { /* Information about the server */ CamelImapServerLevel server_level; guint32 capabilities, parameters; + /* NB: namespace should be handled by summary->namespace */ char *namespace, dir_sep, *base_url, *storage_path; GHashTable *authtypes; -- cgit v1.2.3