diff options
author | Dan Winship <danw@src.gnome.org> | 2000-10-30 11:24:15 +0800 |
---|---|---|
committer | Dan Winship <danw@src.gnome.org> | 2000-10-30 11:24:15 +0800 |
commit | d4656431e9de8e6e3ab526d71323f0d0543c587e (patch) | |
tree | 59b0ff39e227e6079d696c3dd29c8e1e0344dec2 | |
parent | 9e6c10a18be76719fbba41c36c61abc9c1542710 (diff) | |
download | gsoc2013-evolution-d4656431e9de8e6e3ab526d71323f0d0543c587e.tar gsoc2013-evolution-d4656431e9de8e6e3ab526d71323f0d0543c587e.tar.gz gsoc2013-evolution-d4656431e9de8e6e3ab526d71323f0d0543c587e.tar.bz2 gsoc2013-evolution-d4656431e9de8e6e3ab526d71323f0d0543c587e.tar.lz gsoc2013-evolution-d4656431e9de8e6e3ab526d71323f0d0543c587e.tar.xz gsoc2013-evolution-d4656431e9de8e6e3ab526d71323f0d0543c587e.tar.zst gsoc2013-evolution-d4656431e9de8e6e3ab526d71323f0d0543c587e.zip |
Improved IMAP namespace handling: leave the namespace in the
folder names rather than constantly prepending it and stripping it
off. Also some subscription fixes.
* camel-store.c (camel_folder_info_build): Fix for the case where
@top isn't in @folders.
* providers/imap/camel-imap-folder.c (camel_imap_folder_new): Add
a "short_name" argument rather than figuring it out ourselves.
(imap_get_full_name): Implementation of CamelFolder::get_full_name
that strips off namespace so the user doesn't have to see it.
(imap_append_message, imap_copy_message_to, imap_move_message_to):
Use folder->full_name rather than calling
camel_imap_store_get_folder_path.
* providers/imap/camel-imap-utils.c (imap_parse_list_response):
Update this: make @flags a bitmask and @sep a char rather than a
string. Make all of the out arguments optional. Handle literals in
the server response.
* providers/imap/camel-imap-store.c (imap_connect): Do a better
job of getting the correct dir_sep for the namespace we're using.
Construct a base_url here that will be used by get_folder_info.
(camel_imap_store_folder_path): Removed
(imap_folder_exists): Add an argument to return the short name of
the folder (parsed out of the LIST response). Update for
imap_parse_list_response change.
(get_folder): Update for the various other changes.
(get_folder_info): Update for the various other changes. Be more
consistent about the returned layout: put everything underneath
the "namespace" directory, including INBOX, even if it doesn't
belong there. Don't destroy the list of subscribed folders until
we've actually gotten the new list.
(folder_subscribed, subscribe_folder, unsubscribe_folder): Use
folder_name directly rather than camel_imap_store_folder_Path.
* providers/imap/camel-imap-command.c (camel_imap_command): Update
for folder name changes.
svn path=/trunk/; revision=6256
-rw-r--r-- | camel/ChangeLog | 41 | ||||
-rw-r--r-- | camel/camel-store.c | 5 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-command.c | 8 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-folder.c | 45 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-folder.h | 1 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-store.c | 368 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-store.h | 4 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-utils.c | 138 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-utils.h | 7 |
9 files changed, 343 insertions, 274 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog index 368e27b466..e6ab9c5f0e 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,5 +1,46 @@ 2000-10-29 Dan Winship <danw@helixcode.com> + Improved IMAP namespace handling: leave the namespace in the + folder names rather than constantly prepending it and stripping it + off. Also some subscription fixes. + + * camel-store.c (camel_folder_info_build): Fix for the case where + @top isn't in @folders. + + * providers/imap/camel-imap-folder.c (camel_imap_folder_new): Add + a "short_name" argument rather than figuring it out ourselves. + (imap_get_full_name): Implementation of CamelFolder::get_full_name + that strips off namespace so the user doesn't have to see it. + (imap_append_message, imap_copy_message_to, imap_move_message_to): + Use folder->full_name rather than calling + camel_imap_store_get_folder_path. + + * providers/imap/camel-imap-utils.c (imap_parse_list_response): + Update this: make @flags a bitmask and @sep a char rather than a + string. Make all of the out arguments optional. Handle literals in + the server response. + + * providers/imap/camel-imap-store.c (imap_connect): Do a better + job of getting the correct dir_sep for the namespace we're using. + Construct a base_url here that will be used by get_folder_info. + (camel_imap_store_folder_path): Removed + (imap_folder_exists): Add an argument to return the short name of + the folder (parsed out of the LIST response). Update for + imap_parse_list_response change. + (get_folder): Update for the various other changes. + (get_folder_info): Update for the various other changes. Be more + consistent about the returned layout: put everything underneath + the "namespace" directory, including INBOX, even if it doesn't + belong there. Don't destroy the list of subscribed folders until + we've actually gotten the new list. + (folder_subscribed, subscribe_folder, unsubscribe_folder): Use + folder_name directly rather than camel_imap_store_folder_Path. + + * providers/imap/camel-imap-command.c (camel_imap_command): Update + for folder name changes. + +2000-10-29 Dan Winship <danw@helixcode.com> + * camel.h: Remove md5-utils.h include since it's not part of Camel any more. diff --git a/camel/camel-store.c b/camel/camel-store.c index ac6337acac..c9236676b2 100644 --- a/camel/camel-store.c +++ b/camel/camel-store.c @@ -525,10 +525,15 @@ camel_folder_info_build (GPtrArray *folders, CamelFolderInfo *top, /* Hash the folders. */ hash = g_hash_table_new (g_str_hash, g_str_equal); + pfi = top; for (i = 0; i < folders->len; i++) { fi = folders->pdata[i]; + if (fi == top) + pfi = NULL; g_hash_table_insert (hash, fi->full_name, fi); } + if (pfi) + g_hash_table_insert (hash, pfi->full_name, pfi); /* Now find parents. */ for (i = 0; i < folders->len; i++) { diff --git a/camel/providers/imap/camel-imap-command.c b/camel/providers/imap/camel-imap-command.c index 9f79db5020..e9808d5a1f 100644 --- a/camel/providers/imap/camel-imap-command.c +++ b/camel/providers/imap/camel-imap-command.c @@ -69,16 +69,12 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder, /* Check for current folder */ if (folder && (!fmt || folder != store->current_folder)) { - char *folder_path; CamelImapResponse *response; - folder_path = camel_imap_store_folder_path (store, - folder->full_name); store->current_folder = NULL; response = camel_imap_command (store, NULL, ex, - "SELECT \"%s\"", folder_path); - g_free (folder_path); - + "SELECT \"%s\"", + folder->full_name); if (!response) return NULL; store->current_folder = folder; diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index 46d80c6e29..c25006e5a6 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -65,6 +65,7 @@ static CamelFolderClass *parent_class = NULL; static void imap_finalize (CamelObject *object); static void imap_refresh_info (CamelFolder *folder, CamelException *ex); static void imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex); +static const char *imap_get_full_name (CamelFolder *folder); static void imap_expunge (CamelFolder *folder, CamelException *ex); /* message counts */ @@ -113,6 +114,7 @@ camel_imap_folder_class_init (CamelImapFolderClass *camel_imap_folder_class) camel_folder_class->refresh_info = imap_refresh_info; camel_folder_class->sync = imap_sync; camel_folder_class->expunge = imap_expunge; + camel_folder_class->get_full_name = imap_get_full_name; camel_folder_class->get_uids = imap_get_uids; camel_folder_class->free_uids = camel_folder_free_nop; @@ -169,22 +171,17 @@ camel_imap_folder_get_type (void) CamelFolder * camel_imap_folder_new (CamelStore *parent, const char *folder_name, - const char *summary_file, CamelException *ex) + const char *short_name, const char *summary_file, + CamelException *ex) { CamelImapStore *imap_store = CAMEL_IMAP_STORE (parent); CamelFolder *folder = CAMEL_FOLDER (camel_object_new (camel_imap_folder_get_type ())); CamelImapFolder *imap_folder = (CamelImapFolder *)folder; CamelImapResponse *response; - const char *dir_sep, *short_name, *resp; + const char *resp; guint32 validity = 0; int i; - dir_sep = CAMEL_IMAP_STORE (parent)->dir_sep; - short_name = strrchr (folder_name, *dir_sep); - if (short_name) - short_name++; - else - short_name = folder_name; camel_folder_construct (folder, parent, folder_name, short_name); response = camel_imap_command (imap_store, folder, ex, NULL); @@ -393,6 +390,21 @@ imap_expunge (CamelFolder *folder, CamelException *ex) imap_sync (folder, TRUE, ex); } +static const char * +imap_get_full_name (CamelFolder *folder) +{ + CamelURL *url = ((CamelService *)folder->parent_store)->url; + int len; + + if (!url->path || !*url->path) + return folder->full_name; + len = strlen (url->path + 1); + if (!strncmp (url->path + 1, folder->full_name, len) && + strlen (folder->full_name) > len + 1) + return folder->full_name + len + 1; + return folder->full_name; +} + static gint imap_get_message_count (CamelFolder *folder) { @@ -428,9 +440,7 @@ imap_append_message (CamelFolder *folder, CamelMimeMessage *message, CamelMimeFilter *crlf_filter; CamelStreamFilter *streamfilter; GByteArray *ba; - char *folder_path, *flagstr, *result; - - folder_path = camel_imap_store_folder_path (store, folder->full_name); + char *flagstr, *result; /* create flag string param */ if (info && info->flags) @@ -455,9 +465,8 @@ imap_append_message (CamelFolder *folder, CamelMimeMessage *message, camel_object_unref (CAMEL_OBJECT (memstream)); response = camel_imap_command (store, NULL, ex, "APPEND %s%s%s {%d}", - folder_path, flagstr ? " " : "", + folder->full_name, flagstr ? " " : "", flagstr ? flagstr : "", ba->len); - g_free (folder_path); g_free (flagstr); if (!response) { @@ -486,13 +495,10 @@ imap_copy_message_to (CamelFolder *source, const char *uid, { CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store); CamelImapResponse *response; - char *folder_path; - folder_path = camel_imap_store_folder_path (store, destination->full_name); response = camel_imap_command (store, source, ex, "UID COPY %s \"%s\"", - uid, folder_path); + uid, destination->full_name); camel_imap_response_free (response); - g_free (folder_path); /* FIXME: This should go away once folder_changed is being * emitted by camel_imap_folder_changed on appends again. @@ -509,13 +515,10 @@ imap_move_message_to (CamelFolder *source, const char *uid, { CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store); CamelImapResponse *response; - char *folder_path; - folder_path = camel_imap_store_folder_path (store, destination->full_name); response = camel_imap_command (store, source, ex, "UID COPY %s \"%s\"", - uid, folder_path); + uid, destination->full_name); camel_imap_response_free (response); - g_free (folder_path); if (camel_exception_is_set (ex)) return; diff --git a/camel/providers/imap/camel-imap-folder.h b/camel/providers/imap/camel-imap-folder.h index 724ce7ab3e..109cc76506 100644 --- a/camel/providers/imap/camel-imap-folder.h +++ b/camel/providers/imap/camel-imap-folder.h @@ -60,6 +60,7 @@ typedef struct { /* public methods */ CamelFolder *camel_imap_folder_new (CamelStore *parent, const char *folder_name, + const char *short_name, const char *summary_file, CamelException *ex); diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c index 43357a4326..bea7a03b18 100644 --- a/camel/providers/imap/camel-imap-store.c +++ b/camel/providers/imap/camel-imap-store.c @@ -128,8 +128,8 @@ camel_imap_store_init (gpointer object, gpointer klass) CAMEL_SERVICE_URL_ALLOW_AUTH); remote_store->default_port = 143; - - imap_store->dir_sep = NULL; + + imap_store->dir_sep = '\0'; imap_store->current_folder = NULL; store->flags = CAMEL_STORE_SUBSCRIPTIONS; @@ -212,16 +212,15 @@ imap_connect (CamelService *service, CamelException *ex) { CamelImapStore *store = CAMEL_IMAP_STORE (service); CamelSession *session = camel_service_get_session (CAMEL_SERVICE (store)); - gchar *result, *buf, *errbuf = NULL; + gchar *result, *buf, *errbuf = NULL, *namespace; CamelImapResponse *response; gboolean authenticated = FALSE; - + int len; + if (CAMEL_SERVICE_CLASS (remote_store_class)->connect (service, ex) == FALSE) return FALSE; store->command = 0; - g_free (store->dir_sep); - store->dir_sep = g_strdup ("/"); /* default dir sep */ if (!store->storage_path) { store->storage_path = camel_session_get_storage_path (session, service, ex); @@ -306,41 +305,53 @@ imap_connect (CamelService *service, CamelException *ex) store->has_status_capability = FALSE; g_free (result); - /* We now need to find out which directory separator this daemon - * uses. In the pre-4rev1 case, we can't do it, so we'll just - * hope that it's "/". - * FIXME: This code is wrong. The hierarchy separator is per - * namespace. - */ + /* Find the hierarchy separator for our namespace. */ + namespace = service->url->path; + if (namespace) + namespace++; + else + 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 \"\" \"\""); - if (!response) - return FALSE; - result = camel_imap_response_extract (response, "LIST", ex); - if (!result) - return FALSE; - else { - char *flags, *sep, *folder; - - if (imap_parse_list_response (result, "", &flags, - &sep, &folder)) { - if (*sep) { - g_free (store->dir_sep); - store->dir_sep = g_strdup (sep); - } - } + "LIST \"%s\" \"\"", + namespace); + } else { + /* Plain IMAP4 doesn't have that idiom, so we fall back + * to "tell me about this folder", which will fail if + * the folder doesn't exist (eg, if namespace is ""). + */ + response = camel_imap_command (store, NULL, ex, + "LIST \"\" \"%s\"", + namespace); + } + if (!response) + return FALSE; - g_free (flags); - g_free (sep); - g_free (folder); - g_free (result); - } + result = camel_imap_response_extract (response, "LIST", NULL); + if (result) { + imap_parse_list_response (result, NULL, &store->dir_sep, NULL); + g_free (result); + } + if (!store->dir_sep) + store->dir_sep = '/'; /* Guess */ + + /* Generate base URL */ + store->base_url = camel_url_to_string (service->url, FALSE); + len = strlen (store->base_url); + if (service->url->path) + store->base_url[len - strlen (service->url->path) + 1] = '\0'; + else { + store->base_url = g_realloc (store->base_url, len + 2); + store->base_url[len] = '/'; + store->base_url[len + 1] = '\0'; } camel_remote_store_refresh_folders (CAMEL_REMOTE_STORE (store), ex); - return ! camel_exception_is_set (ex); + return !camel_exception_is_set (ex); } static gboolean @@ -355,113 +366,92 @@ imap_disconnect (CamelService *service, CamelException *ex) camel_imap_response_free (response); } - g_free (store->dir_sep); - store->dir_sep = NULL; - store->current_folder = NULL; return CAMEL_SERVICE_CLASS (remote_store_class)->disconnect (service, ex); } -char * -camel_imap_store_folder_path (CamelImapStore *store, const char *name) -{ - CamelURL *url = CAMEL_SERVICE (store)->url; - char *namespace; - - if (url->path && *url->path) - namespace = url->path + 1; - else - namespace = ""; - - if (!*name) - return g_strdup (namespace); - else if (!g_strcasecmp (name, "INBOX") || !*namespace) - return g_strdup (name); - else - return g_strdup_printf ("%s%s%s", namespace, store->dir_sep, name); -} - static gboolean -imap_folder_exists (CamelImapStore *store, const char *folder_path, gboolean *selectable, CamelException *ex) +imap_folder_exists (CamelImapStore *store, const char *folder_name, + gboolean *selectable, char **short_name, + CamelException *ex) { CamelImapResponse *response; - char *result, *flags, *sep, *dirname; - - if (!g_strcasecmp (folder_path, "INBOX")) { + char *result, sep; + int flags; + + if (!g_strcasecmp (folder_name, "INBOX")) { if (selectable) *selectable = TRUE; + if (short_name) + *short_name = g_strdup ("INBOX"); return TRUE; } - - /* it's always gonna be FALSE unless it's true - how's that for a comment? ;-) */ - if (selectable) - *selectable = FALSE; - - response = camel_imap_command (store, NULL, ex, - "LIST \"\" \"%s\"", folder_path); + + response = camel_imap_command (store, NULL, ex, "LIST \"\" \"%s\"", + folder_name); if (!response) return FALSE; result = camel_imap_response_extract (response, "LIST", ex); if (!result) return FALSE; - if (imap_parse_list_response (result, "", &flags, &sep, &dirname)) { - if (selectable) - *selectable = !e_strstrcase (flags, "NoSelect"); - - g_free (flags); - g_free (sep); - g_free (dirname); - g_free (result); - - return TRUE; + if (!imap_parse_list_response (result, &flags, &sep, NULL)) + return FALSE; + + if (selectable) + *selectable = !(flags & IMAP_LIST_FLAG_NOSELECT); + if (short_name) { + *short_name = strrchr (folder_name, sep); + if (*short_name) + *short_name = g_strdup (*short_name + 1); + else + *short_name = g_strdup (folder_name); } - g_free (result); - - g_free (flags); - g_free (sep); - g_free (dirname); - - return FALSE; + + return TRUE; } static gboolean -imap_create (CamelImapStore *store, const char *folder_path, CamelException *ex) +imap_create (CamelImapStore *store, const char *folder_name, + CamelException *ex) { CamelImapResponse *response; - - response = camel_imap_command (store, NULL, ex, - "CREATE \"%s\"", folder_path); + + response = camel_imap_command (store, NULL, ex, "CREATE \"%s\"", + folder_name); camel_imap_response_free (response); return !camel_exception_is_set (ex); } static CamelFolder * -get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex) +get_folder (CamelStore *store, const char *folder_name, guint32 flags, + CamelException *ex) { CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); CamelFolder *new_folder = NULL; - char *folder_path, *summary_file, *p; + char *short_name, *summary_file, *p; gboolean selectable; - folder_path = camel_imap_store_folder_path (imap_store, folder_name); - if (!imap_folder_exists (imap_store, folder_path, &selectable, ex)) { - if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0) { - g_free (folder_path); + if (!imap_folder_exists (imap_store, folder_name, + &selectable, &short_name, ex)) { + if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0) return NULL; - } - if (!imap_create (imap_store, folder_path, ex)) { - g_free (folder_path); + if (!imap_create (imap_store, folder_name, ex)) return NULL; - } - } else if (!selectable) { + + if (!imap_folder_exists (imap_store, folder_name, + &selectable, &short_name, ex)) + return NULL; + } + + if (!selectable) { camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, "%s is not a selectable folder", folder_name); - g_free (folder_path); + g_free (short_name); return NULL; } @@ -473,14 +463,15 @@ get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelExce if (e_mkdir_hier (summary_file, S_IRWXU) == 0) { *p = '/'; new_folder = camel_imap_folder_new (store, folder_name, - summary_file, ex); + short_name, summary_file, + ex); } else { camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Could not create directory %s: %s"), summary_file, g_strerror (errno)); } g_free (summary_file); - g_free (folder_path); + g_free (short_name); if (camel_exception_is_set (ex)) return NULL; @@ -506,29 +497,32 @@ get_root_folder_name (CamelStore *store, CamelException *ex) } static CamelFolderInfo * -parse_list_response_as_folder_info (const char *response, - const char *namespace, - const char *base_url) +parse_list_response_as_folder_info (CamelImapStore *imap_store, + const char *response) { CamelFolderInfo *fi; - char *flags, *sep, *dir; + int flags; + char sep, *dir, *name; - if (!imap_parse_list_response (response, namespace, - &flags, &sep, &dir)) + if (!imap_parse_list_response (response, &flags, &sep, &dir)) return NULL; + if (sep) { + name = strrchr (dir, sep); + if (name && !*++name) { + g_free (dir); + return NULL; + } + } + fi = g_new0 (CamelFolderInfo, 1); fi->full_name = dir; - if (sep) - fi->name = strrchr (dir, *sep); - if (fi->name) - fi->name = g_strdup (fi->name + 1); + if (sep && name) + fi->name = g_strdup (name); else fi->name = g_strdup (dir); - g_free (sep); - if (!e_strstrcase (flags, "\\NoSelect")) - fi->url = g_strdup_printf ("%s%s", base_url, dir); - g_free (flags); + if (!(flags & IMAP_LIST_FLAG_NOSELECT)) + fi->url = g_strdup_printf ("%s%s", imap_store->base_url, dir); return fi; } @@ -540,65 +534,55 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast, { CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); CamelURL *url = CAMEL_SERVICE (store)->url; - gboolean found_inbox = FALSE; - int len, i; + gboolean need_inbox = FALSE; + int i; CamelImapResponse *response; GPtrArray *folders; - char *dir_sep, *namespace, *base_url, *list; - char *folder_path, *status, *p; - CamelFolderInfo *topfi = NULL, *fi; - - /* every time we get a list of subscribed folders, we clear - out our present notion of them - the hashtable will be - repopulated below. */ - if (subscribed_only) { - g_hash_table_foreach (imap_store->subscribed_folders, (GHFunc)g_free, NULL); + const char *name; + char *pattern, *list; + char *status, *p; + CamelFolderInfo *topfi, *fi; + + name = top; + if (!name) { + need_inbox = !subscribed_only; + if (url->path) + name = url->path + 1; + else + name = ""; } - - if (!top) - top = ""; - dir_sep = imap_store->dir_sep; - namespace = camel_imap_store_folder_path (imap_store, top); - - /* Yah! I am complicated! */ - base_url = camel_url_to_string (url, FALSE); - len = strlen (base_url); - if (url->path && base_url[len - 1] != *dir_sep) { - base_url = g_realloc (base_url, len + 2); - base_url[len] = *dir_sep; - base_url[len + 1] = '\0'; - } else if (!url->path) { - base_url = g_realloc (base_url, len + 2); - base_url[len] = '/'; - base_url[len + 1] = '\0'; - } - response = camel_imap_command (imap_store, NULL, ex, - "LIST \"\" \"%s\"", namespace); - if (response) { - list = camel_imap_response_extract (response, "LIST", ex); - if (list) { - topfi = parse_list_response_as_folder_info ( - list, namespace, base_url); - g_free (list); - } - } + "LIST \"\" \"%s\"", name); + if (!response) + return FALSE; + list = camel_imap_response_extract (response, "LIST", ex); + if (!list) + return FALSE; + topfi = parse_list_response_as_folder_info (imap_store, list); + g_free (list); if (!topfi) { - camel_exception_clear (ex); topfi = g_new0 (CamelFolderInfo, 1); - topfi->full_name = g_strdup (namespace); - topfi->name = g_strdup (namespace); + topfi->full_name = g_strdup (name); + topfi->name = g_strdup (name); } + if (!top && subscribed_only) + pattern = g_strdup (""); + else if (*name) + pattern = g_strdup_printf ("%s%c", name, imap_store->dir_sep); + else + pattern = g_strdup (name); response = camel_imap_command (imap_store, NULL, ex, - "%s \"\" \"%s%s%c\"", + "%s \"\" \"%s%c\"", subscribed_only ? "LSUB" : "LIST", - namespace, *namespace ? dir_sep : "", - recursive ? '*' : '%'); - if (!response) { - g_free (namespace); - g_free (base_url); + pattern, recursive ? '*' : '%'); + g_free (pattern); + if (!response) return NULL; + + if (subscribed_only) { + g_hash_table_foreach (imap_store->subscribed_folders, + (GHFunc)g_free, NULL); } /* Turn responses into CamelFolderInfo and remove any @@ -607,29 +591,28 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast, folders = g_ptr_array_new (); for (i = 0; i < response->untagged->len; i++) { list = response->untagged->pdata[i]; - fi = parse_list_response_as_folder_info (list, namespace, - base_url); + fi = parse_list_response_as_folder_info (imap_store, list); if (!fi) continue; g_ptr_array_add (folders, fi); if (subscribed_only) { - char *tmp; - tmp = g_strdup_printf("%s%s%s", namespace, *namespace ? dir_sep : "", fi->full_name); - g_hash_table_insert (imap_store->subscribed_folders, tmp, tmp); + g_hash_table_insert (imap_store->subscribed_folders, + g_strdup (fi->full_name), + GUINT_TO_POINTER (1)); } if (!g_strcasecmp (fi->full_name, "INBOX")) - found_inbox = TRUE; + need_inbox = FALSE; } camel_imap_response_free (response); /* Add INBOX, if necessary */ - if (!*top && !found_inbox) { + if (need_inbox) { fi = g_new0 (CamelFolderInfo, 1); fi->full_name = g_strdup ("INBOX"); fi->name = g_strdup ("INBOX"); - fi->url = g_strdup_printf ("%sINBOX", base_url); + fi->url = g_strdup_printf ("%sINBOX", imap_store->base_url); g_ptr_array_add (folders, fi); } @@ -641,13 +624,10 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast, if (!fi->url) continue; - folder_path = camel_imap_store_folder_path ( - imap_store, fi->full_name); response = camel_imap_command ( imap_store, NULL, NULL, "STATUS %s (MESSAGES UNSEEN)", - folder_path); - g_free (folder_path); + fi->full_name); if (!response) continue; status = camel_imap_response_extract ( @@ -666,11 +646,11 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast, } /* And assemble */ - camel_folder_info_build (folders, topfi, *dir_sep, TRUE); - g_ptr_array_free (folders, FALSE); + camel_folder_info_build (folders, topfi, imap_store->dir_sep, TRUE); + g_ptr_array_free (folders, TRUE); /* Remove the top if it's the root of the store. */ - if (!*top && !topfi->sibling) { + if (!top && !topfi->sibling && !topfi->url) { fi = topfi; topfi = topfi->child; fi->child = NULL; @@ -679,8 +659,6 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast, fi->parent = NULL; } - g_free (namespace); - g_free (base_url); return topfi; } @@ -688,12 +666,9 @@ static gboolean folder_subscribed (CamelStore *store, const char *folder_name) { CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - char *folder_path; - - folder_path = camel_imap_store_folder_path (imap_store, folder_name); return g_hash_table_lookup (imap_store->subscribed_folders, - folder_path) != NULL; + folder_name) != NULL; } static void @@ -702,18 +677,14 @@ subscribe_folder (CamelStore *store, const char *folder_name, { CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); CamelImapResponse *response; - char *folder_path; - - folder_path = camel_imap_store_folder_path (imap_store, folder_name); response = camel_imap_command (imap_store, NULL, ex, - "SUBSCRIBE \"%s\"", - folder_path); + "SUBSCRIBE \"%s\"", folder_name); if (response) { g_hash_table_insert (imap_store->subscribed_folders, - folder_path, folder_path); - } else - g_free (folder_path); + g_strdup (folder_name), + GUINT_TO_POINTER (1)); + } camel_imap_response_free (response); } @@ -723,23 +694,18 @@ unsubscribe_folder (CamelStore *store, const char *folder_name, { CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); CamelImapResponse *response; - char *folder_path; gpointer key, value; - folder_path = camel_imap_store_folder_path (imap_store, folder_name); - response = camel_imap_command (imap_store, NULL, ex, - "UNSUBSCRIBE \"%s\"", - folder_path); + "UNSUBSCRIBE \"%s\"", folder_name); if (response) { g_hash_table_lookup_extended (imap_store->subscribed_folders, - folder_path, key, value); + folder_name, key, value); g_hash_table_remove (imap_store->subscribed_folders, - folder_path); + folder_name); g_free (key); } camel_imap_response_free (response); - g_free (folder_path); } static void diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h index ddcc670f40..b5038ea7de 100644 --- a/camel/providers/imap/camel-imap-store.h +++ b/camel/providers/imap/camel-imap-store.h @@ -56,7 +56,7 @@ typedef struct { CamelImapServerLevel server_level; gboolean has_status_capability; - gchar *dir_sep, *storage_path; + gchar dir_sep, *storage_path, *base_url; gboolean connected; @@ -73,8 +73,6 @@ typedef struct { /* Standard Camel function */ CamelType camel_imap_store_get_type (void); -char *camel_imap_store_folder_path (CamelImapStore *store, const char *name); - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/camel/providers/imap/camel-imap-utils.c b/camel/providers/imap/camel-imap-utils.c index e4d8bfeb02..b38024ecc6 100644 --- a/camel/providers/imap/camel-imap-utils.c +++ b/camel/providers/imap/camel-imap-utils.c @@ -20,6 +20,7 @@ * */ +#include <ctype.h> #include <stdio.h> #include <string.h> #include <time.h> @@ -46,64 +47,81 @@ imap_next_word (const char *buf) return word; } +/** + * imap_parse_list_response: + * @buf: the LIST or LSUB response + * @flags: a pointer to a variable to store the flags in, or %NULL + * @sep: a pointer to a variable to store the hierarchy separator in, or %NULL + * @folder: a pointer to a variable to store the folder name in, or %NULL + * + * Parses a LIST or LSUB response and returns the desired parts of it. + * If @folder is non-%NULL, its value must be freed by the caller. + * + * Return value: whether or not the response was successfully parsed. + **/ gboolean -imap_parse_list_response (const char *buf, const char *namespace, char **flags, char **sep, char **folder) +imap_parse_list_response (const char *buf, int *flags, char *sep, char **folder) { - char *word, *ep, *f; - - *flags = NULL; - *sep = NULL; - *folder = NULL; - + char *word; + int len; + if (*buf != '*') return FALSE; - + word = imap_next_word (buf); if (g_strncasecmp (word, "LIST", 4) && g_strncasecmp (word, "LSUB", 4)) return FALSE; - + /* get the flags */ word = imap_next_word (word); if (*word != '(') return FALSE; - + + if (flags) + *flags = 0; + word++; - for (ep = word; *ep && *ep != ')'; ep++); - if (*ep != ')') - return FALSE; - - *flags = g_strndup (word, (gint)(ep - word)); - - /* get the directory separator */ - word = imap_next_word (ep); - if (*word) { - if (!strncmp (word, "NIL", 3)) { - *sep = NULL; - } else { - for (ep = word; *ep && *ep != ' '; ep++); - *sep = g_strndup (word, (gint)(ep - word)); - string_unquote (*sep); + while (*word != ')') { + len = strcspn (word, " )"); + if (flags) { + if (!g_strncasecmp (word, "\\Noinferiors", len)) + *flags |= IMAP_LIST_FLAG_NOINFERIORS; + else if (!g_strncasecmp (word, "\\Noselect", len)) + *flags |= IMAP_LIST_FLAG_NOSELECT; + else if (!g_strncasecmp (word, "\\Marked", len)) + *flags |= IMAP_LIST_FLAG_MARKED; + else if (!g_strncasecmp (word, "\\Unmarked", len)) + *flags |= IMAP_LIST_FLAG_UNMARKED; } - } else { - return FALSE; + + word += len; + while (*word == ' ') + word++; } - - /* get the folder name */ + + /* get the directory separator */ word = imap_next_word (word); - *folder = g_strdup (word); - g_strstrip (*folder); - string_unquote (*folder); - - /* chop out the folder prefix */ - if (*namespace && !strncmp (*folder, namespace, strlen (namespace))) { - f = *folder + strlen (namespace); - if (*sep && !strncmp (f, *sep, strlen (*sep))) - f += strlen (*sep); - memmove (*folder, f, strlen (f) + 1); + if (!strncmp (word, "NIL", 3)) { + if (sep) + *sep = '\0'; + } else if (*word++ == '"') { + if (*word == '\\') + word++; + if (sep) + *sep = *word; + word++; + if (*word++ != '"') + return FALSE; + } else + return FALSE; + + if (folder) { + /* get the folder name */ + word = imap_next_word (word); + *folder = imap_parse_astring (&word, &len); + return *folder != NULL; } - - string_unquote (*folder); /* unquote the mailbox if it's quoted */ - + return TRUE; } @@ -632,3 +650,39 @@ imap_parse_nstring (char **str_p, int *len) } } +/** + * imap_parse_astring: + * @str_p: a pointer to a string + * @len: a pointer to an int to return the length in + * + * This parses an "astring" (an atom, a quoted string, or a literal) + * starting at *@str_p. On success, *@str_p will point to the first + * character after the end of the astring, and *@len will contain + * the length of the returned string. On failure, *@str_p will be + * set to %NULL. + * + * This assumes that the string is in the form returned by + * camel_imap_command(): that line breaks are indicated by LF rather + * than CRLF. + * + * Return value: the parsed string, or %NULL if no string + * was parsed. (In this case, *@str_p will also be %NULL.) + **/ +char * +imap_parse_astring (char **str_p, int *len) +{ + char *p; + + if (**str_p == '{' || **str_p == '"') + return imap_parse_nstring (str_p, len); + + p = *str_p; + while (isascii ((unsigned char)*p) && + !strchr ("(){ \"\\%*", *p)) + p++; + + *len = p - *str_p; + p = g_strndup (*str_p, *len); + *str_p += *len; + return p; +} diff --git a/camel/providers/imap/camel-imap-utils.h b/camel/providers/imap/camel-imap-utils.h index 28dea3cc9f..d0cc05832d 100644 --- a/camel/providers/imap/camel-imap-utils.h +++ b/camel/providers/imap/camel-imap-utils.h @@ -32,7 +32,11 @@ extern "C" { char *imap_next_word (const char *buf); -gboolean imap_parse_list_response (const char *buf, const char *namespace, char **flags, char **sep, char **folder); +#define IMAP_LIST_FLAG_NOINFERIORS (1 << 0) +#define IMAP_LIST_FLAG_NOSELECT (1 << 1) +#define IMAP_LIST_FLAG_MARKED (1 << 2) +#define IMAP_LIST_FLAG_UNMARKED (1 << 3) +gboolean imap_parse_list_response (const char *buf, int *flags, char *sep, char **folder); char *imap_translate_sexp (const char *expression); @@ -40,6 +44,7 @@ char *imap_create_flag_list (guint32 flags); guint32 imap_parse_flag_list (const char *flag_list); char *imap_parse_nstring (char **str_p, int *len); +char *imap_parse_astring (char **str_p, int *len); #ifdef __cplusplus } |