aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/imap/camel-imap-store.c
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 /camel/providers/imap/camel-imap-store.c
parent9e6c10a18be76719fbba41c36c61abc9c1542710 (diff)
downloadgsoc2013-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
Diffstat (limited to 'camel/providers/imap/camel-imap-store.c')
-rw-r--r--camel/providers/imap/camel-imap-store.c368
1 files changed, 167 insertions, 201 deletions
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