aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camel/ChangeLog91
-rw-r--r--camel/camel-private.h14
-rw-r--r--camel/camel-store-summary.c288
-rw-r--r--camel/camel-store-summary.h93
-rw-r--r--camel/camel-store.h2
-rw-r--r--camel/camel-url.h2
-rw-r--r--camel/providers/imap/Makefile.am2
-rw-r--r--camel/providers/imap/camel-imap-command.c8
-rw-r--r--camel/providers/imap/camel-imap-store-summary.c519
-rw-r--r--camel/providers/imap/camel-imap-store-summary.h100
-rw-r--r--camel/providers/imap/camel-imap-store.c815
-rw-r--r--camel/providers/imap/camel-imap-store.h4
-rw-r--r--camel/providers/imap/camel-imap-utils.c15
13 files changed, 1379 insertions, 574 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index c7183dd317..7e65ed67ef 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,13 @@
+2002-09-04 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-store.c,
+ providers/imap/camel-imap-folder.c: Lots of changes, too numerous
+ to list. Changed to use camel-imap-store-summary to cache list
+ requests. Changed to use a canonicalised url path with / instead
+ of per-store directory separator. Indirects folder name so
+ invalid folder names can still be accessed. Summary now stored in
+ a new expandable format in .ev-store-summary.
+
2002-08-29 Not Zed <NotZed@Ximian.com>
* tests/folder/test3.c: Change the case sensitive search of
@@ -123,6 +133,87 @@
(camel_session_register_timeout): Removed.
(camel_session_remove_timeout): Removed.
+2002-08-28 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-store.c (construct): Load store
+ summary if it exists.
+ (can_work_offline): Just see if we have any folders to say whether
+ we can work offline or not. Should probably always just return
+ true.
+
+2002-08-27 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-store-summary.[ch]: New files to
+ handle offline definition of folders, etc.
+
+ * camel-url.h: Define CamelURL to be struct _CamelURL rather than
+ anonymous struct.
+
+ * camel-store-summary.[ch]: a few api tweaks. Also, the summary
+ header is versioned separately at each level, so that version
+ upgrades can be handled separately. Renamed FolderInfo ->
+ StoreInfo to avoid namespace with current FolderInfo code. This
+ should be reversed when the FolderInfo code is rationalised to
+ this new base.
+
+2002-08-23 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-command.c (camel_imap_command): domt
+ encode folder name.
+
+ * providers/imap/camel-imap-folder.c (do_copy): dont encode folder
+ name.
+ (do_append): dont encode folder name.
+
+ * providers/imap/camel-imap-store.c (get_folder_status): don
+ encode folder name in imap request.
+ (get_folder_online): here too for creating folder.
+ (rename_folder): Assume the incoming 'new name' is a utf8 path,
+ whereas the 'old name' is as from get folder info (raw).
+ (create_folder): Dont encode parent_name, assume its the raw
+ thing.
+
+2002-08-22 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-store.c (get_folder_online): Select
+ based on unconverted name.
+ (imap_build_folder_info): New function to create a folderinfo
+ properly based on raw name.
+ (subscribe_folder): Use above helper.
+ (imap_folder_effectively_unsubscribed): Same here.
+ (imap_forget_folder): Same here.
+ (get_one_folder_offline): "
+
+2002-08-21 Not Zed <NotZed@Ximian.com>
+
+ * providers/imap/camel-imap-store.c
+ (parse_list_response_as_folder_info): Setup path properly, as
+ decoded path with / separator. Setup full_name as non-decoded raw
+ name. Keep url as decoded path but with server separator
+ ... (ick).
+ (create_folder): Dont call build_path anymore, get_folders() does
+ it for us.
+ (subscribe_folder): Build the path ourself.
+ (imap_folder_effectively_unsubscribed): Same here.
+ (get_subscribed_folders): list using %S not %F, we're using the
+ raw server provided name directly.
+ (subscribe_folder): As above, for SUBSCRIBE.
+ (unsubscribe_folder): Same here.
+ (delete_folder): Same.
+ (rename_folder_info): Same here for source name.
+ (rename_folder): And here?
+ (get_folders_online): Amd here.
+
+ * providers/imap/camel-imap-utils.c:
+ (imap_parse_list_response): Dont decode the mailbox.
+
+ * camel-utf8.[ch]: some new utf8 & utf7 utilities.
+
+ * providers/imap/camel-imap-utils.c (imap_mailbox_encode):
+ (imap_mailbox_decode): use camel_utf7/8* functions instead.
+ : Add config.h and alloca.h headers.
+
+>>>>>>> 1.1620.2.1
2002-08-20 Jeffrey Stedfast <fejj@ximian.com>
* providers/imap/camel-imap-store.c (imap_noop): Override the
diff --git a/camel/camel-private.h b/camel/camel-private.h
index e5a7894e6f..5165f31c8b 100644
--- a/camel/camel-private.h
+++ b/camel/camel-private.h
@@ -61,7 +61,7 @@ struct _CamelStorePrivate {
EMutex *folder_lock; /* for locking folder operations */
EMutex *cache_lock; /* for locking access to the cache */
#else
- gpointer dummy;
+ int dummy;
#endif
};
@@ -77,7 +77,7 @@ struct _CamelTransportPrivate {
#ifdef ENABLE_THREADS
GMutex *send_lock; /* for locking send operations */
#else
- gpointer dummy;
+ int dummy;
#endif
};
@@ -94,7 +94,7 @@ struct _CamelServicePrivate {
EMutex *connect_lock; /* for locking connection operations */
EMutex *connect_op_lock;/* for locking the connection_op */
#else
- gpointer dummy;
+ int dummy;
#endif
};
@@ -117,7 +117,7 @@ struct _CamelSessionPrivate {
GHashTable *thread_active;
EThread *thread_queue;
#else
- gpointer dummy;
+ int dummy;
#endif
};
@@ -169,7 +169,7 @@ struct _CamelStoreSummaryPrivate {
GMutex *alloc_lock; /* for setting up and using allocators */
GMutex *ref_lock; /* for reffing/unreffing messageinfo's ALWAYS obtain before summary_lock */
#else
- gpointer dummy;
+ int dummy;
#endif
};
@@ -205,7 +205,7 @@ struct _CamelDataWrapperPrivate {
#ifdef ENABLE_THREADS
pthread_mutex_t stream_lock;
#else
- gpointer dummy;
+ int dummy;
#endif
};
@@ -225,7 +225,7 @@ struct _CamelCertDBPrivate {
GMutex *alloc_lock; /* for setting up and using allocators */
GMutex *ref_lock; /* for reffing/unreffing certs */
#else
- gpointer dummy;
+ int dummy;
#endif
};
diff --git a/camel/camel-store-summary.c b/camel/camel-store-summary.c
index 8cd2bf37dd..b114ac78f4 100644
--- a/camel/camel-store-summary.c
+++ b/camel/camel-store-summary.c
@@ -22,6 +22,9 @@
#include <config.h>
#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
@@ -37,24 +40,29 @@
#include "e-util/e-memory.h"
#include "camel-private.h"
+#include "camel-url.h"
#define d(x)
#define io(x) /* io debug */
-#define CAMEL_STORE_SUMMARY_VERSION (13)
+/* possible versions, for versioning changes */
+#define CAMEL_STORE_SUMMARY_VERSION_0 (1)
+
+/* current version */
+#define CAMEL_STORE_SUMMARY_VERSION (1)
#define _PRIVATE(o) (((CamelStoreSummary *)(o))->priv)
static int summary_header_load(CamelStoreSummary *, FILE *);
static int summary_header_save(CamelStoreSummary *, FILE *);
-static CamelFolderInfo * folder_info_new(CamelStoreSummary *, const char *);
-static CamelFolderInfo * folder_info_load(CamelStoreSummary *, FILE *);
-static int folder_info_save(CamelStoreSummary *, FILE *, CamelFolderInfo *);
-static void folder_info_free(CamelStoreSummary *, CamelFolderInfo *);
+static CamelStoreInfo * store_info_new(CamelStoreSummary *, const char *);
+static CamelStoreInfo * store_info_load(CamelStoreSummary *, FILE *);
+static int store_info_save(CamelStoreSummary *, FILE *, CamelStoreInfo *);
+static void store_info_free(CamelStoreSummary *, CamelStoreInfo *);
-static const char *folder_info_string(CamelStoreSummary *, const CamelFolderInfo *, int);
-static void folder_info_set_string(CamelStoreSummary *, CamelFolderInfo *, int, const char *);
+static const char *store_info_string(CamelStoreSummary *, const CamelStoreInfo *, int);
+static void store_info_set_string(CamelStoreSummary *, CamelStoreInfo *, int, const char *);
static void camel_store_summary_class_init (CamelStoreSummaryClass *klass);
static void camel_store_summary_init (CamelStoreSummary *obj);
@@ -70,13 +78,13 @@ camel_store_summary_class_init (CamelStoreSummaryClass *klass)
klass->summary_header_load = summary_header_load;
klass->summary_header_save = summary_header_save;
- klass->folder_info_new = folder_info_new;
- klass->folder_info_load = folder_info_load;
- klass->folder_info_save = folder_info_save;
- klass->folder_info_free = folder_info_free;
+ klass->store_info_new = store_info_new;
+ klass->store_info_load = store_info_load;
+ klass->store_info_save = store_info_save;
+ klass->store_info_free = store_info_free;
- klass->folder_info_string = folder_info_string;
- klass->folder_info_set_string = folder_info_set_string;
+ klass->store_info_string = store_info_string;
+ klass->store_info_set_string = store_info_set_string;
}
static void
@@ -86,9 +94,9 @@ camel_store_summary_init (CamelStoreSummary *s)
p = _PRIVATE(s) = g_malloc0(sizeof(*p));
- s->folder_info_size = sizeof(CamelFolderInfo);
+ s->store_info_size = sizeof(CamelStoreInfo);
- s->folder_info_chunks = NULL;
+ s->store_info_chunks = NULL;
s->version = CAMEL_STORE_SUMMARY_VERSION;
s->flags = 0;
@@ -96,7 +104,7 @@ camel_store_summary_init (CamelStoreSummary *s)
s->time = 0;
s->folders = g_ptr_array_new();
- s->folders_full = g_hash_table_new(g_str_hash, g_str_equal);
+ s->folders_path = g_hash_table_new(g_str_hash, g_str_equal);
#ifdef ENABLE_THREADS
p->summary_lock = g_mutex_new();
@@ -116,12 +124,12 @@ camel_store_summary_finalise (CamelObject *obj)
camel_store_summary_clear(s);
g_ptr_array_free(s->folders, TRUE);
- g_hash_table_destroy(s->folders_full);
+ g_hash_table_destroy(s->folders_path);
g_free(s->summary_path);
- if (s->folder_info_chunks)
- e_memchunk_destroy(s->folder_info_chunks);
+ if (s->store_info_chunks)
+ e_memchunk_destroy(s->store_info_chunks);
#ifdef ENABLE_THREADS
g_mutex_free(p->summary_lock);
@@ -181,12 +189,13 @@ void camel_store_summary_set_filename(CamelStoreSummary *s, const char *name)
CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock);
}
-void camel_store_summary_set_uri_prefix(CamelStoreSummary *s, const char *prefix)
+void camel_store_summary_set_uri_base(CamelStoreSummary *s, CamelURL *base)
{
CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
- g_free(s->uri_prefix);
- s->uri_prefix = g_strdup(prefix);
+ if (s->uri_base)
+ camel_url_free(s->uri_base);
+ s->uri_base = camel_url_new_with_base(base, "");
CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock);
}
@@ -219,10 +228,10 @@ camel_store_summary_count(CamelStoreSummary *s)
* of range.
* It must be freed using camel_store_summary_info_free().
**/
-CamelFolderInfo *
+CamelStoreInfo *
camel_store_summary_index(CamelStoreSummary *s, int i)
{
- CamelFolderInfo *info = NULL;
+ CamelStoreInfo *info = NULL;
CAMEL_STORE_SUMMARY_LOCK(s, ref_lock);
CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
@@ -253,7 +262,7 @@ camel_store_summary_index(CamelStoreSummary *s, int i)
GPtrArray *
camel_store_summary_array(CamelStoreSummary *s)
{
- CamelFolderInfo *info;
+ CamelStoreInfo *info;
GPtrArray *res = g_ptr_array_new();
int i;
@@ -291,28 +300,28 @@ camel_store_summary_array_free(CamelStoreSummary *s, GPtrArray *array)
}
/**
- * camel_store_summary_full:
+ * camel_store_summary_path:
* @s:
- * @full:
+ * @path:
*
- * Retrieve a summary item by full name.
+ * Retrieve a summary item by path name.
*
* A referenced to the summary item is returned, which may be
* ref'd or free'd as appropriate.
*
- * Return value: The summary item, or NULL if the @full name
+ * Return value: The summary item, or NULL if the @path name
* is not available.
* It must be freed using camel_store_summary_info_free().
**/
-CamelFolderInfo *
-camel_store_summary_full(CamelStoreSummary *s, const char *full)
+CamelStoreInfo *
+camel_store_summary_path(CamelStoreSummary *s, const char *path)
{
- CamelFolderInfo *info;
+ CamelStoreInfo *info;
CAMEL_STORE_SUMMARY_LOCK(s, ref_lock);
CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
- info = g_hash_table_lookup(s->folders_full, full);
+ info = g_hash_table_lookup(s->folders_path, path);
CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock);
@@ -329,7 +338,7 @@ camel_store_summary_load(CamelStoreSummary *s)
{
FILE *in;
int i;
- CamelFolderInfo *mi;
+ CamelStoreInfo *mi;
g_assert(s->summary_path);
@@ -343,7 +352,7 @@ camel_store_summary_load(CamelStoreSummary *s)
/* now read in each message ... */
for (i=0;i<s->count;i++) {
- mi = ((CamelStoreSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->folder_info_load(s, in);
+ mi = ((CamelStoreSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->store_info_load(s, in);
if (mi == NULL)
goto error;
@@ -385,18 +394,25 @@ camel_store_summary_save(CamelStoreSummary *s)
int fd;
int i;
guint32 count;
- CamelFolderInfo *mi;
+ CamelStoreInfo *mi;
g_assert(s->summary_path);
- if ((s->flags & CAMEL_STORE_SUMMARY_DIRTY) == 0)
+ io(printf("** saving summary\n"));
+
+ if ((s->flags & CAMEL_STORE_SUMMARY_DIRTY) == 0) {
+ io(printf("** summary clean no save\n"));
return 0;
+ }
- fd = open(s->summary_path, O_RDWR|O_CREAT, 0600);
- if (fd == -1)
+ fd = open(s->summary_path, O_RDWR|O_CREAT|O_TRUNC, 0600);
+ if (fd == -1) {
+ io(printf("** open error: %s\n", strerror(errno)));
return -1;
+ }
out = fdopen(fd, "w");
if ( out == NULL ) {
+ printf("** fdopen error: %s\n", strerror(errno));
close(fd);
return -1;
}
@@ -418,7 +434,7 @@ camel_store_summary_save(CamelStoreSummary *s)
count = s->folders->len;
for (i=0;i<count;i++) {
mi = s->folders->pdata[i];
- ((CamelStoreSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->folder_info_save(s, out, mi);
+ ((CamelStoreSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->store_info_save(s, out, mi);
}
CAMEL_STORE_SUMMARY_UNLOCK(s, io_lock);
@@ -472,27 +488,27 @@ int camel_store_summary_header_load(CamelStoreSummary *s)
* info_new_*() functions, as it will be free'd based on the summary
* class. And MUST NOT be allocated directly using malloc.
**/
-void camel_store_summary_add(CamelStoreSummary *s, CamelFolderInfo *info)
+void camel_store_summary_add(CamelStoreSummary *s, CamelStoreInfo *info)
{
if (info == NULL)
return;
- if (camel_folder_info_full(s, info) == NULL) {
- g_warning("Trying to add a folder info with missing required full name\n");
+ if (camel_store_info_path(s, info) == NULL) {
+ g_warning("Trying to add a folder info with missing required path name\n");
return;
}
CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
g_ptr_array_add(s->folders, info);
- g_hash_table_insert(s->folders_full, (char *)camel_folder_info_full(s, info), info);
+ g_hash_table_insert(s->folders_path, (char *)camel_store_info_path(s, info), info);
s->flags |= CAMEL_STORE_SUMMARY_DIRTY;
CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock);
}
/**
- * camel_store_summary_add_from_full:
+ * camel_store_summary_add_from_path:
* @s:
* @h:
*
@@ -500,20 +516,20 @@ void camel_store_summary_add(CamelStoreSummary *s, CamelFolderInfo *info)
*
* Return value: The newly added record.
**/
-CamelFolderInfo *camel_store_summary_add_from_full(CamelStoreSummary *s, const char *full)
+CamelStoreInfo *camel_store_summary_add_from_path(CamelStoreSummary *s, const char *path)
{
- CamelFolderInfo *info;
+ CamelStoreInfo *info;
CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
- info = g_hash_table_lookup(s->folders_full, full);
+ info = g_hash_table_lookup(s->folders_path, path);
if (info != NULL) {
- g_warning("Trying to add folder '%s' to summary that already has it", full);
+ g_warning("Trying to add folder '%s' to summary that already has it", path);
info = NULL;
} else {
- info = camel_store_summary_info_new_from_full(s, full);
+ info = camel_store_summary_info_new_from_path(s, path);
g_ptr_array_add(s->folders, info);
- g_hash_table_insert(s->folders_full, (char *)camel_folder_info_full(s, info), info);
+ g_hash_table_insert(s->folders_path, (char *)camel_store_info_path(s, info), info);
s->flags |= CAMEL_STORE_SUMMARY_DIRTY;
}
@@ -523,18 +539,18 @@ CamelFolderInfo *camel_store_summary_add_from_full(CamelStoreSummary *s, const c
}
/**
- * camel_store_summary_info_new_from_full:
+ * camel_store_summary_info_new_from_path:
* @s:
* @h:
*
* Create a new info record from a name.
*
* Return value: Guess? This info record MUST be freed using
- * camel_store_summary_info_free(), camel_folder_info_free() will not work.
+ * camel_store_summary_info_free(), camel_store_info_free() will not work.
**/
-CamelFolderInfo *camel_store_summary_info_new_from_full(CamelStoreSummary *s, const char *f)
+CamelStoreInfo *camel_store_summary_info_new_from_path(CamelStoreSummary *s, const char *f)
{
- return ((CamelStoreSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s))) -> folder_info_new(s, f);
+ return ((CamelStoreSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s))) -> store_info_new(s, f);
}
/**
@@ -544,7 +560,7 @@ CamelFolderInfo *camel_store_summary_info_new_from_full(CamelStoreSummary *s, co
*
* Unref and potentially free the message info @mi, and all associated memory.
**/
-void camel_store_summary_info_free(CamelStoreSummary *s, CamelFolderInfo *mi)
+void camel_store_summary_info_free(CamelStoreSummary *s, CamelStoreInfo *mi)
{
g_assert(mi);
g_assert(s);
@@ -561,7 +577,7 @@ void camel_store_summary_info_free(CamelStoreSummary *s, CamelFolderInfo *mi)
CAMEL_STORE_SUMMARY_UNLOCK(s, ref_lock);
- ((CamelStoreSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->folder_info_free(s, mi);
+ ((CamelStoreSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->store_info_free(s, mi);
}
/**
@@ -571,7 +587,7 @@ void camel_store_summary_info_free(CamelStoreSummary *s, CamelFolderInfo *mi)
*
* Add an extra reference to @mi.
**/
-void camel_store_summary_info_ref(CamelStoreSummary *s, CamelFolderInfo *mi)
+void camel_store_summary_info_ref(CamelStoreSummary *s, CamelStoreInfo *mi)
{
g_assert(mi);
g_assert(s);
@@ -617,8 +633,8 @@ camel_store_summary_clear(CamelStoreSummary *s)
camel_store_summary_info_free(s, s->folders->pdata[i]);
g_ptr_array_set_size(s->folders, 0);
- g_hash_table_destroy(s->folders_full);
- s->folders_full = g_hash_table_new(g_str_hash, g_str_equal);
+ g_hash_table_destroy(s->folders_path);
+ s->folders_path = g_hash_table_new(g_str_hash, g_str_equal);
s->flags |= CAMEL_STORE_SUMMARY_DIRTY;
CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock);
}
@@ -630,10 +646,10 @@ camel_store_summary_clear(CamelStoreSummary *s)
*
* Remove a specific @info record from the summary.
**/
-void camel_store_summary_remove(CamelStoreSummary *s, CamelFolderInfo *info)
+void camel_store_summary_remove(CamelStoreSummary *s, CamelStoreInfo *info)
{
CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
- g_hash_table_remove(s->folders_full, camel_folder_info_full(s, info));
+ g_hash_table_remove(s->folders_path, camel_store_info_path(s, info));
g_ptr_array_remove(s->folders, info);
s->flags |= CAMEL_STORE_SUMMARY_DIRTY;
CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock);
@@ -644,18 +660,18 @@ void camel_store_summary_remove(CamelStoreSummary *s, CamelFolderInfo *info)
/**
* camel_store_summary_remove_uid:
* @s:
- * @full:
+ * @path:
*
- * Remove a specific info record from the summary, by @full.
+ * Remove a specific info record from the summary, by @path.
**/
-void camel_store_summary_remove_full(CamelStoreSummary *s, const char *full)
+void camel_store_summary_remove_path(CamelStoreSummary *s, const char *path)
{
- CamelFolderInfo *oldinfo;
- char *oldfull;
+ CamelStoreInfo *oldinfo;
+ char *oldpath;
CAMEL_STORE_SUMMARY_LOCK(s, ref_lock);
CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
- if (g_hash_table_lookup_extended(s->folders_full, full, (void *)&oldfull, (void *)&oldinfo)) {
+ if (g_hash_table_lookup_extended(s->folders_path, path, (void *)&oldpath, (void *)&oldinfo)) {
/* make sure it doesn't vanish while we're removing it */
oldinfo->refcount++;
CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock);
@@ -679,9 +695,9 @@ void camel_store_summary_remove_index(CamelStoreSummary *s, int index)
{
CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
if (index < s->folders->len) {
- CamelFolderInfo *info = s->folders->pdata[index];
+ CamelStoreInfo *info = s->folders->pdata[index];
- g_hash_table_remove(s->folders_full, camel_folder_info_full(s, info));
+ g_hash_table_remove(s->folders_path, camel_store_info_path(s, info));
g_ptr_array_remove_index(s->folders, index);
s->flags |= CAMEL_STORE_SUMMARY_DIRTY;
@@ -712,10 +728,13 @@ summary_header_load(CamelStoreSummary *s, FILE *in)
s->flags = flags;
s->time = time;
s->count = count;
- if (s->version != version) {
- g_warning("Summary header version mismatch");
+ s->version = version;
+
+ if (version < CAMEL_STORE_SUMMARY_VERSION_0) {
+ g_warning("Store summary header version too low");
return -1;
}
+
return 0;
}
@@ -726,7 +745,8 @@ summary_header_save(CamelStoreSummary *s, FILE *out)
io(printf("Savining header\n"));
- camel_file_util_encode_fixed_int32(out, s->version);
+ /* always write latest version */
+ camel_file_util_encode_fixed_int32(out, CAMEL_STORE_SUMMARY_VERSION);
camel_file_util_encode_fixed_int32(out, s->flags);
camel_file_util_encode_time_t(out, s->time);
return camel_file_util_encode_fixed_int32(out, camel_store_summary_count(s));
@@ -741,54 +761,54 @@ summary_header_save(CamelStoreSummary *s, FILE *out)
*
* Return value:
**/
-CamelFolderInfo *
+CamelStoreInfo *
camel_store_summary_info_new(CamelStoreSummary *s)
{
- CamelFolderInfo *mi;
+ CamelStoreInfo *mi;
CAMEL_STORE_SUMMARY_LOCK(s, alloc_lock);
- if (s->folder_info_chunks == NULL)
- s->folder_info_chunks = e_memchunk_new(32, s->folder_info_size);
- mi = e_memchunk_alloc0(s->folder_info_chunks);
+ if (s->store_info_chunks == NULL)
+ s->store_info_chunks = e_memchunk_new(32, s->store_info_size);
+ mi = e_memchunk_alloc0(s->store_info_chunks);
CAMEL_STORE_SUMMARY_UNLOCK(s, alloc_lock);
mi->refcount = 1;
return mi;
}
-const char *camel_folder_info_string(CamelStoreSummary *s, const CamelFolderInfo *mi, int type)
+const char *camel_store_info_string(CamelStoreSummary *s, const CamelStoreInfo *mi, int type)
{
- return ((CamelStoreSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->folder_info_string(s, mi, type);
+ return ((CamelStoreSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->store_info_string(s, mi, type);
}
-void camel_folder_info_set_string(CamelStoreSummary *s, CamelFolderInfo *mi, int type, const char *value)
+void camel_store_info_set_string(CamelStoreSummary *s, CamelStoreInfo *mi, int type, const char *value)
{
- return ((CamelStoreSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->folder_info_set_string(s, mi, type, value);
+ return ((CamelStoreSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->store_info_set_string(s, mi, type, value);
}
-static CamelFolderInfo *
-folder_info_new(CamelStoreSummary *s, const char *f)
+static CamelStoreInfo *
+store_info_new(CamelStoreSummary *s, const char *f)
{
- CamelFolderInfo *mi;
+ CamelStoreInfo *mi;
mi = camel_store_summary_info_new(s);
- mi->full = g_strdup(f);
- mi->unread = CAMEL_STORE_SUMMARY_UNKNOWN;
- mi->total = CAMEL_STORE_SUMMARY_UNKNOWN;
+ mi->path = g_strdup(f);
+ mi->unread = CAMEL_STORE_INFO_FOLDER_UNKNOWN;
+ mi->total = CAMEL_STORE_INFO_FOLDER_UNKNOWN;
return mi;
}
-static CamelFolderInfo *
-folder_info_load(CamelStoreSummary *s, FILE *in)
+static CamelStoreInfo *
+store_info_load(CamelStoreSummary *s, FILE *in)
{
- CamelFolderInfo *mi;
+ CamelStoreInfo *mi;
mi = camel_store_summary_info_new(s);
io(printf("Loading folder info\n"));
- camel_file_util_decode_string(in, &mi->full);
+ camel_file_util_decode_string(in, &mi->path);
camel_file_util_decode_uint32(in, &mi->flags);
camel_file_util_decode_uint32(in, &mi->unread);
camel_file_util_decode_uint32(in, &mi->total);
@@ -802,11 +822,11 @@ folder_info_load(CamelStoreSummary *s, FILE *in)
}
static int
-folder_info_save(CamelStoreSummary *s, FILE *out, CamelFolderInfo *mi)
+store_info_save(CamelStoreSummary *s, FILE *out, CamelStoreInfo *mi)
{
io(printf("Saving folder info\n"));
- camel_file_util_encode_string(out, camel_folder_info_full(s, mi));
+ camel_file_util_encode_string(out, camel_store_info_path(s, mi));
camel_file_util_encode_uint32(out, mi->flags);
camel_file_util_encode_uint32(out, mi->unread);
camel_file_util_encode_uint32(out, mi->total);
@@ -815,15 +835,15 @@ folder_info_save(CamelStoreSummary *s, FILE *out, CamelFolderInfo *mi)
}
static void
-folder_info_free(CamelStoreSummary *s, CamelFolderInfo *mi)
+store_info_free(CamelStoreSummary *s, CamelStoreInfo *mi)
{
- g_free(mi->full);
+ g_free(mi->path);
g_free(mi->uri);
- e_memchunk_free(s->folder_info_chunks, mi);
+ e_memchunk_free(s->store_info_chunks, mi);
}
static const char *
-folder_info_string(CamelStoreSummary *s, const CamelFolderInfo *mi, int type)
+store_info_string(CamelStoreSummary *s, const CamelStoreInfo *mi, int type)
{
const char *p;
@@ -832,26 +852,30 @@ folder_info_string(CamelStoreSummary *s, const CamelFolderInfo *mi, int type)
g_assert (mi != NULL);
switch (type) {
- case CAMEL_STORE_SUMMARY_FULL:
- return mi->full;
- case CAMEL_STORE_SUMMARY_NAME:
- p = strrchr(mi->full, '/');
+ case CAMEL_STORE_INFO_PATH:
+ return mi->path;
+ case CAMEL_STORE_INFO_NAME:
+ p = strrchr(mi->path, '/');
if (p)
return p;
else
- return mi->full;
- case CAMEL_STORE_SUMMARY_URI:
- if (mi->uri)
- return mi->uri;
- if (s->uri_prefix)
- return (((CamelFolderInfo *)mi)->uri = g_strdup_printf("%s%s", s->uri_prefix, mi->full));
+ return mi->path;
+ case CAMEL_STORE_INFO_URI:
+ if (mi->uri == NULL) {
+ CamelURL *uri;
+
+ uri = camel_url_new_with_base(s->uri_base, mi->path);
+ ((CamelStoreInfo *)mi)->uri = camel_url_to_string(uri, 0);
+ camel_url_free(uri);
+ }
+ return mi->uri;
}
return "";
}
static void
-folder_info_set_string (CamelStoreSummary *s, CamelFolderInfo *mi, int type, const char *str)
+store_info_set_string (CamelStoreSummary *s, CamelStoreInfo *mi, int type, const char *str)
{
const char *p;
char *v;
@@ -860,40 +884,36 @@ folder_info_set_string (CamelStoreSummary *s, CamelFolderInfo *mi, int type, con
g_assert (mi != NULL);
switch(type) {
- case CAMEL_STORE_SUMMARY_FULL:
- g_free(mi->full);
+ case CAMEL_STORE_INFO_PATH:
+ CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
+ g_hash_table_remove(s->folders_path, (char *)camel_store_info_path(s, mi));
+ g_free(mi->path);
g_free(mi->uri);
- mi->full = g_strdup(str);
+ mi->path = g_strdup(str);
+ g_hash_table_insert(s->folders_path, (char *)camel_store_info_path(s, mi), mi);
+ s->flags |= CAMEL_STORE_SUMMARY_DIRTY;
+ CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock);
break;
- case CAMEL_STORE_SUMMARY_NAME:
- p = strrchr(mi->full, '/');
+ case CAMEL_STORE_INFO_NAME:
+ CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
+ g_hash_table_remove(s->folders_path, (char *)camel_store_info_path(s, mi));
+ p = strrchr(mi->path, '/');
if (p) {
- len = p-mi->full+1;
+ len = p-mi->path+1;
v = g_malloc(len+strlen(str)+1);
- memcpy(v, mi->full, len);
+ memcpy(v, mi->path, len);
strcpy(v+len, str);
} else {
v = g_strdup(str);
}
- g_free(mi->full);
- mi->full = v;
+ g_free(mi->path);
+ mi->path = v;
+ g_hash_table_insert(s->folders_path, (char *)camel_store_info_path(s, mi), mi);
+ CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock);
break;
- case CAMEL_STORE_SUMMARY_URI:
- if (s->uri_prefix) {
- len = strlen(s->uri_prefix);
- if (len > strlen(str)
- || strncmp(s->uri_prefix, str, len) != 0) {
- g_warning("Trying to set folderinfo uri '%s' for summary with prefix '%s'",
- str, s->uri_prefix);
- return;
- }
- g_free(mi->full);
- g_free(mi->uri);
- mi->full = g_strdup(str + len);
- mi->uri = g_strdup(str);
- } else {
- g_warning("Trying to set folderinfo uri '%s' for summary with no uri prefix", str);
- }
+ case CAMEL_STORE_INFO_URI:
+ g_warning("Cannot set store info uri, aborting");
+ abort();
break;
}
}
diff --git a/camel/camel-store-summary.h b/camel/camel-store-summary.h
index a26d2fa84c..dbcd6119b7 100644
--- a/camel/camel-store-summary.h
+++ b/camel/camel-store-summary.h
@@ -29,44 +29,42 @@ extern "C" {
#endif /* __cplusplus */
#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
+
+#include <glib.h>
#include <camel/camel-mime-parser.h>
#include <camel/camel-object.h>
+#include <camel/camel-url.h>
#define CAMEL_STORE_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_store_summary_get_type (), CamelStoreSummary)
#define CAMEL_STORE_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_store_summary_get_type (), CamelStoreSummaryClass)
-#define CAMEL_IS_FOLDER_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_store_summary_get_type ())
+#define CAMEL_IS_STORE_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_store_summary_get_type ())
typedef struct _CamelStoreSummary CamelStoreSummary;
typedef struct _CamelStoreSummaryClass CamelStoreSummaryClass;
-typedef struct _CamelFolderInfo CamelFolderInfo;
+typedef struct _CamelStoreInfo CamelStoreInfo;
-enum _CamelFolderFlags {
- CAMEL_STORE_SUMMARY_FOLDER_NOSELECT,
- CAMEL_STORE_SUMMARY_FOLDER_READONLY,
- CAMEL_STORE_SUMMARY_FOLDER_SUBSCRIBED,
- CAMEL_STORE_SUMMARY_FOLDER_FLAGGED,
+enum _CamelStoreInfoFlags {
+ CAMEL_STORE_INFO_FOLDER_NOSELECT,
+ CAMEL_STORE_INFO_FOLDER_READONLY,
+ CAMEL_STORE_INFO_FOLDER_SUBSCRIBED,
+ CAMEL_STORE_INFO_FOLDER_FLAGGED,
};
-#define CAMEL_STORE_SUMMARY_UNKNOWN (~0)
+#define CAMEL_STORE_INFO_FOLDER_UNKNOWN (~0)
enum {
- CAMEL_STORE_SUMMARY_FULL = 0,
- CAMEL_STORE_SUMMARY_NAME,
- CAMEL_STORE_SUMMARY_URI,
- CAMEL_STORE_SUMMARY_LAST,
+ CAMEL_STORE_INFO_PATH = 0,
+ CAMEL_STORE_INFO_NAME,
+ CAMEL_STORE_INFO_URI,
+ CAMEL_STORE_INFO_LAST,
};
-struct _CamelFolderInfo {
+struct _CamelStoreInfo {
guint32 refcount;
char *uri;
- char *full;
+ char *path;
guint32 flags;
guint32 unread;
guint32 total;
@@ -74,6 +72,7 @@ struct _CamelFolderInfo {
enum _CamelStoreSummaryFlags {
CAMEL_STORE_SUMMARY_DIRTY = 1<<0,
+ CAMEL_STORE_SUMMARY_FRAGMENT = 1<<1, /* path name is stored in fragment rather than path */
};
struct _CamelStoreSummary {
@@ -82,22 +81,22 @@ struct _CamelStoreSummary {
struct _CamelStoreSummaryPrivate *priv;
/* header info */
- guint32 version; /* version of file required, should be set by implementors */
+ guint32 version; /* version of base part of file */
guint32 flags; /* flags */
guint32 count; /* how many were saved/loaded */
time_t time; /* timestamp for this summary (for implementors to use) */
+ struct _CamelURL *uri_base; /* url of base part of summary */
/* sizes of memory objects */
- guint32 folder_info_size;
+ guint32 store_info_size;
/* memory allocators (setup automatically) */
- struct _EMemChunk *folder_info_chunks;
+ struct _EMemChunk *store_info_chunks;
char *summary_path;
- char *uri_prefix;
- GPtrArray *folders; /* CamelFolderInfo's */
- GHashTable *folders_full; /* CamelFolderInfo's by full name */
+ GPtrArray *folders; /* CamelStoreInfo's */
+ GHashTable *folders_path; /* CamelStoreInfo's by path name */
};
struct _CamelStoreSummaryClass {
@@ -108,21 +107,21 @@ struct _CamelStoreSummaryClass {
int (*summary_header_save)(CamelStoreSummary *, FILE *);
/* create/save/load an individual message info */
- CamelFolderInfo * (*folder_info_new)(CamelStoreSummary *, const char *full);
- CamelFolderInfo * (*folder_info_load)(CamelStoreSummary *, FILE *);
- int (*folder_info_save)(CamelStoreSummary *, FILE *, CamelFolderInfo *);
- void (*folder_info_free)(CamelStoreSummary *, CamelFolderInfo *);
+ CamelStoreInfo * (*store_info_new)(CamelStoreSummary *, const char *path);
+ CamelStoreInfo * (*store_info_load)(CamelStoreSummary *, FILE *);
+ int (*store_info_save)(CamelStoreSummary *, FILE *, CamelStoreInfo *);
+ void (*store_info_free)(CamelStoreSummary *, CamelStoreInfo *);
/* virtualise access methods */
- const char *(*folder_info_string)(CamelStoreSummary *, const CamelFolderInfo *, int);
- void (*folder_info_set_string)(CamelStoreSummary *, CamelFolderInfo *, int, const char *);
+ const char *(*store_info_string)(CamelStoreSummary *, const CamelStoreInfo *, int);
+ void (*store_info_set_string)(CamelStoreSummary *, CamelStoreInfo *, int, const char *);
};
CamelType camel_store_summary_get_type (void);
CamelStoreSummary *camel_store_summary_new (void);
void camel_store_summary_set_filename(CamelStoreSummary *, const char *);
-void camel_store_summary_set_uri_prefix(CamelStoreSummary *, const char *);
+void camel_store_summary_set_uri_base(CamelStoreSummary *s, CamelURL *base);
/* load/save the summary in its entirety */
int camel_store_summary_load(CamelStoreSummary *);
@@ -135,21 +134,21 @@ int camel_store_summary_header_load(CamelStoreSummary *);
void camel_store_summary_touch(CamelStoreSummary *s);
/* add a new raw summary item */
-void camel_store_summary_add(CamelStoreSummary *, CamelFolderInfo *info);
+void camel_store_summary_add(CamelStoreSummary *, CamelStoreInfo *info);
/* build/add raw summary items */
-CamelFolderInfo *camel_store_summary_add_from_full(CamelStoreSummary *, const char *);
+CamelStoreInfo *camel_store_summary_add_from_path(CamelStoreSummary *, const char *);
/* Just build raw summary items */
-CamelFolderInfo *camel_store_summary_info_new(CamelStoreSummary *s);
-CamelFolderInfo *camel_store_summary_info_new_from_full(CamelStoreSummary *s, const char *);
+CamelStoreInfo *camel_store_summary_info_new(CamelStoreSummary *s);
+CamelStoreInfo *camel_store_summary_info_new_from_path(CamelStoreSummary *s, const char *);
-void camel_store_summary_info_ref(CamelStoreSummary *, CamelFolderInfo *);
-void camel_store_summary_info_free(CamelStoreSummary *, CamelFolderInfo *);
+void camel_store_summary_info_ref(CamelStoreSummary *, CamelStoreInfo *);
+void camel_store_summary_info_free(CamelStoreSummary *, CamelStoreInfo *);
/* removes a summary item */
-void camel_store_summary_remove(CamelStoreSummary *s, CamelFolderInfo *info);
-void camel_store_summary_remove_full(CamelStoreSummary *s, const char *full);
+void camel_store_summary_remove(CamelStoreSummary *s, CamelStoreInfo *info);
+void camel_store_summary_remove_path(CamelStoreSummary *s, const char *path);
void camel_store_summary_remove_index(CamelStoreSummary *s, int);
/* remove all items */
@@ -157,18 +156,18 @@ void camel_store_summary_clear(CamelStoreSummary *s);
/* lookup functions */
int camel_store_summary_count(CamelStoreSummary *);
-CamelFolderInfo *camel_store_summary_index(CamelStoreSummary *, int);
-CamelFolderInfo *camel_store_summary_full(CamelStoreSummary *, const char *uid);
+CamelStoreInfo *camel_store_summary_index(CamelStoreSummary *, int);
+CamelStoreInfo *camel_store_summary_path(CamelStoreSummary *, const char *uid);
GPtrArray *camel_store_summary_array(CamelStoreSummary *s);
void camel_store_summary_array_free(CamelStoreSummary *s, GPtrArray *array);
-const char *camel_folder_info_string(CamelStoreSummary *, const CamelFolderInfo *, int type);
-void camel_folder_info_set_string(CamelStoreSummary *, CamelFolderInfo *, int type, const char *value);
+const char *camel_store_info_string(CamelStoreSummary *, const CamelStoreInfo *, int type);
+void camel_store_info_set_string(CamelStoreSummary *, CamelStoreInfo *, int type, const char *value);
/* helper macro's */
-#define camel_folder_info_full(s, i) (camel_folder_info_string((CamelStoreSummary *)s, (const CamelFolderInfo *)i, CAMEL_STORE_SUMMARY_FULL))
-#define camel_folder_info_uri(s, i) (camel_folder_info_string((CamelStoreSummary *)s, (const CamelFolderInfo *)i, CAMEL_STORE_SUMMARY_URI))
-#define camel_folder_info_name(s, i) (camel_folder_info_string((CamelStoreSummary *)s, (const CamelFolderInfo *)i, CAMEL_STORE_SUMMARY_NAME))
+#define camel_store_info_path(s, i) (camel_store_info_string((CamelStoreSummary *)s, (const CamelStoreInfo *)i, CAMEL_STORE_INFO_PATH))
+#define camel_store_info_uri(s, i) (camel_store_info_string((CamelStoreSummary *)s, (const CamelStoreInfo *)i, CAMEL_STORE_INFO_URI))
+#define camel_store_info_name(s, i) (camel_store_info_string((CamelStoreSummary *)s, (const CamelStoreInfo *)i, CAMEL_STORE_INFO_NAME))
#ifdef __cplusplus
}
diff --git a/camel/camel-store.h b/camel/camel-store.h
index e054ab7224..29fb3cc95e 100644
--- a/camel/camel-store.h
+++ b/camel/camel-store.h
@@ -62,6 +62,8 @@ typedef struct _CamelFolderInfo {
#define CAMEL_FOLDER_NOINFERIORS (1<<1)
/* a folder which has children (not yet fully implemented) */
#define CAMEL_FOLDER_CHILDREN (1<<2)
+/* a folder which is subscribed */
+#define CAMEL_FOLDER_SUBSCRIBED (1<<3)
/* Structure of rename event's event_data */
typedef struct _CamelRenameInfo {
diff --git a/camel/camel-url.h b/camel/camel-url.h
index d60c9594c2..6bce26c8ad 100644
--- a/camel/camel-url.h
+++ b/camel/camel-url.h
@@ -35,7 +35,7 @@ extern "C" {
#pragma }
#endif /* __cplusplus */
-typedef struct {
+typedef struct _CamelURL {
char *protocol;
char *user;
char *authmech;
diff --git a/camel/providers/imap/Makefile.am b/camel/providers/imap/Makefile.am
index dbee888f39..469964a9a6 100644
--- a/camel/providers/imap/Makefile.am
+++ b/camel/providers/imap/Makefile.am
@@ -24,6 +24,7 @@ libcamelimap_la_SOURCES = \
camel-imap-provider.c \
camel-imap-search.c \
camel-imap-store.c \
+ camel-imap-store-summary.c \
camel-imap-summary.c \
camel-imap-utils.c \
camel-imap-wrapper.c
@@ -34,6 +35,7 @@ libcamelimapinclude_HEADERS = \
camel-imap-message-cache.h \
camel-imap-search.h \
camel-imap-store.h \
+ camel-imap-store-summary.h \
camel-imap-summary.h \
camel-imap-types.h \
camel-imap-utils.h \
diff --git a/camel/providers/imap/camel-imap-command.c b/camel/providers/imap/camel-imap-command.c
index ef7dd1ba35..e3581c80af 100644
--- a/camel/providers/imap/camel-imap-command.c
+++ b/camel/providers/imap/camel-imap-command.c
@@ -37,9 +37,11 @@
#include "camel-imap-utils.h"
#include "camel-imap-folder.h"
#include "camel-imap-store.h"
+#include "camel-imap-store-summary.h"
#include "camel-imap-private.h"
#include <camel/camel-exception.h>
#include <camel/camel-private.h>
+#include <camel/camel-utf8.h>
#define d(x) x
@@ -764,8 +766,10 @@ imap_command_strdup_vprintf (CamelImapStore *store, const char *fmt,
case 'S':
case 'F':
string = args->pdata[i++];
- if (*p == 'F')
- string = imap_mailbox_encode (string, strlen (string));
+ if (*p == 'F') {
+ char *s = camel_imap_store_summary_full_from_path(store->summary, string);
+ string = s?s:camel_utf8_utf7(string);
+ }
if (imap_is_atom (string)) {
outptr += sprintf (outptr, "%s", string);
diff --git a/camel/providers/imap/camel-imap-store-summary.c b/camel/providers/imap/camel-imap-store-summary.c
new file mode 100644
index 0000000000..4ba5bb9b68
--- /dev/null
+++ b/camel/providers/imap/camel-imap-store-summary.c
@@ -0,0 +1,519 @@
+/*
+ * Copyright (C) 2002 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "camel-imap-store-summary.h"
+
+#include "camel-file-utils.h"
+
+#include "hash-table-utils.h"
+#include "e-util/md5-utils.h"
+#include "e-util/e-memory.h"
+
+#include "camel-private.h"
+#include "camel-utf8.h"
+
+#define d(x)
+#define io(x) /* io debug */
+
+#define CAMEL_IMAP_STORE_SUMMARY_VERSION_0 (0)
+
+#define CAMEL_IMAP_STORE_SUMMARY_VERSION (0)
+
+#define _PRIVATE(o) (((CamelImapStoreSummary *)(o))->priv)
+
+static int summary_header_load(CamelStoreSummary *, FILE *);
+static int summary_header_save(CamelStoreSummary *, FILE *);
+
+/*static CamelStoreInfo * store_info_new(CamelStoreSummary *, const char *);*/
+static CamelStoreInfo * store_info_load(CamelStoreSummary *, FILE *);
+static int store_info_save(CamelStoreSummary *, FILE *, CamelStoreInfo *);
+static void store_info_free(CamelStoreSummary *, CamelStoreInfo *);
+
+static const char *store_info_string(CamelStoreSummary *, const CamelStoreInfo *, int);
+static void store_info_set_string(CamelStoreSummary *, CamelStoreInfo *, int, const char *);
+
+static void camel_imap_store_summary_class_init (CamelImapStoreSummaryClass *klass);
+static void camel_imap_store_summary_init (CamelImapStoreSummary *obj);
+static void camel_imap_store_summary_finalise (CamelObject *obj);
+
+static CamelStoreSummaryClass *camel_imap_store_summary_parent;
+
+static void
+camel_imap_store_summary_class_init (CamelImapStoreSummaryClass *klass)
+{
+ CamelStoreSummaryClass *ssklass = (CamelStoreSummaryClass *)klass;
+
+ ssklass->summary_header_load = summary_header_load;
+ ssklass->summary_header_save = summary_header_save;
+
+ /*ssklass->store_info_new = store_info_new;*/
+ ssklass->store_info_load = store_info_load;
+ ssklass->store_info_save = store_info_save;
+ ssklass->store_info_free = store_info_free;
+
+ ssklass->store_info_string = store_info_string;
+ ssklass->store_info_set_string = store_info_set_string;
+}
+
+static void
+camel_imap_store_summary_init (CamelImapStoreSummary *s)
+{
+ /*struct _CamelImapStoreSummaryPrivate *p;
+
+ p = _PRIVATE(s) = g_malloc0(sizeof(*p));*/
+
+ ((CamelStoreSummary *)s)->store_info_size = sizeof(CamelImapStoreInfo);
+ s->version = CAMEL_IMAP_STORE_SUMMARY_VERSION;
+}
+
+static void
+camel_imap_store_summary_finalise (CamelObject *obj)
+{
+ /*struct _CamelImapStoreSummaryPrivate *p;*/
+ /*CamelImapStoreSummary *s = (CamelImapStoreSummary *)obj;*/
+
+ /*p = _PRIVATE(obj);
+ g_free(p);*/
+}
+
+CamelType
+camel_imap_store_summary_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ camel_imap_store_summary_parent = (CamelStoreSummaryClass *)camel_store_summary_get_type();
+ type = camel_type_register((CamelType)camel_imap_store_summary_parent, "CamelImapStoreSummary",
+ sizeof (CamelImapStoreSummary),
+ sizeof (CamelImapStoreSummaryClass),
+ (CamelObjectClassInitFunc) camel_imap_store_summary_class_init,
+ NULL,
+ (CamelObjectInitFunc) camel_imap_store_summary_init,
+ (CamelObjectFinalizeFunc) camel_imap_store_summary_finalise);
+ }
+
+ return type;
+}
+
+/**
+ * camel_imap_store_summary_new:
+ *
+ * Create a new CamelImapStoreSummary object.
+ *
+ * Return value: A new CamelImapStoreSummary widget.
+ **/
+CamelImapStoreSummary *
+camel_imap_store_summary_new (void)
+{
+ CamelImapStoreSummary *new = CAMEL_IMAP_STORE_SUMMARY ( camel_object_new (camel_imap_store_summary_get_type ()));
+
+ return new;
+}
+
+/**
+ * camel_imap_store_summary_full_name:
+ * @s:
+ * @path:
+ *
+ * Retrieve a summary item by full name.
+ *
+ * A referenced to the summary item is returned, which may be
+ * ref'd or free'd as appropriate.
+ *
+ * Return value: The summary item, or NULL if the @full_name name
+ * is not available.
+ * It must be freed using camel_store_summary_info_free().
+ **/
+CamelImapStoreInfo *
+camel_imap_store_summary_full_name(CamelImapStoreSummary *s, const char *full_name)
+{
+ int count, i;
+ CamelImapStoreInfo *info;
+
+ count = camel_store_summary_count((CamelStoreSummary *)s);
+ for (i=0;i<count;i++) {
+ info = (CamelImapStoreInfo *)camel_store_summary_index((CamelStoreSummary *)s, i);
+ if (info) {
+ if (strcmp(info->full_name, full_name) == 0)
+ return info;
+ camel_store_summary_info_free((CamelStoreSummary *)s, (CamelStoreInfo *)info);
+ }
+ }
+
+ return NULL;
+}
+
+char *
+camel_imap_store_summary_full_to_path(CamelImapStoreSummary *s, const char *full_name, char dir_sep)
+{
+ char *path, *p;
+ int c;
+ const char *f;
+
+ if (dir_sep != '/') {
+ p = path = alloca(strlen(full_name)*3+1);
+ f = full_name;
+ while ( (c = *f++ & 0xff) ) {
+ if (c == dir_sep)
+ *p++ = '/';
+ else if (c == '/' || c == '%')
+ p += sprintf(p, "%%%02X", c);
+ else
+ *p++ = c;
+ }
+ *p = 0;
+ } else
+ path = (char *)full_name;
+
+ return camel_utf7_utf8(path);
+}
+
+static guint32 hexnib(guint32 c)
+{
+ if (c >= '0' && c <= '9')
+ return c-'0';
+ else if (c>='A' && c <= 'Z')
+ return c-'A'+10;
+ else
+ return 0;
+}
+
+char *
+camel_imap_store_summary_path_to_full(CamelImapStoreSummary *s, const char *path, char dir_sep)
+{
+ unsigned char *full, *f;
+ guint32 c, v = 0;
+ const char *p;
+ int state=0;
+ char *subpath, *last = NULL;
+ CamelStoreInfo *si;
+
+ /* check to see if we have a subpath of path already defined */
+ subpath = alloca(strlen(path)+1);
+ strcpy(subpath, path);
+ do {
+ si = camel_store_summary_path((CamelStoreSummary *)s, subpath);
+ if (si == NULL) {
+ last = strrchr(subpath, '/');
+ if (last)
+ *last = 0;
+ }
+ } while (si == NULL && last);
+
+ /* path is already present, use the raw version we have */
+ if (si && strlen(subpath) == strlen(path)) {
+ f = g_strdup(camel_imap_store_info_full_name(s, si));
+ camel_store_summary_info_free((CamelStoreSummary *)s, si);
+ return f;
+ }
+
+ f = full = alloca(strlen(path)*2+1);
+ if (si)
+ p = path + strlen(subpath);
+ else
+ p = path;
+ while ( (c = camel_utf8_getc((const unsigned char **)&p)) ) {
+ switch(state) {
+ case 0:
+ if (c == '%')
+ state = 1;
+ else {
+ if (c == '/')
+ c = dir_sep;
+ camel_utf8_putc(&f, c);
+ }
+ break;
+ case 1:
+ state = 2;
+ v = hexnib(c)<<4;
+ break;
+ case 2:
+ state = 0;
+ v |= hexnib(c);
+ camel_utf8_putc(&f, v);
+ break;
+ }
+ }
+ camel_utf8_putc(&f, c);
+
+ /* merge old path part if required */
+ f = camel_utf8_utf7(full);
+ if (si) {
+ full = g_strdup_printf("%s%s", camel_imap_store_info_full_name(s, si), f);
+ g_free(f);
+ camel_store_summary_info_free((CamelStoreSummary *)s, si);
+ f = full;
+ }
+
+ return f;
+}
+
+CamelImapStoreInfo *
+camel_imap_store_summary_add_from_full(CamelImapStoreSummary *s, const char *full_name, char dir_sep)
+{
+ CamelImapStoreInfo *info;
+ char *pathu8;
+
+ d(printf("adding full name '%s' '%c'\n", full_name, dir_sep));
+
+ info = camel_imap_store_summary_full_name(s, full_name);
+ if (info) {
+ camel_store_summary_info_free((CamelStoreSummary *)s, (CamelStoreInfo *)info);
+ d(printf(" already there\n"));
+ return info;
+ }
+
+ pathu8 = camel_imap_store_summary_full_to_path(s, full_name, dir_sep);
+
+ info = (CamelImapStoreInfo *)camel_store_summary_add_from_path((CamelStoreSummary *)s, pathu8);
+ if (info) {
+ d(printf(" '%s' -> '%s'\n", pathu8, full_name));
+ camel_store_info_set_string((CamelStoreSummary *)s, (CamelStoreInfo *)info, CAMEL_IMAP_STORE_INFO_FULL_NAME, full_name);
+ } else
+ d(printf(" failed\n"));
+
+ return info;
+}
+
+/* should this be const? */
+char *
+camel_imap_store_summary_full_from_path(CamelImapStoreSummary *s, const char *path)
+{
+ CamelImapStoreInfo *si;
+
+ si = (CamelImapStoreInfo *)camel_store_summary_path((CamelStoreSummary *)s, path);
+
+ d(printf("looking up path %s -> %s\n", path, si?si->full_name:"not found"));
+
+ if (si)
+ return g_strdup(si->full_name);
+
+ return NULL;
+}
+
+/* TODO: this api needs some more work */
+CamelImapStoreNamespace *camel_imap_store_summary_namespace_new(CamelImapStoreSummary *s, const char *full_name, char dir_sep)
+{
+ CamelImapStoreNamespace *ns;
+
+ ns = g_malloc0(sizeof(*ns));
+ ns->full_name = g_strdup(full_name);
+ ns->sep = dir_sep;
+ ns->path = camel_imap_store_summary_full_to_path(s, full_name, dir_sep);
+
+ return ns;
+}
+
+void camel_imap_store_summary_namespace_set(CamelImapStoreSummary *s, CamelImapStoreNamespace *ns)
+{
+ static void namespace_clear(CamelStoreSummary *s);
+
+ namespace_clear((CamelStoreSummary *)s);
+ s->namespace = ns;
+ camel_store_summary_touch((CamelStoreSummary *)s);
+}
+
+static void
+namespace_free(CamelStoreSummary *s, CamelImapStoreNamespace *ns)
+{
+ g_free(ns->path);
+ g_free(ns->full_name);
+ g_free(ns);
+}
+
+static void
+namespace_clear(CamelStoreSummary *s)
+{
+ CamelImapStoreSummary *is = (CamelImapStoreSummary *)s;
+
+ if (is->namespace)
+ namespace_free(s, is->namespace);
+ is->namespace = NULL;
+}
+
+static CamelImapStoreNamespace *
+namespace_load(CamelStoreSummary *s, FILE *in)
+{
+ CamelImapStoreNamespace *ns;
+ guint32 sep = '/';
+
+ ns = g_malloc0(sizeof(*ns));
+ if (camel_file_util_decode_string(in, &ns->path) == -1
+ || camel_file_util_decode_string(in, &ns->full_name) == -1
+ || camel_file_util_decode_uint32(in, &sep) == -1) {
+ namespace_free(s, ns);
+ ns = NULL;
+ } else {
+ ns->sep = sep;
+ }
+
+ return ns;
+}
+
+static int
+namespace_save(CamelStoreSummary *s, FILE *in, CamelImapStoreNamespace *ns)
+{
+ if (camel_file_util_encode_string(in, ns->path) == -1
+ || camel_file_util_encode_string(in, ns->full_name) == -1
+ || camel_file_util_encode_uint32(in, (guint32)ns->sep) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int
+summary_header_load(CamelStoreSummary *s, FILE *in)
+{
+ CamelImapStoreSummary *is = (CamelImapStoreSummary *)s;
+ gint32 version, capabilities, count;
+
+ namespace_clear(s);
+
+ if (camel_imap_store_summary_parent->summary_header_load((CamelStoreSummary *)s, in) == -1
+ || camel_file_util_decode_fixed_int32(in, &version) == -1)
+ return -1;
+
+ is->version = version;
+
+ if (version < CAMEL_IMAP_STORE_SUMMARY_VERSION_0) {
+ g_warning("Store summary header version too low");
+ return -1;
+ }
+
+ /* note file format can be expanded to contain more namespaces, but only 1 at the moment */
+ if (camel_file_util_decode_fixed_int32(in, &capabilities) == -1
+ || camel_file_util_decode_fixed_int32(in, &count) == -1
+ || count > 1)
+ return -1;
+
+ is->capabilities = capabilities;
+ if (count == 1) {
+ if ((is->namespace = namespace_load(s, in)) == NULL)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+summary_header_save(CamelStoreSummary *s, FILE *out)
+{
+ CamelImapStoreSummary *is = (CamelImapStoreSummary *)s;
+ guint32 count;
+
+ count = is->namespace?1:0;
+
+ /* always write as latest version */
+ if (camel_imap_store_summary_parent->summary_header_save((CamelStoreSummary *)s, out) == -1
+ || camel_file_util_encode_fixed_int32(out, CAMEL_IMAP_STORE_SUMMARY_VERSION) == -1
+ || camel_file_util_encode_fixed_int32(out, is->capabilities) == -1
+ || camel_file_util_encode_fixed_int32(out, count) == -1)
+ return -1;
+
+ if (is->namespace && namespace_save(s, out, is->namespace) == -1)
+ return -1;
+
+ return 0;
+}
+
+static CamelStoreInfo *
+store_info_load(CamelStoreSummary *s, FILE *in)
+{
+ CamelImapStoreInfo *mi;
+
+ mi = (CamelImapStoreInfo *)camel_imap_store_summary_parent->store_info_load(s, in);
+ if (mi) {
+ if (camel_file_util_decode_string(in, &mi->full_name) == -1) {
+ camel_store_summary_info_free(s, (CamelStoreInfo *)mi);
+ mi = NULL;
+ }
+ }
+
+ return (CamelStoreInfo *)mi;
+}
+
+static int
+store_info_save(CamelStoreSummary *s, FILE *out, CamelStoreInfo *mi)
+{
+ CamelImapStoreInfo *isi = (CamelImapStoreInfo *)mi;
+
+ if (camel_imap_store_summary_parent->store_info_save(s, out, mi) == -1
+ || camel_file_util_encode_string(out, isi->full_name) == -1)
+ return -1;
+
+ return 0;
+}
+
+static void
+store_info_free(CamelStoreSummary *s, CamelStoreInfo *mi)
+{
+ CamelImapStoreInfo *isi = (CamelImapStoreInfo *)mi;
+
+ g_free(isi->full_name);
+ camel_imap_store_summary_parent->store_info_free(s, mi);
+}
+
+static const char *
+store_info_string(CamelStoreSummary *s, const CamelStoreInfo *mi, int type)
+{
+ CamelImapStoreInfo *isi = (CamelImapStoreInfo *)mi;
+
+ /* FIXME: Locks? */
+
+ g_assert (mi != NULL);
+
+ switch (type) {
+ case CAMEL_IMAP_STORE_INFO_FULL_NAME:
+ return isi->full_name;
+ default:
+ return camel_imap_store_summary_parent->store_info_string(s, mi, type);
+ }
+}
+
+static void
+store_info_set_string(CamelStoreSummary *s, CamelStoreInfo *mi, int type, const char *str)
+{
+ CamelImapStoreInfo *isi = (CamelImapStoreInfo *)mi;
+
+ g_assert(mi != NULL);
+
+ switch(type) {
+ case CAMEL_IMAP_STORE_INFO_FULL_NAME:
+ d(printf("Set full name %s -> %s\n", isi->full_name, str));
+ CAMEL_STORE_SUMMARY_LOCK(s, summary_lock);
+ g_free(isi->full_name);
+ isi->full_name = g_strdup(str);
+ CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock);
+ break;
+ default:
+ camel_imap_store_summary_parent->store_info_set_string(s, mi, type, str);
+ break;
+ }
+}
diff --git a/camel/providers/imap/camel-imap-store-summary.h b/camel/providers/imap/camel-imap-store-summary.h
new file mode 100644
index 0000000000..013283b5c1
--- /dev/null
+++ b/camel/providers/imap/camel-imap-store-summary.h
@@ -0,0 +1,100 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 Ximian Inc.
+ *
+ * Authors: Michael Zucchi <notzed@ximian.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef _CAMEL_IMAP_STORE_SUMMARY_H
+#define _CAMEL_IMAP_STORE_SUMMARY_H
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#include <camel/camel-object.h>
+#include <camel/camel-store-summary.h>
+
+#define CAMEL_IMAP_STORE_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_imap_store_summary_get_type (), CamelImapStoreSummary)
+#define CAMEL_IMAP_STORE_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_imap_store_summary_get_type (), CamelImapStoreSummaryClass)
+#define CAMEL_IS_IMAP_STORE_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_imap_store_summary_get_type ())
+
+typedef struct _CamelImapStoreSummary CamelImapStoreSummary;
+typedef struct _CamelImapStoreSummaryClass CamelImapStoreSummaryClass;
+
+typedef struct _CamelImapStoreInfo CamelImapStoreInfo;
+
+enum {
+ CAMEL_IMAP_STORE_INFO_FULL_NAME = CAMEL_STORE_INFO_LAST,
+ CAMEL_IMAP_STORE_INFO_LAST,
+};
+
+struct _CamelImapStoreInfo {
+ CamelStoreInfo info;
+ char *full_name;
+};
+
+typedef struct _CamelImapStoreNamespace CamelImapStoreNamespace;
+
+struct _CamelImapStoreNamespace {
+ char *path; /* display path */
+ char *full_name; /* real name */
+ char sep; /* directory separator */
+};
+
+struct _CamelImapStoreSummary {
+ CamelStoreSummary summary;
+
+ struct _CamelImapStoreSummaryPrivate *priv;
+
+ /* header info */
+ guint32 version; /* version of base part of file */
+ guint32 capabilities;
+ CamelImapStoreNamespace *namespace; /* eventually to be a list */
+};
+
+struct _CamelImapStoreSummaryClass {
+ CamelStoreSummaryClass summary_class;
+};
+
+CamelType camel_imap_store_summary_get_type (void);
+CamelImapStoreSummary *camel_imap_store_summary_new (void);
+
+/* TODO: this api needs some more work */
+CamelImapStoreNamespace *camel_imap_store_summary_namespace_new(CamelImapStoreSummary *s, const char *full_name, char dir_sep);
+void camel_imap_store_summary_namespace_set(CamelImapStoreSummary *s, CamelImapStoreNamespace *ns);
+
+/* converts to/from utf8 canonical nasmes */
+char *camel_imap_store_summary_full_to_path(CamelImapStoreSummary *s, const char *full_name, char dir_sep);
+char *camel_imap_store_summary_path_to_full(CamelImapStoreSummary *s, const char *path, char dir_sep);
+
+CamelImapStoreInfo *camel_imap_store_summary_full_name(CamelImapStoreSummary *s, const char *full_name);
+CamelImapStoreInfo *camel_imap_store_summary_add_from_full(CamelImapStoreSummary *s, const char *full_name, char dir_sep);
+
+/* a convenience lookup function. always use this if path known */
+char *camel_imap_store_summary_full_from_path(CamelImapStoreSummary *s, const char *path);
+
+/* helper macro's */
+#define camel_imap_store_info_full_name(s, i) (camel_store_info_string((CamelStoreSummary *)s, (const CamelStoreInfo *)i, CAMEL_IMAP_STORE_INFO_FULL_NAME))
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* ! _CAMEL_IMAP_STORE_SUMMARY_H */
diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c
index c56976466d..7eb3c3accb 100644
--- a/camel/providers/imap/camel-imap-store.c
+++ b/camel/providers/imap/camel-imap-store.c
@@ -38,6 +38,7 @@
#include "e-util/e-path.h"
#include "camel-imap-store.h"
+#include "camel-imap-store-summary.h"
#include "camel-imap-folder.h"
#include "camel-imap-utils.h"
#include "camel-imap-command.h"
@@ -55,6 +56,7 @@
#include "camel-tcp-stream-ssl.h"
#include "camel-url.h"
#include "camel-sasl.h"
+#include "camel-utf8.h"
#include "string-utils.h"
#include "camel-imap-private.h"
@@ -114,14 +116,10 @@ static void get_folders_online (CamelImapStore *imap_store, const char *pattern,
GPtrArray *folders, gboolean lsub, CamelException *ex);
-static void imap_folder_effectively_unsubscribed(CamelImapStore *imap_store,
- const char *folder_name, CamelException *ex);
-
-static gboolean imap_check_folder_still_extant (CamelImapStore *imap_store, const char *full_name,
- CamelException *ex);
-
-static void imap_forget_folder(CamelImapStore *imap_store, const char *folder_name,
- CamelException *ex);
+static void imap_folder_effectively_unsubscribed(CamelImapStore *imap_store, const char *folder_name, CamelException *ex);
+static gboolean imap_check_folder_still_extant (CamelImapStore *imap_store, const char *full_name, CamelException *ex);
+static void imap_forget_folder(CamelImapStore *imap_store, const char *folder_name, CamelException *ex);
+static void imap_set_server_level (CamelImapStore *store);
static void
camel_imap_store_class_init (CamelImapStoreClass *camel_imap_store_class)
@@ -180,6 +178,11 @@ static void
camel_imap_store_finalize (CamelObject *object)
{
CamelImapStore *imap_store = CAMEL_IMAP_STORE (object);
+
+ if (imap_store->summary) {
+ camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
+ camel_object_unref(imap_store->summary);
+ }
if (imap_store->istream)
camel_object_unref (CAMEL_OBJECT (imap_store->istream));
@@ -254,7 +257,6 @@ camel_imap_store_init (gpointer object, gpointer klass)
imap_store->dir_sep = '\0';
imap_store->current_folder = NULL;
imap_store->connected = FALSE;
- imap_store->subscribed_folders = NULL;
imap_store->tag_prefix = imap_tag_prefix++;
if (imap_tag_prefix > 'Z')
@@ -294,6 +296,8 @@ construct (CamelService *service, CamelSession *session,
{
CamelImapStore *imap_store = CAMEL_IMAP_STORE (service);
CamelStore *store = CAMEL_STORE (service);
+ char *tmp;
+ CamelURL *summary_url;
CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
if (camel_exception_is_set (ex))
@@ -313,6 +317,7 @@ construct (CamelService *service, CamelSession *session,
store->flags |= CAMEL_STORE_SUBSCRIPTIONS;
if (camel_url_get_param (url, "namespace")) {
imap_store->parameters |= IMAP_PARAM_OVERRIDE_NAMESPACE;
+ g_free(imap_store->namespace);
imap_store->namespace = g_strdup (camel_url_get_param (url, "namespace"));
}
if (camel_url_get_param (url, "check_all"))
@@ -321,6 +326,32 @@ construct (CamelService *service, CamelSession *session,
imap_store->parameters |= IMAP_PARAM_FILTER_INBOX;
store->flags |= CAMEL_STORE_FILTER_INBOX;
}
+
+ /* setup/load the store summary */
+ tmp = alloca(strlen(imap_store->storage_path)+32);
+ sprintf(tmp, "%s/.ev-store-summary", imap_store->storage_path);
+ imap_store->summary = camel_imap_store_summary_new();
+ camel_store_summary_set_filename((CamelStoreSummary *)imap_store->summary, tmp);
+ summary_url = camel_url_new(imap_store->base_url, NULL);
+ camel_store_summary_set_uri_base((CamelStoreSummary *)imap_store->summary, summary_url);
+ camel_url_free(summary_url);
+ if (camel_store_summary_load((CamelStoreSummary *)imap_store->summary) == 0) {
+ CamelImapStoreSummary *is = imap_store->summary;
+
+ if (is->namespace) {
+ /* if namespace has changed, clear folder list */
+ if (imap_store->namespace && strcmp(imap_store->namespace, is->namespace->full_name) != 0) {
+ camel_store_summary_clear((CamelStoreSummary *)is);
+ } else {
+ imap_store->namespace = g_strdup(is->namespace->full_name);
+ imap_store->dir_sep = is->namespace->sep;
+ store->dir_sep = is->namespace->sep;
+ }
+ }
+
+ imap_store->capabilities = is->capabilities;
+ imap_set_server_level(imap_store);
+ }
}
static int
@@ -502,6 +533,12 @@ imap_get_capability (CamelService *service, CamelException *ex)
g_free (result);
imap_set_server_level (store);
+
+ if (store->summary->capabilities != store->capabilities) {
+ store->summary->capabilities = store->capabilities;
+ camel_store_summary_touch((CamelStoreSummary *)store->summary);
+ camel_store_summary_save((CamelStoreSummary *)store->summary);
+ }
return TRUE;
}
@@ -761,40 +798,62 @@ query_auth_types (CamelService *service, CamelException *ex)
return g_list_prepend (sasl_types, &camel_imap_password_authtype);
}
+/* folder_name is path name */
+static CamelFolderInfo *
+imap_build_folder_info(CamelImapStore *imap_store, const char *folder_name)
+{
+ CamelURL *url;
+ const char *name;
+ CamelFolderInfo *fi;
+
+ fi = g_malloc0(sizeof(*fi));
+
+ fi->full_name = g_strdup(folder_name);
+ fi->unread_message_count = 0;
+
+ url = camel_url_new (imap_store->base_url, NULL);
+ g_free (url->path);
+ url->path = g_strdup_printf ("/%s", folder_name);
+ fi->url = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
+ camel_url_free(url);
+ fi->path = g_strdup_printf("/%s", folder_name);
+ name = strrchr (fi->path, '/');
+ if (name)
+ name++;
+ else
+ name = fi->path;
+
+ fi->name = g_strdup (name);
+
+ return fi;
+}
+
static void
imap_folder_effectively_unsubscribed(CamelImapStore *imap_store,
const char *folder_name, CamelException *ex)
{
- gpointer key, value;
CamelFolderInfo *fi;
- const char *name;
-
- if (g_hash_table_lookup_extended (imap_store->subscribed_folders,
- folder_name, &key, &value)) {
- g_hash_table_remove (imap_store->subscribed_folders, key);
- g_free (key);
+ CamelStoreInfo *si;
+
+ si = camel_store_summary_path((CamelStoreSummary *)imap_store->summary, folder_name);
+ if (si) {
+ if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
+ si->flags &= ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+ camel_store_summary_touch((CamelStoreSummary *)imap_store->summary);
+ camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
+ }
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
}
-
+
if (imap_store->renaming) {
/* we don't need to emit a "folder_unsubscribed" signal
if we are in the process of renaming folders, so we
are done here... */
return;
+
}
-
- name = strrchr (folder_name, imap_store->dir_sep);
- if (name)
- name++;
- else
- name = folder_name;
-
- fi = g_new0 (CamelFolderInfo, 1);
- fi->full_name = g_strdup (folder_name);
- fi->name = g_strdup (name);
- fi->url = g_strdup_printf ("%s/%s", imap_store->base_url, folder_name);
- fi->unread_message_count = -1;
- camel_folder_info_build_path (fi, imap_store->dir_sep);
-
+
+ fi = imap_build_folder_info(imap_store, folder_name);
camel_object_trigger_event (CAMEL_OBJECT (imap_store), "folder_unsubscribed", fi);
camel_folder_info_free (fi);
}
@@ -809,7 +868,7 @@ imap_forget_folder (CamelImapStore *imap_store, const char *folder_name, CamelEx
char *folder_dir, *storage_path;
CamelFolderInfo *fi;
const char *name;
-
+
name = strrchr (folder_name, imap_store->dir_sep);
if (name)
name++;
@@ -850,13 +909,11 @@ imap_forget_folder (CamelImapStore *imap_store, const char *folder_name, CamelEx
g_free (folder_dir);
event:
-
- fi = g_new0 (CamelFolderInfo, 1);
- fi->full_name = g_strdup (folder_name);
- fi->name = g_strdup (name);
- fi->url = g_strdup_printf ("%s/%s", imap_store->base_url, folder_name);
- fi->unread_message_count = -1;
- camel_folder_info_build_path (fi, imap_store->dir_sep);
+
+ camel_store_summary_remove_path((CamelStoreSummary *)imap_store->summary, folder_name);
+ camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
+
+ fi = imap_build_folder_info(imap_store, folder_name);
camel_object_trigger_event (CAMEL_OBJECT (imap_store), "folder_deleted", fi);
camel_folder_info_free (fi);
}
@@ -1108,19 +1165,12 @@ imap_auth_loop (CamelService *service, CamelException *ex)
return TRUE;
}
-#define IMAP_STOREINFO_VERSION 2
-
static gboolean
can_work_offline (CamelDiscoStore *disco_store)
{
CamelImapStore *store = CAMEL_IMAP_STORE (disco_store);
- char *path;
- gboolean can;
- path = g_strdup_printf ("%s/storeinfo", store->storage_path);
- can = access (path, F_OK) == 0;
- g_free (path);
- return can;
+ return camel_store_summary_count((CamelStoreSummary *)store->summary) != 0;
}
static gboolean
@@ -1131,10 +1181,10 @@ imap_connect_online (CamelService *service, CamelException *ex)
CamelImapResponse *response;
struct _namespaces *namespaces;
char *result, *name, *path;
- FILE *storeinfo;
- int i, flags;
+ int i;
size_t len;
-
+ CamelImapStoreNamespace *ns;
+
CAMEL_SERVICE_LOCK (store, connect_lock);
if (!connect_to_server_wrapper (service, ex) ||
!imap_auth_loop (service, ex)) {
@@ -1143,16 +1193,6 @@ imap_connect_online (CamelService *service, CamelException *ex)
return FALSE;
}
- path = g_strdup_printf ("%s/storeinfo", store->storage_path);
- storeinfo = fopen (path, "w");
- if (!storeinfo)
- g_warning ("Could not open storeinfo %s", path);
- g_free (path);
-
- /* Write header and capabilities */
- camel_file_util_encode_uint32 (storeinfo, IMAP_STOREINFO_VERSION);
- camel_file_util_encode_uint32 (storeinfo, store->capabilities);
-
/* Get namespace and hierarchy separator */
if ((store->capabilities & IMAP_CAPABILITY_NAMESPACE) &&
!(store->parameters & IMAP_PARAM_OVERRIDE_NAMESPACE)) {
@@ -1189,7 +1229,7 @@ imap_connect_online (CamelService *service, CamelException *ex)
if (!store->namespace)
store->namespace = g_strdup ("");
-
+
if (!store->dir_sep) {
if (store->server_level >= IMAP_LEVEL_IMAP4REV1) {
/* This idiom means "tell me the hierarchy separator
@@ -1230,32 +1270,24 @@ imap_connect_online (CamelService *service, CamelException *ex)
g_free (store->namespace);
store->namespace = tmp;
}
-
- /* Write namespace/separator out */
- camel_file_util_encode_string (storeinfo, store->namespace);
- camel_file_util_encode_uint32 (storeinfo, store->dir_sep);
+
+ ns = camel_imap_store_summary_namespace_new(store->summary, store->namespace, store->dir_sep);
+ camel_imap_store_summary_namespace_set(store->summary, ns);
if (CAMEL_STORE (store)->flags & CAMEL_STORE_SUBSCRIPTIONS) {
- /* Get subscribed folders */
- response = camel_imap_command (store, NULL, ex, "LSUB \"\" \"*\"");
- if (!response)
- goto done;
- 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 (store, result, &flags, NULL, &name))
- continue;
- if (flags & (CAMEL_IMAP_FOLDER_MARKED | CAMEL_IMAP_FOLDER_UNMARKED))
+ GPtrArray *folders;
+
+ /* this pre-fills the summary, and checks that lsub is useful */
+ folders = g_ptr_array_new();
+ get_folders_online(store, "*", folders, TRUE, ex);
+ for (i=0;i<folders->len;i++) {
+ CamelFolderInfo *fi = folders->pdata[i];
+
+ if (fi->flags & (CAMEL_IMAP_FOLDER_MARKED | CAMEL_IMAP_FOLDER_UNMARKED))
store->capabilities |= IMAP_CAPABILITY_useful_lsub;
- if (flags & CAMEL_FOLDER_NOSELECT) {
- g_free (name);
- continue;
- }
- g_hash_table_insert (store->subscribed_folders, name,
- GINT_TO_POINTER (1));
- camel_file_util_encode_string (storeinfo, result);
+ camel_folder_info_free(fi);
}
- camel_imap_response_free (store, response);
+ g_ptr_array_free(folders, TRUE);
}
path = g_strdup_printf ("%s/journal", store->storage_path);
@@ -1263,7 +1295,9 @@ imap_connect_online (CamelService *service, CamelException *ex)
g_free (path);
done:
- fclose (storeinfo);
+ /* save any changes we had */
+ camel_store_summary_save((CamelStoreSummary *)store->summary);
+
CAMEL_SERVICE_UNLOCK (store, connect_lock);
if (camel_exception_is_set (ex))
@@ -1279,9 +1313,7 @@ imap_connect_offline (CamelService *service, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (service);
CamelDiscoStore *disco_store = CAMEL_DISCO_STORE (service);
- char *buf, *name, *path;
- FILE *storeinfo;
- guint32 tmp;
+ char *path;
path = g_strdup_printf ("%s/journal", store->storage_path);
disco_store->diary = camel_disco_diary_new (disco_store, path, ex);
@@ -1289,48 +1321,6 @@ imap_connect_offline (CamelService *service, CamelException *ex)
if (!disco_store->diary)
return FALSE;
- path = g_strdup_printf ("%s/storeinfo", store->storage_path);
- storeinfo = fopen (path, "r");
- g_free (path);
- tmp = 0;
- if (storeinfo)
- camel_file_util_decode_uint32 (storeinfo, &tmp);
- if (tmp != IMAP_STOREINFO_VERSION) {
- if (storeinfo)
- fclose (storeinfo);
-
- /* We know we're offline, so this will have to set @ex
- * and return FALSE.
- */
- return camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex);
- }
-
- store->subscribed_folders = g_hash_table_new (g_str_hash, g_str_equal);
-
- camel_file_util_decode_uint32 (storeinfo, &store->capabilities);
- imap_set_server_level (store);
- camel_file_util_decode_string (storeinfo, &name);
- /* if the namespace has changed, the subscribed folder list in this file is bogus */
- if (store->namespace == NULL || (name != NULL && strcmp(name, store->namespace) == 0)) {
- g_free(store->namespace);
- store->namespace = name;
- camel_file_util_decode_uint32 (storeinfo, &tmp);
- store->dir_sep = tmp;
- ((CamelStore *)store)->dir_sep = tmp;
- while (camel_file_util_decode_string (storeinfo, &buf) == 0) {
- if (!imap_parse_list_response (store, buf, NULL, NULL, &name)) {
- g_free (buf);
- continue;
- }
- g_hash_table_insert (store->subscribed_folders, name,
- GINT_TO_POINTER (1));
- g_free (buf);
- }
- } else {
- g_free(name);
- }
-
- fclose (storeinfo);
imap_store_refresh_folders (store, ex);
store->connected = !camel_exception_is_set (ex);
@@ -1349,13 +1339,6 @@ imap_disconnect_offline (CamelService *service, gboolean clean, CamelException *
store->current_folder = NULL;
}
- if (store->subscribed_folders) {
- g_hash_table_foreach_remove (store->subscribed_folders,
- free_key, NULL);
- g_hash_table_destroy (store->subscribed_folders);
- store->subscribed_folders = NULL;
- }
-
if (store->authtypes) {
g_hash_table_foreach_remove (store->authtypes,
free_key, NULL);
@@ -1529,29 +1512,34 @@ get_folder_online (CamelStore *store, const char *folder_name,
if (!g_strcasecmp (folder_name, "INBOX"))
folder_name = "INBOX";
-
+
/* Lock around the whole lot to check/create atomically */
CAMEL_SERVICE_LOCK (imap_store, connect_lock);
if (imap_store->current_folder) {
camel_object_unref (CAMEL_OBJECT (imap_store->current_folder));
imap_store->current_folder = NULL;
}
- response = camel_imap_command (imap_store, NULL, NULL,
- "SELECT %F", folder_name);
+ response = camel_imap_command (imap_store, NULL, NULL, "SELECT %F", folder_name);
if (!response) {
+ char *folder_real;
+
if (!flags & CAMEL_STORE_FOLDER_CREATE) {
CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
return no_such_folder (folder_name, ex);
}
-
- response = camel_imap_command (imap_store, NULL, ex,
- "CREATE %F", folder_name);
+
+ folder_real = camel_imap_store_summary_path_to_full(imap_store->summary, folder_name, store->dir_sep);
+
+ response = camel_imap_command (imap_store, NULL, ex, "CREATE %S", folder_real);
+
if (response) {
+ camel_imap_store_summary_add_from_full(imap_store->summary, folder_real, store->dir_sep);
+
camel_imap_response_free (imap_store, response);
- response = camel_imap_command (imap_store, NULL, NULL,
- "SELECT %F", folder_name);
+ response = camel_imap_command (imap_store, NULL, NULL, "SELECT %F", folder_name);
}
+ g_free(folder_real);
if (!response) {
CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
return NULL;
@@ -1652,60 +1640,79 @@ delete_folder (CamelStore *store, const char *folder_name, CamelException *ex)
}
static void
-manage_subscriptions (CamelStore *store, CamelFolderInfo *fi, gboolean subscribe)
+manage_subscriptions (CamelStore *store, const char *old_name, gboolean subscribe)
{
- while (fi) {
- if (fi->child)
- manage_subscriptions (store, fi->child, subscribe);
-
- if (subscribe)
- subscribe_folder (store, fi->full_name, NULL);
- else
- unsubscribe_folder (store, fi->full_name, NULL);
-
- fi = fi->sibling;
+ CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ CamelStoreInfo *si;
+ int olen = strlen(old_name);
+ const char *path;
+ int i, count;
+
+ count = camel_store_summary_count((CamelStoreSummary *)imap_store->summary);
+ for (i=0;i<count;i++) {
+ si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i);
+ if (si) {
+ path = camel_store_info_path(imap_store->summary, si);
+ if (strncmp(path, old_name, olen) == 0) {
+ if (subscribe)
+ subscribe_folder(store, path, NULL);
+ else
+ unsubscribe_folder(store, path, NULL);
+ }
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+ }
}
}
-#define subscribe_folders(store, fi) manage_subscriptions (store, fi, TRUE)
-#define unsubscribe_folders(store, fi) manage_subscriptions (store, fi, FALSE)
-
static void
-rename_folder_info (CamelImapStore *imap_store, CamelFolderInfo *fi, const char *old_name, const char *new_name)
+rename_folder_info (CamelImapStore *imap_store, const char *old_name, const char *new_name)
{
- CamelImapResponse *response;
- char *name;
-
- while (fi) {
- if (fi->child)
- rename_folder_info (imap_store, fi->child, old_name, new_name);
-
- name = g_strdup_printf ("%s%s", new_name, fi->full_name + strlen (old_name));
-
- if (imap_store->dir_sep == '.') {
- /* kludge around imap servers like Courier that don't rename
- subfolders when you rename the parent folder - like
- the spec says to do!!! */
- response = camel_imap_command (imap_store, NULL, NULL, "RENAME %F %F", fi->full_name, name);
- if (response)
- camel_imap_response_free (imap_store, response);
+ int i, count;
+ CamelStoreInfo *si;
+ int olen = strlen(old_name);
+ const char *path;
+ char *npath, *nfull;
+
+ count = camel_store_summary_count((CamelStoreSummary *)imap_store->summary);
+ for (i=0;i<count;i++) {
+ si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i);
+ if (si == NULL)
+ continue;
+ path = camel_store_info_path(imap_store->summary, si);
+ if (strncmp(path, old_name, olen) == 0) {
+ if (strlen(path) > olen)
+ npath = g_strdup_printf("%s/%s", new_name, path+olen+1);
+ else
+ npath = g_strdup(new_name);
+ nfull = camel_imap_store_summary_path_to_full(imap_store->summary, npath, imap_store->dir_sep);
+
+ /* workaround for broken server (courier uses '.') that doesn't rename
+ subordinate folders as required by rfc 2060 */
+ if (imap_store->dir_sep == '.') {
+ CamelImapResponse *response;
+
+ response = camel_imap_command (imap_store, NULL, NULL, "RENAME %F %S", path, nfull);
+ if (response)
+ camel_imap_response_free (imap_store, response);
+ }
+
+ camel_store_info_set_string((CamelStoreSummary *)imap_store->summary, si, CAMEL_STORE_INFO_PATH, npath);
+ camel_store_info_set_string((CamelStoreSummary *)imap_store->summary, si, CAMEL_IMAP_STORE_INFO_FULL_NAME, nfull);
+
+ camel_store_summary_touch((CamelStoreSummary *)imap_store->summary);
+ g_free(nfull);
+ g_free(npath);
}
-
- g_free (fi->full_name);
- fi->full_name = name;
-
- fi = fi->sibling;
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
}
}
static void
-rename_folder (CamelStore *store, const char *old_name, const char *new_name, CamelException *ex)
+rename_folder (CamelStore *store, const char *old_name, const char *new_name_in, CamelException *ex)
{
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
CamelImapResponse *response;
- char *oldpath, *newpath, *storage_path;
- CamelFolderInfo *fi;
- guint32 flags;
+ char *oldpath, *newpath, *storage_path, *new_name;
if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex))
return;
@@ -1730,35 +1737,31 @@ rename_folder (CamelStore *store, const char *old_name, const char *new_name, Ca
imap_store->renaming = TRUE;
- flags = CAMEL_STORE_FOLDER_INFO_FAST | CAMEL_STORE_FOLDER_INFO_RECURSIVE |
- (store->flags & CAMEL_STORE_SUBSCRIPTIONS ? CAMEL_STORE_FOLDER_INFO_SUBSCRIBED : 0);
-
- fi = ((CamelStoreClass *)((CamelObject *)store)->klass)->get_folder_info (store, old_name, flags, ex);
- if (fi && store->flags & CAMEL_STORE_SUBSCRIPTIONS)
- unsubscribe_folders (store, fi);
-
- response = camel_imap_command (imap_store, NULL, ex, "RENAME %F %F", old_name, new_name);
+ if (store->flags & CAMEL_STORE_SUBSCRIPTIONS)
+ manage_subscriptions(store, old_name, FALSE);
+
+ new_name = camel_imap_store_summary_path_to_full(imap_store->summary, new_name_in, store->dir_sep);
+ response = camel_imap_command (imap_store, NULL, ex, "RENAME %F %S", old_name, new_name);
if (!response) {
- if (fi && store->flags & CAMEL_STORE_SUBSCRIPTIONS)
- subscribe_folders (store, fi);
-
- camel_store_free_folder_info (store, fi);
+ if (store->flags & CAMEL_STORE_SUBSCRIPTIONS)
+ manage_subscriptions(store, old_name, TRUE);
+ g_free(new_name);
imap_store->renaming = FALSE;
return;
}
camel_imap_response_free (imap_store, response);
-
- rename_folder_info (imap_store, fi, old_name, new_name);
- if (fi && store->flags & CAMEL_STORE_SUBSCRIPTIONS)
- subscribe_folders (store, fi);
-
- camel_store_free_folder_info (store, fi);
-
+
+ /* rename summary, and handle broken server */
+ rename_folder_info(imap_store, old_name, new_name_in);
+
+ if (store->flags & CAMEL_STORE_SUBSCRIPTIONS)
+ manage_subscriptions(store, new_name_in, TRUE);
+
storage_path = g_strdup_printf("%s/folders", imap_store->storage_path);
oldpath = e_path_to_physical (storage_path, old_name);
- newpath = e_path_to_physical (storage_path, new_name);
+ newpath = e_path_to_physical (storage_path, new_name_in);
g_free(storage_path);
/* So do we care if this didn't work? Its just a cache? */
@@ -1769,7 +1772,8 @@ rename_folder (CamelStore *store, const char *old_name, const char *new_name, Ca
g_free (oldpath);
g_free (newpath);
-
+ g_free(new_name);
+
imap_store->renaming = FALSE;
}
@@ -1778,13 +1782,11 @@ create_folder (CamelStore *store, const char *parent_name,
const char *folder_name, CamelException *ex)
{
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
- char *full_name, *resp, *thisone;
+ char *full_name, *resp, *thisone, *parent_real, *real_name;
CamelImapResponse *response;
CamelException internal_ex;
CamelFolderInfo *root = NULL;
gboolean need_convert;
- char **pathnames = NULL;
- GPtrArray *folders = NULL;
int i = 0, flags;
if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex))
@@ -1801,12 +1803,22 @@ create_folder (CamelStore *store, const char *parent_name,
}
/* check if the parent allows inferiors */
-
+
+ /* FIXME: use storesummary directly */
+ parent_real = camel_imap_store_summary_full_from_path(imap_store->summary, parent_name);
+ if (parent_real == NULL) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_STATE,
+ _("Unknown parent folder: %s"), parent_name);
+ return NULL;
+ }
+
need_convert = FALSE;
- response = camel_imap_command (imap_store, NULL, ex, "LIST \"\" %F",
- parent_name);
- if (!response) /* whoa, this is bad */
+ response = camel_imap_command (imap_store, NULL, ex, "LIST \"\" %S",
+ parent_real);
+ if (!response) /* whoa, this is bad */ {
+ g_free(parent_real);
return NULL;
+ }
/* FIXME: does not handle unexpected circumstances very well */
for (i = 0; i < response->untagged->len; i++) {
@@ -1833,6 +1845,7 @@ create_folder (CamelStore *store, const char *parent_name,
if (get_folder_status (imap_store, parent_name, "MESSAGES")) {
camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INVALID_STATE,
_("The parent folder is not allowed to contain subfolders"));
+ g_free(parent_real);
return NULL;
}
@@ -1844,91 +1857,53 @@ create_folder (CamelStore *store, const char *parent_name,
}
/* add the dirsep to the end of parent_name */
- name = g_strdup_printf ("%s%c", parent_name, imap_store->dir_sep);
- response = camel_imap_command (imap_store, NULL, ex, "CREATE %F",
+ name = g_strdup_printf ("%s%c", parent_real, imap_store->dir_sep);
+ response = camel_imap_command (imap_store, NULL, ex, "CREATE %S",
name);
g_free (name);
- if (!response)
+ if (!response) {
+ g_free(parent_real);
return NULL;
- else
+ } else
camel_imap_response_free (imap_store, response);
+
+ root = imap_build_folder_info(imap_store, parent_name);
}
/* ok now we can create the folder */
-
- full_name = imap_concat (imap_store, parent_name, folder_name);
- response = camel_imap_command (imap_store, NULL, ex, "CREATE %F",
- full_name);
- g_free (full_name);
+ real_name = camel_imap_store_summary_path_to_full(imap_store->summary, folder_name, store->dir_sep);
+ full_name = imap_concat (imap_store, parent_real, real_name);
+ g_free(real_name);
+ response = camel_imap_command (imap_store, NULL, ex, "CREATE %S", full_name);
if (response) {
- CamelFolderInfo *parent, *fi;
-
+ CamelImapStoreInfo *si;
+ CamelFolderInfo *fi;
+
camel_imap_response_free (imap_store, response);
-
- /* We have to do this in case we are creating a
- recursive directory structure */
- i = 0;
- pathnames = imap_parse_folder_name (imap_store, folder_name);
- full_name = imap_concat (imap_store, parent_name, pathnames[i]);
- g_free (pathnames[i]);
-
- folders = g_ptr_array_new ();
-
- get_folders_online (imap_store, full_name, folders, FALSE, ex);
- g_free (full_name);
- if (camel_exception_is_set (&internal_ex)) {
- camel_exception_xfer (&internal_ex, ex);
- goto exception;
- }
-
- root = parent = folders->pdata[i];
-
- for (i = 1; parent && pathnames[i]; i++) {
- full_name = imap_concat (imap_store, parent_name, pathnames[i]);
- g_free (pathnames[i]);
-
- get_folders_online (imap_store, full_name, folders, FALSE, &internal_ex);
- if (camel_exception_is_set (&internal_ex)) {
- camel_exception_xfer (&internal_ex, ex);
- goto exception;
- }
- g_free (full_name);
-
- if (folders->len != i + 1)
- break;
-
- fi = folders->pdata[i];
- camel_folder_info_build_path (fi, imap_store->dir_sep);
- parent->child = fi;
- fi->parent = parent;
- parent = fi;
+
+ si = camel_imap_store_summary_add_from_full(imap_store->summary, full_name, store->dir_sep);
+ camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
+ fi = imap_build_folder_info(imap_store, camel_store_info_path(imap_store->summary, si));
+ if (root) {
+ root->child = fi;
+ fi->parent = root;
+ } else {
+ root = fi;
}
-
- camel_folder_info_build_path(root, imap_store->dir_sep);
camel_object_trigger_event (CAMEL_OBJECT (store), "folder_created", root);
-
- g_free (pathnames);
-
- g_ptr_array_free (folders, TRUE);
+ } else if (root) {
+ /* need to re-recreate the folder we just deleted */
+ camel_object_trigger_event (CAMEL_OBJECT (store), "folder_created", root);
+ camel_folder_info_free(root);
+ root = NULL;
}
+
+ g_free (full_name);
+ g_free(parent_real);
return root;
-
- exception:
-
- for (/* i is already set */; pathnames && pathnames[i]; i++)
- g_free (pathnames[i]);
- g_free (pathnames);
-
- if (folders) {
- for (i = 0; i < folders->len; i++)
- camel_folder_info_free (folders->pdata[i]);
- g_ptr_array_free (folders, TRUE);
- }
-
- return NULL;
}
static CamelFolderInfo *
@@ -1936,32 +1911,45 @@ parse_list_response_as_folder_info (CamelImapStore *imap_store,
const char *response)
{
CamelFolderInfo *fi;
- int flags;
- char sep, *dir, *name = NULL;
+ int flags, i;
+ char sep, *dir, *name = NULL, *path;
CamelURL *url;
if (!imap_parse_list_response (imap_store, response, &flags, &sep, &dir))
return NULL;
+
+ /* FIXME: should use imap_build_folder_info, note the differences with param setting tho */
+ path = camel_utf7_utf8(dir);
+
+ /* hack: pokes in value from any list response */
+ camel_imap_store_summary_add_from_full(imap_store->summary, dir, sep?sep:'/');
- if (sep) {
- name = strrchr (dir, sep);
- if (name && !*++name) {
- g_free (dir);
+ if (sep && (name = strrchr(path, sep))) {
+ if (!*++name) {
+ g_free(dir);
+ g_free(path);
return NULL;
}
- }
+ } else
+ name = path;
fi = g_new0 (CamelFolderInfo, 1);
fi->flags = flags;
- fi->full_name = dir;
- if (sep && name)
- fi->name = g_strdup (name);
- else
- fi->name = g_strdup (dir);
-
+ /*fi->full_name = dir;*/
+ fi->name = g_strdup(name);
+ fi->path = g_strdup_printf("/%s", path);
+
+ if (sep && sep != '/') {
+ for (i=0;fi->path[i];i++)
+ if (fi->path[i] == sep)
+ fi->path[i] = '/';
+ }
+ fi->full_name = g_strdup(fi->path+1);
+
url = camel_url_new (imap_store->base_url, NULL);
g_free (url->path);
- url->path = g_strdup_printf ("/%s", dir);
+ url->path = g_strdup_printf ("/%s", fi->full_name);
+
if (flags & CAMEL_FOLDER_NOSELECT || fi->name[0] == 0)
camel_url_set_param (url, "noselect", "yes");
fi->url = camel_url_to_string (url, 0);
@@ -1974,43 +1962,40 @@ parse_list_response_as_folder_info (CamelImapStore *imap_store,
return fi;
}
-static void
-copy_folder_name (gpointer name, gpointer key, gpointer array)
-{
- g_ptr_array_add (array, name);
-}
-
/* this is used when lsub doesn't provide very useful information */
static GPtrArray *
get_subscribed_folders (CamelImapStore *imap_store, const char *top, CamelException *ex)
{
GPtrArray *names, *folders;
+ int i, toplen = strlen (top);
+ CamelStoreInfo *si;
CamelImapResponse *response;
CamelFolderInfo *fi;
char *result;
- int i, toplen = strlen (top);
-
+
folders = g_ptr_array_new ();
names = g_ptr_array_new ();
- g_hash_table_foreach (imap_store->subscribed_folders,
- copy_folder_name, names);
+ for (i=0;(si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i));i++) {
+ if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)
+ g_ptr_array_add(names, (char *)camel_imap_store_info_full_name(imap_store->summary, si));
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+ }
if (names->len == 0)
g_ptr_array_add (names, "INBOX");
-
+
for (i = 0; i < names->len; i++) {
response = camel_imap_command (imap_store, NULL, ex,
- "LIST \"\" %F",
+ "LIST \"\" %S",
names->pdata[i]);
if (!response)
break;
result = camel_imap_response_extract (imap_store, response, "LIST", NULL);
if (!result) {
- g_hash_table_remove (imap_store->subscribed_folders,
- names->pdata[i]);
- g_free (names->pdata[i]);
- g_ptr_array_remove_index_fast (names, i--);
+ camel_store_summary_remove_path((CamelStoreSummary *)imap_store->summary, names->pdata[i]);
+ g_ptr_array_remove_index_fast (names, i);
+ i--;
continue;
}
@@ -2031,6 +2016,31 @@ get_subscribed_folders (CamelImapStore *imap_store, const char *top, CamelExcept
return folders;
}
+static int imap_match_pattern(char dir_sep, const char *pattern, const char *name)
+{
+ char p, n;
+
+ p = *pattern++;
+ n = *name++;
+ while (n && p) {
+ if (n == p) {
+ p = *pattern++;
+ n = *name++;
+ } else if (p == '%') {
+ if (n != dir_sep) {
+ n = *name++;
+ } else {
+ p = *pattern++;
+ }
+ } else if (p == '*') {
+ return TRUE;
+ } else
+ return FALSE;
+ }
+
+ return n == 0 && (p == '%' || p == 0);
+}
+
static void
get_folders_online (CamelImapStore *imap_store, const char *pattern,
GPtrArray *folders, gboolean lsub, CamelException *ex)
@@ -2038,21 +2048,56 @@ get_folders_online (CamelImapStore *imap_store, const char *pattern,
CamelImapResponse *response;
CamelFolderInfo *fi;
char *list;
- int i;
-
+ int i, count;
+ GHashTable *present;
+ CamelStoreInfo *si;
+
response = camel_imap_command (imap_store, NULL, ex,
- "%s \"\" %F", lsub ? "LSUB" : "LIST",
+ "%s \"\" %S", lsub ? "LSUB" : "LIST",
pattern);
if (!response)
return;
-
+
+ present = g_hash_table_new(g_str_hash, g_str_equal);
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)
- g_ptr_array_add (folders, fi);
+ if (fi) {
+ g_ptr_array_add(folders, fi);
+ g_hash_table_insert(present, fi->full_name, fi);
+ }
}
camel_imap_response_free (imap_store, response);
+
+ /* update our summary to match the server */
+ count = camel_store_summary_count((CamelStoreSummary *)imap_store->summary);
+ for (i=0;i<count;i++) {
+ si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i);
+ if (si == NULL)
+ continue;
+
+ if (imap_match_pattern(((CamelStore *)imap_store)->dir_sep, pattern, camel_imap_store_info_full_name(imap_store->summary, si))) {
+ if (g_hash_table_lookup(present, camel_store_info_path(imap_store->summary, si)) != NULL) {
+ if (lsub && (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) == 0) {
+ si->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+ camel_store_summary_touch((CamelStoreSummary *)imap_store->summary);
+ }
+ } else {
+ if (lsub) {
+ if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
+ si->flags &= ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+ camel_store_summary_touch((CamelStoreSummary *)imap_store->summary);
+ }
+ } else {
+ camel_store_summary_remove((CamelStoreSummary *)imap_store->summary, si);
+ count--;
+ i--;
+ }
+ }
+ }
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+ }
+ g_hash_table_destroy(present);
}
#if 1
@@ -2072,7 +2117,7 @@ dumpfi(CamelFolderInfo *fi)
}
while (fi) {
- printf("%-40s %-30s %*s\n", fi->path, fi->full_name, depth*2+strlen(fi->name), fi->name);
+ printf("%-40s %-30s %*s\n", fi->path, fi->full_name, depth*2+strlen(fi->url), fi->url);
if (fi->child)
dumpfi(fi->child);
fi = fi->sibling;
@@ -2179,13 +2224,21 @@ get_folders(CamelStore *store, const char *top, guint32 flags, CamelException *e
infos = g_hash_table_new(folder_hash, folder_eq);
/* get starting point & strip trailing '/' */
- if (top[0] == 0 && imap_store->namespace)
- top = imap_store->namespace;
- i = strlen(top)-1;
- name = alloca(i+2);
- strcpy(name, top);
- while (i>0 && name[i] == store->dir_sep)
- name[i--] = 0;
+ if (top[0] == 0) {
+ if (imap_store->namespace) {
+ top = imap_store->namespace;
+ i = strlen(top)-1;
+ name = g_malloc(i+2);
+ strcpy(name, top);
+ while (i>0 && name[i] == store->dir_sep)
+ name[i--] = 0;
+ } else
+ name = g_strdup("");
+ } else {
+ name = camel_imap_store_summary_full_from_path(imap_store->summary, top);
+ if (name == NULL)
+ name = camel_imap_store_summary_path_to_full(imap_store->summary, top, store->dir_sep);
+ }
d(printf("\n\nList '%s' %s\n", name, flags&CAMEL_STORE_FOLDER_INFO_RECURSIVE?"RECURSIVE":"NON-RECURSIVE"));
@@ -2194,13 +2247,18 @@ get_folders(CamelStore *store, const char *top, guint32 flags, CamelException *e
/* first get working list of names */
get_folders_online (imap_store, name[0]?name:"%", folders, flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, ex);
+ if (camel_exception_is_set(ex))
+ goto fail;
for (i=0; i<folders->len && !haveinbox; i++) {
fi = folders->pdata[i];
haveinbox = (strcasecmp(fi->full_name, "INBOX")) == 0;
}
- if (!haveinbox && top == imap_store->namespace)
+ if (!haveinbox && top == imap_store->namespace) {
get_folders_online(imap_store, "INBOX", folders, flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, ex);
+ if (camel_exception_is_set(ex))
+ goto fail;
+ }
for (i=0; i<folders->len; i++)
p = g_slist_prepend(p, folders->pdata[i]);
@@ -2230,11 +2288,13 @@ get_folders(CamelStore *store, const char *top, guint32 flags, CamelException *e
/* Otherwise, if this has (or might have) children, scan it */
else if ( (fi->flags & (CAMEL_IMAP_FOLDER_NOCHILDREN|CAMEL_FOLDER_NOINFERIORS)) == 0
|| (fi->flags & CAMEL_FOLDER_CHILDREN) != 0) {
- char *n;
-
- n = imap_concat(imap_store, fi->full_name, "%");
+ char *n, *real;
+
+ real = camel_imap_store_summary_full_from_path(imap_store->summary, fi->full_name);
+ n = imap_concat(imap_store, real?real:fi->full_name, "%");
get_folders_online(imap_store, n, folders, flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, ex);
g_free(n);
+ g_free(real);
if (folders->len > 0)
fi->flags |= CAMEL_FOLDER_CHILDREN;
@@ -2259,8 +2319,16 @@ get_folders(CamelStore *store, const char *top, guint32 flags, CamelException *e
g_ptr_array_free(folders, TRUE);
g_hash_table_destroy(infos);
+ g_free(name);
return folders_out;
+fail:
+ g_ptr_array_free(folders, TRUE);
+ g_ptr_array_free(folders_out, TRUE);
+ g_hash_table_destroy(infos);
+ g_free(name);
+
+ return NULL;
}
static CamelFolderInfo *
@@ -2280,14 +2348,18 @@ get_folder_info_online (CamelStore *store, const char *top, guint32 flags, Camel
else
folders = get_folders(store, top, flags, ex);
+ if (folders == NULL)
+ return NULL;
+
/* note the weird top stuff, it is so a namespace based list "" is properly tree-ised */
- tree = camel_folder_info_build(folders, top[0] == 0 && imap_store->namespace?"":top, imap_store->dir_sep, TRUE);
+ tree = camel_folder_info_build(folders, top[0] == 0 && imap_store->namespace?"":top, '/', TRUE);
g_ptr_array_free(folders, TRUE);
if (!(flags & CAMEL_STORE_FOLDER_INFO_FAST))
get_folder_counts(imap_store, tree, ex);
dumpfi(tree);
+ camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
return tree;
}
@@ -2298,7 +2370,7 @@ get_one_folder_offline (const char *physical_path, const char *path, gpointer da
GPtrArray *folders = data;
CamelImapStore *imap_store = folders->pdata[0];
CamelFolderInfo *fi;
- CamelURL *url;
+ CamelStoreInfo *si;
if (*path != '/')
return TRUE;
@@ -2309,26 +2381,16 @@ get_one_folder_offline (const char *physical_path, const char *path, gpointer da
* not a folder we're explicitly interested in.
*/
- if (g_hash_table_lookup (imap_store->subscribed_folders, path + 1) == 0)
- return TRUE;
-
- fi = g_new0 (CamelFolderInfo, 1);
- fi->full_name = g_strdup (path+1);
- fi->name = strrchr (fi->full_name, imap_store->dir_sep);
- if (fi->name)
- fi->name = g_strdup (fi->name + 1);
- else
- fi->name = g_strdup (fi->full_name);
-
- url = camel_url_new(imap_store->base_url, NULL);
- camel_url_set_path(url, path);
- fi->url = camel_url_to_string(url, 0);
- camel_url_free(url);
-
- /* FIXME: check summary */
- fi->unread_message_count = -1;
+ si = camel_store_summary_path((CamelStoreSummary *)imap_store->summary, path+1);
+ if (si) {
+ if ((((CamelStore *)imap_store)->flags & CAMEL_STORE_SUBSCRIPTIONS) == 0
+ || si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
+ fi = imap_build_folder_info(imap_store, path+1);
+ g_ptr_array_add (folders, fi);
+ }
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+ }
- g_ptr_array_add (folders, fi);
return TRUE;
}
@@ -2363,8 +2425,7 @@ get_folder_info_offline (CamelStore *store, const char *top,
fi = NULL;
} else {
g_ptr_array_remove_index_fast (folders, 0);
- fi = camel_folder_info_build (folders, "",
- imap_store->dir_sep, TRUE);
+ fi = camel_folder_info_build (folders, "", '/', TRUE);
}
g_free(storage_path);
@@ -2376,13 +2437,19 @@ static gboolean
folder_subscribed (CamelStore *store, const char *folder_name)
{
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
+ CamelStoreInfo *si;
+ int truth = FALSE;
- g_return_val_if_fail (imap_store->subscribed_folders != NULL, FALSE);
+ si = camel_store_summary_path((CamelStoreSummary *)imap_store->summary, folder_name);
+ if (si) {
+ truth = (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0;
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+ }
- return g_hash_table_lookup (imap_store->subscribed_folders,
- folder_name) != NULL;
+ return truth;
}
+/* Note: folder_name must match a folder as listed with get_folder_info() -> full_name */
static void
subscribe_folder (CamelStore *store, const char *folder_name,
CamelException *ex)
@@ -2390,9 +2457,8 @@ subscribe_folder (CamelStore *store, const char *folder_name,
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
CamelImapResponse *response;
CamelFolderInfo *fi;
- const char *name;
- CamelURL *url;
-
+ CamelStoreInfo *si;
+
if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex))
return;
if (!camel_imap_store_connected (imap_store, ex))
@@ -2404,8 +2470,15 @@ subscribe_folder (CamelStore *store, const char *folder_name,
return;
camel_imap_response_free (imap_store, response);
- g_hash_table_insert (imap_store->subscribed_folders,
- g_strdup (folder_name), GUINT_TO_POINTER (1));
+ si = camel_store_summary_path((CamelStoreSummary *)imap_store->summary, folder_name);
+ if (si) {
+ if ((si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) == 0) {
+ si->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+ camel_store_summary_touch((CamelStoreSummary *)imap_store->summary);
+ camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
+ }
+ camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+ }
if (imap_store->renaming) {
/* we don't need to emit a "folder_subscribed" signal
@@ -2413,26 +2486,8 @@ subscribe_folder (CamelStore *store, const char *folder_name,
are done here... */
return;
}
-
- name = strrchr (folder_name, imap_store->dir_sep);
- if (name)
- name++;
- else
- name = folder_name;
-
- url = camel_url_new (imap_store->base_url, NULL);
- g_free (url->path);
- url->path = g_strdup_printf ("/%s", folder_name);
-
- fi = g_new0 (CamelFolderInfo, 1);
- fi->full_name = g_strdup (folder_name);
- fi->name = g_strdup (name);
- fi->url = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
- fi->unread_message_count = -1;
- camel_folder_info_build_path (fi, imap_store->dir_sep);
-
- camel_url_free (url);
-
+
+ fi = imap_build_folder_info(imap_store, folder_name);
camel_object_trigger_event (CAMEL_OBJECT (store), "folder_subscribed", fi);
camel_folder_info_free (fi);
}
diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h
index 499c282649..38df1880a0 100644
--- a/camel/providers/imap/camel-imap-store.h
+++ b/camel/providers/imap/camel-imap-store.h
@@ -102,6 +102,8 @@ struct _CamelImapStore {
CamelStream *istream;
CamelStream *ostream;
+
+ struct _CamelImapStoreSummary *summary;
/* Information about the command channel / connection status */
gboolean connected;
@@ -113,7 +115,7 @@ struct _CamelImapStore {
CamelImapServerLevel server_level;
guint32 capabilities, parameters;
char *namespace, dir_sep, *base_url, *storage_path;
- GHashTable *authtypes, *subscribed_folders;
+ GHashTable *authtypes;
gboolean renaming;
diff --git a/camel/providers/imap/camel-imap-utils.c b/camel/providers/imap/camel-imap-utils.c
index 15bf2540b3..fc507398db 100644
--- a/camel/providers/imap/camel-imap-utils.c
+++ b/camel/providers/imap/camel-imap-utils.c
@@ -20,11 +20,19 @@
*
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
-#include <iconv.h>
+#include <errno.h>
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
#include "camel-imap-utils.h"
#include "camel-imap-summary.h"
@@ -363,7 +371,9 @@ imap_parse_list_response (CamelImapStore *store, const char *buf, int *flags, ch
astring = imap_parse_astring (&word, &len);
if (!astring)
return FALSE;
-
+
+ *folder = astring;
+#if 0
mailbox = imap_mailbox_decode (astring, strlen (astring));
g_free (astring);
if (!mailbox)
@@ -385,6 +395,7 @@ imap_parse_list_response (CamelImapStore *store, const char *buf, int *flags, ch
*flags &= ~CAMEL_FOLDER_NOSELECT;
*folder = mailbox;
+#endif
}
return TRUE;