aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camel/ChangeLog49
-rw-r--r--camel/camel-remote-store.c50
-rw-r--r--camel/camel-remote-store.h1
-rw-r--r--camel/camel-store.c72
-rw-r--r--camel/camel-store.h6
-rw-r--r--camel/providers/imap/camel-imap-store.c401
-rw-r--r--camel/providers/imap/camel-imap-store.h3
-rw-r--r--camel/providers/nntp/camel-nntp-store.c11
8 files changed, 386 insertions, 207 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index 18263b19cd..c947b4e04e 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,5 +1,54 @@
2001-01-09 Dan Winship <danw@helixcode.com>
+ Mostly IMAP changes. Use the NAMESPACE extension (where
+ available). Deal with servers that don't return LIST flags in
+ response to LSUB (like UW) to get rid of the "not a selectable
+ folder" error messages in the UI. Take advantage of the \Marked
+ and \Unmarked flags to try to speed up the folder scan by not
+ doing STATUS on unmarked folders. Some further tweaks on the shape
+ of the resulting folder tree in various situations...
+
+ * camel-store.h: Remove the (read) message_count, since nothing
+ uses it, and we can speed up IMAP a bit this way.
+
+ * camel-store.c (camel_folder_info_build): Redo this a bit to make
+ it more useful for IMAP since that's the only thing that uses it.
+
+ * camel-remote-store.c (camel_remote_store_connected): Public
+ function to check if the store is connected, and try to connect it
+ if it's not.
+ (remote_send_string, remote_send_stream, remote_recv_line): Use
+ that.
+
+ * providers/imap/camel-imap-store.c (camel_imap_store_finalize):
+ fix up for changes.
+ (camel_imap_store_init): Initialize subscribed_folders to NULL
+ rather than an empty hash table.
+ (imap_connect): Get the list of subscribed folders here. If the
+ server doesn't claim that any of them are either Marked or
+ Unmarked, then assume that it doesn't do that for LSUB and
+ remember that for later. If the server supports the NAMESPACE
+ extension and the user didn't specify a namespace, use the
+ server-provided one.
+ (imap_disconnect): Free the list of subscribed folders, and the
+ namespace.
+ (get_folder): check camel_remote_store_connected
+ (get_folder_info): check camel_remote_store_connected. Add a bunch
+ of new cleverness. If we learned that the server doesn't do LSUB
+ usefully, do a bunch of LISTs by hand. Then, if we're getting
+ unread counts, only do it for folders that weren't listed as
+ Unmarked. Also, deal with namespaces that end with the separator
+ character, and update for changes to camel_folder_info_build.
+ (folder_subscribed): Add a g_return_val_if_fail.
+ (subscribe_folder, unsubscribe_folder): check
+ camel_remote_store_connected.
+
+ * providers/nntp/camel-nntp-store.c (build_folder_info,
+ build_folder_info_from_grouplist, nntp_store_get_folder_info):
+ Don't fill in message_count since it doesn't exist any more.
+
+2001-01-09 Dan Winship <danw@helixcode.com>
+
Kill off a long-hated Camel kludge: "empty" URLs and
query_auth_types_generic.
diff --git a/camel/camel-remote-store.c b/camel/camel-remote-store.c
index 70b34ec1f2..8d095244e2 100644
--- a/camel/camel-remote-store.c
+++ b/camel/camel-remote-store.c
@@ -304,13 +304,8 @@ remote_send_string (CamelRemoteStore *store, CamelException *ex, char *fmt, va_l
/* Check for connectedness. Failed (or cancelled) operations will
* close the connection. */
-
- if (store->ostream == NULL) {
- d(g_message ("remote: (send) disconnected, reconnecting."));
-
- if (!camel_service_connect (CAMEL_SERVICE (store), ex))
- return -1;
- }
+ if (!camel_remote_store_connected (store, ex))
+ return -1;
/* create the command */
cmdbuf = g_strdup_vprintf (fmt, ap);
@@ -380,12 +375,8 @@ remote_send_stream (CamelRemoteStore *store, CamelStream *stream, CamelException
/* Check for connectedness. Failed (or cancelled) operations will
* close the connection. */
- if (store->ostream == NULL) {
- d(g_message ("remote: (sendstream) disconnected, reconnecting."));
-
- if (!camel_service_connect (CAMEL_SERVICE (store), ex))
- return -1;
- }
+ if (!camel_remote_store_connected (store, ex))
+ return -1;
d(fprintf (stderr, "(sending stream)\n"));
@@ -442,18 +433,12 @@ remote_recv_line (CamelRemoteStore *store, char **dest, CamelException *ex)
* meaning if we reconnect, so always set an exception.
*/
- if (store->istream == NULL) {
- g_message ("remote: (recv) disconnected, reconnecting.");
-
- camel_service_connect (CAMEL_SERVICE (store), ex);
-
- if (!camel_exception_is_set (ex))
- camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_NOT_CONNECTED,
- g_strerror (errno));
-
+ if (!camel_remote_store_connected (store, ex)) {
+ camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_NOT_CONNECTED,
+ g_strerror (errno));
return -1;
}
-
+
bytes = g_byte_array_new ();
do {
@@ -547,3 +532,22 @@ camel_remote_store_refresh_folders (CamelRemoteStore *store, CamelException *ex)
CAMEL_STORE_UNLOCK(store, cache_lock);
}
+
+/**
+ * camel_remote_store_connected:
+ * @store: a CamelRemoteStore
+ * @ex: a CamelException
+ *
+ * Ensure that the remote store is connected.
+ *
+ * Return value: Whether or not it is connected
+ **/
+gboolean
+camel_remote_store_connected (CamelRemoteStore *store, CamelException *ex)
+{
+ if (store->istream == NULL) {
+ camel_service_connect (CAMEL_SERVICE (store), ex);
+ return !camel_exception_is_set (ex);
+ }
+ return TRUE;
+}
diff --git a/camel/camel-remote-store.h b/camel/camel-remote-store.h
index 910db53e92..51322b6886 100644
--- a/camel/camel-remote-store.h
+++ b/camel/camel-remote-store.h
@@ -75,6 +75,7 @@ gint camel_remote_store_recv_line (CamelRemoteStore *store, char **dest,
CamelException *ex);
void camel_remote_store_refresh_folders (CamelRemoteStore *store,
CamelException *ex);
+gboolean camel_remote_store_connected (CamelRemoteStore *store, CamelException *ex);
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/camel/camel-store.c b/camel/camel-store.c
index 48ec13918b..7c61809150 100644
--- a/camel/camel-store.c
+++ b/camel/camel-store.c
@@ -558,48 +558,54 @@ camel_folder_info_free (CamelFolderInfo *fi)
/**
* camel_folder_info_build:
* @folders: an array of CamelFolderInfo
- * @top: the top of the folder tree
+ * @namespace: an ignorable prefix on the folder names
* @separator: the hieararchy separator character
* @short_names: %TRUE if the (short) name of a folder is the part after
* the last @separator in the full name. %FALSE if it is the full name.
*
- * This takes an array of folders and attaches them together. @top points
- * to the (or at least, "a") top-level element of the tree: it may or may
- * not also be an element of @folders. If necessary, camel_folder_info_build
- * will create additional CamelFolderInfo with %NULL urls to fill in gaps
- * in the tree. The value of @short_names is used in constructing the
- * names of these intermediate folders.
+ * This takes an array of folders and attaches them together according
+ * to the hierarchy described by their full_names and @separator. If
+ * @namespace is non-%NULL, then it will be ignored as a full_name
+ * prefix, for purposes of comparison. If necessary,
+ * camel_folder_info_build will create additional CamelFolderInfo with
+ * %NULL urls to fill in gaps in the tree. The value of @short_names
+ * is used in constructing the names of these intermediate folders.
+ *
+ * Return value: the top level of the tree of linked folder info.
**/
-void
-camel_folder_info_build (GPtrArray *folders, CamelFolderInfo *top,
+CamelFolderInfo *
+camel_folder_info_build (GPtrArray *folders, const char *namespace,
char separator, gboolean short_names)
{
- CamelFolderInfo *fi, *pfi;
+ CamelFolderInfo *fi, *pfi, *top = NULL;
GHashTable *hash;
- char *p, *pname;
- int i;
+ char *name, *p, *pname;
+ int i, nlen;
+
+ if (!namespace)
+ namespace = "";
+ nlen = strlen (namespace);
/* 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 (!strncmp (namespace, fi->full_name, nlen))
+ g_hash_table_insert (hash, fi->full_name + nlen, fi);
+ else
+ 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++) {
fi = folders->pdata[i];
- if (fi == top)
- continue;
-
- p = strrchr (fi->full_name, separator);
+ if (!strncmp (namespace, fi->full_name, nlen))
+ name = fi->full_name + nlen;
+ else
+ name = fi->full_name;
+ p = strrchr (name, separator);
if (p) {
- pname = g_strndup (fi->full_name, p - fi->full_name);
+ pname = g_strndup (name, p - name);
pfi = g_hash_table_lookup (hash, pname);
if (pfi) {
g_free (pname);
@@ -620,12 +626,22 @@ camel_folder_info_build (GPtrArray *folders, CamelFolderInfo *top,
fi->sibling = pfi->child;
fi->parent = pfi;
pfi->child = fi;
- } else {
- fi->sibling = top->child;
- fi->parent = top;
- top->child = fi;
- }
+ } else if (!top)
+ top = fi;
}
+ g_hash_table_destroy (hash);
+
+ /* Link together the top-level folders */
+ for (i = 0; i < folders->len; i++) {
+ fi = folders->pdata[i];
+ if (fi->parent || fi == top)
+ continue;
+ if (top)
+ fi->sibling = top;
+ top = fi;
+ }
+
+ return top;
}
gboolean
diff --git a/camel/camel-store.h b/camel/camel-store.h
index 0ad6e0cbed..4df8fa369f 100644
--- a/camel/camel-store.h
+++ b/camel/camel-store.h
@@ -41,7 +41,7 @@ extern "C" {
typedef struct _CamelFolderInfo {
struct _CamelFolderInfo *parent, *sibling, *child;
char *url, *full_name, *name;
- int message_count, unread_message_count;
+ int unread_message_count;
} CamelFolderInfo;
@@ -158,8 +158,8 @@ void camel_store_free_folder_info_nop (CamelStore *store,
CamelFolderInfo *fi);
void camel_folder_info_free (CamelFolderInfo *fi);
-void camel_folder_info_build (GPtrArray *folders,
- CamelFolderInfo *top,
+CamelFolderInfo *camel_folder_info_build (GPtrArray *folders,
+ const char *namespace,
char separator,
gboolean short_names);
diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c
index 7b3691efe6..d3701ca5b7 100644
--- a/camel/providers/imap/camel-imap-store.c
+++ b/camel/providers/imap/camel-imap-store.c
@@ -118,9 +118,13 @@ camel_imap_store_finalize (CamelObject *object)
{
CamelImapStore *imap_store = CAMEL_IMAP_STORE (object);
- g_hash_table_foreach_remove (imap_store->subscribed_folders,
- free_sub, NULL);
- g_hash_table_destroy (imap_store->subscribed_folders);
+ if (imap_store->subscribed_folders) {
+ g_hash_table_foreach_remove (imap_store->subscribed_folders,
+ free_sub, NULL);
+ g_hash_table_destroy (imap_store->subscribed_folders);
+ }
+ if (imap_store->namespace)
+ g_free (imap_store->namespace);
#ifdef ENABLE_THREADS
e_mutex_destroy(imap_store->priv->command_lock);
#endif
@@ -142,7 +146,7 @@ camel_imap_store_init (gpointer object, gpointer klass)
store->flags = CAMEL_STORE_SUBSCRIPTIONS;
imap_store->connected = FALSE;
- imap_store->subscribed_folders = g_hash_table_new (g_str_hash, g_str_equal);
+ imap_store->subscribed_folders = NULL;
imap_store->priv = g_malloc0(sizeof(*imap_store->priv));
#ifdef ENABLE_THREADS
@@ -284,10 +288,10 @@ imap_connect (CamelService *service, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (service);
CamelSession *session = camel_service_get_session (CAMEL_SERVICE (store));
- gchar *result, *errbuf = NULL, *namespace;
+ char *result, *errbuf = NULL, *name;
CamelImapResponse *response;
gboolean authenticated = FALSE;
- int len;
+ int len, i, flags;
if (connect_to_server (service, ex) == 0)
return FALSE;
@@ -366,50 +370,92 @@ imap_connect (CamelService *service, CamelException *ex)
}
}
- /* Find our storage path. */
- if (!store->storage_path) {
- store->storage_path =
- camel_session_get_storage_path (session, service, ex);
- if (camel_exception_is_set (ex))
- return FALSE;
+ /* Get subscribed folders */
+ CAMEL_IMAP_STORE_LOCK (store, command_lock);
+ response = camel_imap_command (store, NULL, ex, "LSUB \"\" \"*\"");
+ CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
+ if (!response)
+ return FALSE;
+ store->subscribed_folders = g_hash_table_new (g_str_hash, g_str_equal);
+ for (i = 0; i < response->untagged->len; i++) {
+ result = response->untagged->pdata[i];
+ if (!imap_parse_list_response (result, &flags, NULL, &name))
+ continue;
+ if (flags & (IMAP_LIST_FLAG_MARKED | IMAP_LIST_FLAG_UNMARKED))
+ store->useful_lsub = TRUE;
+ if (flags & IMAP_LIST_FLAG_NOSELECT) {
+ g_free (name);
+ continue;
+ }
+ g_hash_table_insert (store->subscribed_folders, name,
+ GINT_TO_POINTER (flags));
}
+ camel_imap_response_free (response);
- /* Find the hierarchy separator for our namespace. */
- namespace = service->url->path;
- if (namespace)
- namespace++;
- else
- namespace = "";
+ /* Get namespace and hierarchy separator */
+ if (service->url->path && strlen (service->url->path) > 1)
+ store->namespace = g_strdup (service->url->path + 1);
+ else if (store->capabilities & IMAP_CAPABILITY_NAMESPACE) {
+ CAMEL_IMAP_STORE_LOCK (store, command_lock);
+ response = camel_imap_command (store, NULL, ex, "NAMESPACE");
+ CAMEL_IMAP_STORE_UNLOCK (store, command_lock);
+ if (!response)
+ return FALSE;
- CAMEL_IMAP_STORE_LOCK(store, command_lock);
- 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 %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);
+ result = camel_imap_response_extract (response, "NAMESPACE", ex);
+ if (!result)
+ return FALSE;
+
+ name = e_strstrcase (result, "NAMESPACE ((");
+ if (name) {
+ char *sep;
+
+ name += 12;
+ store->namespace = imap_parse_string (&name, &len);
+ if (name && *name++ == ' ') {
+ sep = imap_parse_string (&name, &len);
+ if (sep) {
+ store->dir_sep = *sep;
+ g_free (sep);
+ }
+ }
+ }
+ g_free (result);
}
- CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
+ if (!store->namespace)
+ store->namespace = g_strdup ("");
- if (!response)
- return FALSE;
+ if (!store->dir_sep) {
+ CAMEL_IMAP_STORE_LOCK(store, command_lock);
+ 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 %S \"\"",
+ store->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",
+ store->namespace);
+ }
+ CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
- result = camel_imap_response_extract (response, "LIST", NULL);
- if (result) {
- imap_parse_list_response (result, NULL, &store->dir_sep, NULL);
- g_free (result);
+ if (!response)
+ return FALSE;
+
+ 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 */
}
- if (!store->dir_sep)
- store->dir_sep = '/'; /* Guess */
/* Generate base URL */
store->base_url = camel_url_to_string (service->url, FALSE);
@@ -422,6 +468,14 @@ imap_connect (CamelService *service, CamelException *ex)
store->base_url[len + 1] = '\0';
}
+ /* Find our storage path. */
+ if (!store->storage_path) {
+ store->storage_path =
+ camel_session_get_storage_path (session, service, ex);
+ if (camel_exception_is_set (ex))
+ return FALSE;
+ }
+
camel_remote_store_refresh_folders (CAMEL_REMOTE_STORE (store), ex);
return !camel_exception_is_set (ex);
@@ -442,9 +496,21 @@ imap_disconnect (CamelService *service, gboolean clean, CamelException *ex)
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
camel_imap_response_free (response);
}
-
+ store->connected = FALSE;
store->current_folder = NULL;
-
+
+ if (store->subscribed_folders) {
+ g_hash_table_foreach_remove (store->subscribed_folders,
+ free_sub, NULL);
+ g_hash_table_destroy (store->subscribed_folders);
+ store->subscribed_folders = NULL;
+ }
+
+ if (store->namespace) {
+ g_free (store->namespace);
+ store->namespace = NULL;
+ }
+
return CAMEL_SERVICE_CLASS (remote_store_class)->disconnect (service, clean, ex);
}
@@ -513,6 +579,9 @@ get_folder (CamelStore *store, const char *folder_name, guint32 flags,
char *short_name, *summary_file, *p;
gboolean selectable;
+ if (!camel_remote_store_connected (CAMEL_REMOTE_STORE (store), ex))
+ return NULL;
+
/* lock around the whole lot to check/create atomically */
CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
if (!imap_folder_exists (imap_store, folder_name,
@@ -603,129 +672,183 @@ parse_list_response_as_folder_info (CamelImapStore *imap_store,
fi->name = g_strdup (dir);
if (!(flags & IMAP_LIST_FLAG_NOSELECT))
fi->url = g_strdup_printf ("%s%s", imap_store->base_url, dir);
+ if (!(flags & IMAP_LIST_FLAG_UNMARKED))
+ fi->unread_message_count = -1;
return fi;
}
+static void
+copy_folder_name (gpointer name, gpointer key, gpointer array)
+{
+ g_ptr_array_add (array, name);
+}
+
+static void
+get_subscribed_folders_by_hand (CamelImapStore *imap_store, const char *top,
+ GPtrArray *folders, CamelException *ex)
+{
+ GPtrArray *names;
+ CamelImapResponse *response;
+ CamelFolderInfo *fi;
+ char *result;
+ int i, toplen = strlen (top);
+
+ names = g_ptr_array_new ();
+ g_hash_table_foreach (imap_store->subscribed_folders,
+ copy_folder_name, names);
+
+ for (i = 0; i < names->len; i++) {
+ CAMEL_IMAP_STORE_LOCK (imap_store, command_lock);
+ response = camel_imap_command (imap_store, NULL, ex,
+ "LIST \"\" %S",
+ names->pdata[i]);
+ CAMEL_IMAP_STORE_UNLOCK (imap_store, command_lock);
+
+ if (!response) {
+ g_ptr_array_free (names, TRUE);
+ return;
+ }
+ result = camel_imap_response_extract (response, "LIST", ex);
+ if (!result) {
+ g_ptr_array_free (names, TRUE);
+ return;
+ }
+
+ fi = parse_list_response_as_folder_info (imap_store, result);
+ if (!fi)
+ continue;
+
+ if (strncmp (top, fi->full_name, toplen) != 0) {
+ camel_folder_info_free (fi);
+ continue;
+ }
+
+ g_ptr_array_add (folders, fi);
+ }
+ g_ptr_array_free (names, TRUE);
+}
+
+static void
+get_folders (CamelImapStore *imap_store, const char *pattern,
+ GPtrArray *folders, gboolean lsub, CamelException *ex)
+{
+ CamelImapResponse *response;
+ CamelFolderInfo *fi;
+ char *list;
+ int i;
+
+ CAMEL_IMAP_STORE_LOCK (imap_store, command_lock);
+ response = camel_imap_command (imap_store, NULL, ex,
+ "%s \"\" %S", lsub ? "LSUB" : "LIST",
+ pattern);
+ CAMEL_IMAP_STORE_UNLOCK (imap_store, command_lock);
+ if (!response)
+ return;
+
+ for (i = 0; i < response->untagged->len; i++) {
+ list = response->untagged->pdata[i];
+ fi = parse_list_response_as_folder_info (imap_store, list);
+ if (!fi)
+ continue;
+ g_ptr_array_add (folders, fi);
+ }
+ camel_imap_response_free (response);
+}
+
static CamelFolderInfo *
get_folder_info (CamelStore *store, const char *top, gboolean fast,
gboolean recursive, gboolean subscribed_only,
CamelException *ex)
{
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
- CamelURL *url = CAMEL_SERVICE (store)->url;
gboolean need_inbox = FALSE;
- int i;
CamelImapResponse *response;
GPtrArray *folders;
- const char *name;
- char *pattern, *list;
- char *status;
- const char *p;
- CamelFolderInfo *topfi, *fi;
+ const char *name, *p;
+ char *pattern, *status;
+ CamelFolderInfo *fi;
+ int i;
+
+ if (!camel_remote_store_connected (CAMEL_REMOTE_STORE (store), ex))
+ return NULL;
name = top;
if (!name) {
need_inbox = TRUE;
- if (url->path)
- name = url->path + 1;
- else
- name = "";
- }
- CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
- response = camel_imap_command (imap_store, NULL, ex,
- "LIST \"\" %S", name);
- CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
- 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) {
- topfi = g_new0 (CamelFolderInfo, 1);
- topfi->full_name = g_strdup (name);
- topfi->name = g_strdup (name);
+ name = imap_store->namespace;
}
- if (*name)
- pattern = g_strdup_printf ("%s%c%c", name, imap_store->dir_sep,
- recursive ? '*' : '%');
- else
- pattern = g_strdup_printf ("%s%c", name,
- recursive ? '*' : '%');
- CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
- response = camel_imap_command (imap_store, NULL, ex,
- "%s \"\" %S",
- subscribed_only ? "LSUB" : "LIST",
- pattern);
- CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
+ folders = g_ptr_array_new ();
- g_free (pattern);
- if (!response)
+ get_folders (imap_store, name, folders, FALSE, ex);
+ if (camel_exception_is_set (ex))
return NULL;
-
- if (subscribed_only) {
- g_hash_table_foreach_remove (imap_store->subscribed_folders,
- free_sub, NULL);
+ if (folders->len) {
+ fi = folders->pdata[0];
+ if (!fi->url)
+ g_ptr_array_remove_index (folders, 0);
}
- /* Turn responses into CamelFolderInfo and remove any
- * extraneous responses.
- */
- 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 (imap_store, list);
- if (!fi)
- continue;
- g_ptr_array_add (folders, fi);
-
- if (subscribed_only) {
- g_hash_table_insert (imap_store->subscribed_folders,
- g_strdup (fi->full_name),
- GUINT_TO_POINTER (1));
+ if (subscribed_only && !imap_store->useful_lsub)
+ get_subscribed_folders_by_hand (imap_store, name, folders, ex);
+ else {
+ if (*name && name[strlen (name) - 1] != imap_store->dir_sep) {
+ pattern = g_strdup_printf ("%s%c%c", name,
+ imap_store->dir_sep,
+ recursive ? '*' : '%');
+ } else {
+ pattern = g_strdup_printf ("%s%c", name,
+ recursive ? '*' : '%');
}
-
- if (!g_strcasecmp (fi->full_name, "INBOX"))
- need_inbox = FALSE;
+ get_folders (imap_store, pattern, folders, subscribed_only, ex);
+ g_free (pattern);
+ }
+ if (camel_exception_is_set (ex)) {
+ for (i = 0; i < folders->len; i++)
+ camel_folder_info_free (folders->pdata[i]);
+ g_ptr_array_free (folders, TRUE);
+ return NULL;
}
- camel_imap_response_free (response);
/* Add INBOX, if necessary */
if (need_inbox) {
+ for (i = 0; i < folders->len; i++) {
+ fi = folders->pdata[i];
+ if (!g_strcasecmp (fi->full_name, "INBOX")) {
+ need_inbox = FALSE;
+ break;
+ }
+ }
+ }
+ 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", imap_store->base_url);
+ fi->unread_message_count = -1;
g_ptr_array_add (folders, fi);
}
if (!fast) {
- /* Get read/unread counts */
+ /* Get unread counts */
for (i = 0; i < folders->len; i++) {
fi = folders->pdata[i];
- if (!fi->url)
+ if (!fi->url || fi->unread_message_count != -1)
continue;
- CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
- response = camel_imap_command (
- imap_store, NULL, NULL,
- "STATUS %S (MESSAGES UNSEEN)",
- fi->full_name);
- CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
+ CAMEL_IMAP_STORE_LOCK (imap_store, command_lock);
+ response = camel_imap_command (imap_store, NULL, NULL,
+ "STATUS %S (UNSEEN)",
+ fi->full_name);
+ CAMEL_IMAP_STORE_UNLOCK (imap_store, command_lock);
if (!response)
continue;
- status = camel_imap_response_extract (
- response, "STATUS", NULL);
+ status = camel_imap_response_extract (response, "STATUS", NULL);
if (!status)
continue;
- p = e_strstrcase (status, "MESSAGES");
- if (p)
- fi->message_count = strtoul (p + 8, NULL, 10);
p = e_strstrcase (status, "UNSEEN");
if (p)
fi->unread_message_count = strtoul (p + 6, NULL, 10);
@@ -733,30 +856,10 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
}
}
- /* And assemble */
- camel_folder_info_build (folders, topfi, imap_store->dir_sep, TRUE);
+ /* And assemble. */
+ fi = camel_folder_info_build (folders, name, imap_store->dir_sep, TRUE);
g_ptr_array_free (folders, TRUE);
-
- /* If this is the root of the store, prune off any namespace. */
- if (!top && !topfi->sibling) {
- int toplen = strlen (name), len;
-
- while (!topfi->sibling) {
- len = strlen (topfi->full_name);
- if (len > toplen ||
- strncmp (topfi->full_name, name, len) != 0)
- break;
-
- fi = topfi;
- topfi = topfi->child;
- fi->child = NULL;
- camel_folder_info_free (fi);
- for (fi = topfi; fi; fi = fi->sibling)
- fi->parent = NULL;
- }
- }
-
- return topfi;
+ return fi;
}
static gboolean
@@ -764,6 +867,8 @@ folder_subscribed (CamelStore *store, const char *folder_name)
{
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ g_return_val_if_fail (imap_store->subscribed_folders != NULL, FALSE);
+
return g_hash_table_lookup (imap_store->subscribed_folders,
folder_name) != NULL;
}
@@ -775,6 +880,9 @@ subscribe_folder (CamelStore *store, const char *folder_name,
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
CamelImapResponse *response;
+ if (!camel_remote_store_connected (CAMEL_REMOTE_STORE (store), ex))
+ return;
+
CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
response = camel_imap_command (imap_store, NULL, ex,
"SUBSCRIBE %S", folder_name);
@@ -794,6 +902,9 @@ unsubscribe_folder (CamelStore *store, const char *folder_name,
CamelImapResponse *response;
gpointer key, value;
+ if (!camel_remote_store_connected (CAMEL_REMOTE_STORE (store), ex))
+ return;
+
CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
response = camel_imap_command (imap_store, NULL, ex,
"UNSUBSCRIBE %S", folder_name);
diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h
index cd93d8eddf..2e944d12d2 100644
--- a/camel/providers/imap/camel-imap-store.h
+++ b/camel/providers/imap/camel-imap-store.h
@@ -65,11 +65,12 @@ typedef struct {
CamelImapServerLevel server_level;
guint32 capabilities;
- gchar dir_sep, *storage_path, *base_url;
+ char *namespace, dir_sep, *storage_path, *base_url;
gboolean connected;
GHashTable *subscribed_folders;
+ gboolean useful_lsub;
} CamelImapStore;
diff --git a/camel/providers/nntp/camel-nntp-store.c b/camel/providers/nntp/camel-nntp-store.c
index a3f6926a2a..21de4fbdb1 100644
--- a/camel/providers/nntp/camel-nntp-store.c
+++ b/camel/providers/nntp/camel-nntp-store.c
@@ -359,7 +359,6 @@ build_folder_info (CamelNNTPStore *nntp_store, CamelFolderInfo **root,
node->name = g_strdup (node_name);
node->full_name = g_strdup (node_full_name);
node->url = NULL;
- node->message_count = -1;
node->unread_message_count = -1;
if (parent) {
@@ -399,8 +398,7 @@ build_folder_info (CamelNNTPStore *nntp_store, CamelFolderInfo **root,
url->user ? "@" : "",
url->host, (char *)entry->group_name);
- new_group->message_count = entry->high - entry->low;
- new_group->unread_message_count = (new_group->message_count -
+ new_group->unread_message_count = (entry->high - entry->low -
camel_nntp_newsrc_get_num_articles_read (nntp_store->newsrc, entry->group_name));
if (parent) {
@@ -454,8 +452,7 @@ build_folder_info_from_grouplist (CamelNNTPStore *nntp_store, const char *top)
url->user ? "@" : "",
url->host, (char *)entry->group_name);
- fi->message_count = entry->high - entry->low;
- fi->unread_message_count = (fi->message_count -
+ fi->unread_message_count = (entry->high - entry->low -
camel_nntp_newsrc_get_num_articles_read (
nntp_store->newsrc, entry->group_name));
@@ -520,7 +517,7 @@ nntp_store_get_folder_info (CamelStore *store, const char *top,
url->user ? "@" : "",
url->host, (char *)names->pdata[i]);
/* FIXME */
- fi->message_count = fi->unread_message_count = -1;
+ fi->unread_message_count = -1;
if (last)
last->sibling = fi;
@@ -540,7 +537,7 @@ nntp_store_get_folder_info (CamelStore *store, const char *top,
fi->full_name = g_strdup (top);
fi->url = g_strdup_printf ("nntp://%s/%s", url->host, top);
/* FIXME */
- fi->message_count = fi->unread_message_count = -1;
+ fi->unread_message_count = -1;
return fi;
}