aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Winship <danw@src.gnome.org>2000-10-30 11:24:15 +0800
committerDan Winship <danw@src.gnome.org>2000-10-30 11:24:15 +0800
commitd4656431e9de8e6e3ab526d71323f0d0543c587e (patch)
tree59b0ff39e227e6079d696c3dd29c8e1e0344dec2
parent9e6c10a18be76719fbba41c36c61abc9c1542710 (diff)
downloadgsoc2013-evolution-d4656431e9de8e6e3ab526d71323f0d0543c587e.tar.gz
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/ChangeLog41
-rw-r--r--camel/camel-store.c5
-rw-r--r--camel/providers/imap/camel-imap-command.c8
-rw-r--r--camel/providers/imap/camel-imap-folder.c45
-rw-r--r--camel/providers/imap/camel-imap-folder.h1
-rw-r--r--camel/providers/imap/camel-imap-store.c368
-rw-r--r--camel/providers/imap/camel-imap-store.h4
-rw-r--r--camel/providers/imap/camel-imap-utils.c138
-rw-r--r--camel/providers/imap/camel-imap-utils.h7
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
}