From 466e05c024510d8019989f8bf8f04541c3ca792d Mon Sep 17 00:00:00 2001 From: 4 Date: Sat, 15 Sep 2001 08:12:58 +0000 Subject: New function, set the complete list of folders on a vfolder, all at once. 2001-09-14 * camel-vee-folder.c (camel_vee_folder_set_folders): New function, set the complete list of folders on a vfolder, all at once. (camel_vee_folder_set_expression): If we set the query to be the same thing, dont do anything. * camel-vee-store.c (camel_vee_store_init): Turn off vtrash for this store. * camel-store.c (camel_store_init): Enable vtrash by default via flags. (camel_store_get_trash): REturn NULL if the store doesn't support vtrash. (init_trash): Dont init if store doesn't support vtrash. * camel-store.h: Add a new flags CAMEL_STORE_VTRASH -> store supports vtrash. 2001-09-13 * camel-vee-store.c (vee_get_folder_info): Implement. (build_info): Used to build a folder record from the folders hashtable. (vee_delete_folder): Implemented, remove folder from hashtable. (vee_rename_folder): Implemented, remove old folder from hashtable, add new one and rename its guts too. * camel-store.c (camel_store_rename_folder): Do nothing if we're not asked to actually change names. Also dont do the renamed cache check till after we've called the subclass. (camel_store_delete_folder): Call the subclass delete firs,t then make sure the cache is right. * camel-vee-folder.c (vee_folder_construct): Remove support for name?query syntax to setup vfolder. Abort if such syntax is used. (camel_vee_folder_new): Removed code that handles ? syntax, etc. (vee_folder_build_folder): Handle unset expression, treat it as an empty search. (camel_vee_folder_set_expression): Oops, actually set the expression. * camel-vtrash-folder.c (camel_vtrash_folder_new): Dont use name?query syntax to setup vfolder, but set the expression directly. Also fixes a small memleak. 2001-09-12 * camel-store.c (camel_store_delete_folder): Fixed warnings with a cast. (camel_store_rename_folder): " svn path=/trunk/; revision=12854 --- camel/ChangeLog | 51 +++++++++++++ camel/camel-store.c | 27 +++++-- camel/camel-store.h | 3 +- camel/camel-vee-folder.c | 95 +++++++++++++++++++----- camel/camel-vee-folder.h | 1 + camel/camel-vee-store.c | 171 ++++++++++++++++++++++++++++++++++++++++++++ camel/camel-vtrash-folder.c | 11 ++- 7 files changed, 326 insertions(+), 33 deletions(-) diff --git a/camel/ChangeLog b/camel/ChangeLog index e2cc98dd49..a62a593ca5 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,54 @@ +2001-09-14 + + * camel-vee-folder.c (camel_vee_folder_set_folders): New function, + set the complete list of folders on a vfolder, all at once. + (camel_vee_folder_set_expression): If we set the query to be the + same thing, dont do anything. + + * camel-vee-store.c (camel_vee_store_init): Turn off vtrash for + this store. + + * camel-store.c (camel_store_init): Enable vtrash by default via + flags. + (camel_store_get_trash): REturn NULL if the store doesn't support + vtrash. + (init_trash): Dont init if store doesn't support vtrash. + + * camel-store.h: Add a new flags CAMEL_STORE_VTRASH -> store + supports vtrash. + +2001-09-13 + + * camel-vee-store.c (vee_get_folder_info): Implement. + (build_info): Used to build a folder record from the folders + hashtable. + (vee_delete_folder): Implemented, remove folder from hashtable. + (vee_rename_folder): Implemented, remove old folder from + hashtable, add new one and rename its guts too. + + * camel-store.c (camel_store_rename_folder): Do nothing if we're + not asked to actually change names. Also dont do the renamed + cache check till after we've called the subclass. + (camel_store_delete_folder): Call the subclass delete firs,t then + make sure the cache is right. + + * camel-vee-folder.c (vee_folder_construct): Remove support for + name?query syntax to setup vfolder. Abort if such syntax is used. + (camel_vee_folder_new): Removed code that handles ? syntax, etc. + (vee_folder_build_folder): Handle unset expression, treat it as an + empty search. + (camel_vee_folder_set_expression): Oops, actually set the + expression. + + * camel-vtrash-folder.c (camel_vtrash_folder_new): Dont use + name?query syntax to setup vfolder, but set the expression + directly. Also fixes a small memleak. + +2001-09-12 + + * camel-store.c (camel_store_delete_folder): Fixed warnings with a cast. + (camel_store_rename_folder): " + 2001-09-14 Jeffrey Stedfast * camel-url.c (camel_url_set_param): Use g_datalist_set_data_full diff --git a/camel/camel-store.c b/camel/camel-store.c index 470ada7baf..9722163cec 100644 --- a/camel/camel-store.c +++ b/camel/camel-store.c @@ -111,7 +111,8 @@ camel_store_init (void *o) } else store->folders = NULL; - store->flags = 0; + /* set vtrash on by default */ + store->flags = CAMEL_STORE_VTRASH; store->priv = g_malloc0 (sizeof (*store->priv)); #ifdef ENABLE_THREADS @@ -226,11 +227,15 @@ camel_store_get_folder (CamelStore *store, const char *folder_name, guint32 flag if (store->folders) { CAMEL_STORE_LOCK(store, cache_lock); + printf("adding folder '%s' to folders hashtable\n", folder_name); g_hash_table_insert (store->folders, g_strdup (folder_name), folder); + printf("store folders size = %d\n", g_hash_table_size(store->folders)); + camel_object_hook_event (CAMEL_OBJECT (folder), "finalize", folder_finalize, store); CAMEL_STORE_UNLOCK(store, cache_lock); - } + } else + printf("not adding folder '%s' to folders hashtable\n", folder_name); } } @@ -296,13 +301,15 @@ camel_store_delete_folder (CamelStore *store, const char *folder_name, CamelExce CAMEL_STORE_LOCK(store, folder_lock); + CS_CLASS (store)->delete_folder (store, folder_name, ex); + /* if we deleted a folder, force it out of the cache, and also out of the vtrash if setup */ if (store->folders) { CamelFolder *folder; char *key; CAMEL_STORE_LOCK(store, cache_lock); - if (g_hash_table_lookup_extended(store->folders, folder_name, &key, (void **)&folder)) { + if (g_hash_table_lookup_extended(store->folders, folder_name, (void **)&key, (void **)&folder)) { g_hash_table_remove(store->folders, key); g_free(key); CAMEL_STORE_UNLOCK(store, cache_lock); @@ -313,7 +320,6 @@ camel_store_delete_folder (CamelStore *store, const char *folder_name, CamelExce } } - CS_CLASS (store)->delete_folder (store, folder_name, ex); CAMEL_STORE_UNLOCK(store, folder_lock); } @@ -341,17 +347,20 @@ camel_store_rename_folder (CamelStore *store, const char *old_name, const char * char *key; CamelFolder *folder; + if (strcmp(old_name, new_name) == 0) + return; + CAMEL_STORE_LOCK(store, folder_lock); + CS_CLASS (store)->rename_folder (store, old_name, new_name, ex); /* remove the old name from the cache if it is there */ CAMEL_STORE_LOCK(store, cache_lock); - if (g_hash_table_lookup_extended(store->folders, old_name, &key, (void **)&folder)) { + if (g_hash_table_lookup_extended(store->folders, old_name, (void **)&key, (void **)&folder)) { g_hash_table_remove(store->folders, key); g_free(key); } CAMEL_STORE_UNLOCK(store, cache_lock); - CS_CLASS (store)->rename_folder (store, old_name, new_name, ex); CAMEL_STORE_UNLOCK(store, folder_lock); } @@ -406,6 +415,9 @@ trash_finalize (CamelObject *trash, gpointer event_data, gpointer user_data) static void init_trash (CamelStore *store) { + if ((store->flags & CAMEL_STORE_VTRASH) == 0) + return; + store->vtrash = camel_vtrash_folder_new (store, CAMEL_VTRASH_NAME); if (store->vtrash) { @@ -455,6 +467,9 @@ CamelFolder * camel_store_get_trash (CamelStore *store, CamelException *ex) { CamelFolder *folder; + + if ((store->flags & CAMEL_STORE_VTRASH) == 0) + return NULL; CAMEL_STORE_LOCK(store, folder_lock); folder = CS_CLASS (store)->get_trash (store, ex); diff --git a/camel/camel-store.h b/camel/camel-store.h index 02ceb5747c..6983524091 100644 --- a/camel/camel-store.h +++ b/camel/camel-store.h @@ -54,7 +54,8 @@ typedef struct _CamelFolderInfo { /* Flags for store flags */ -#define CAMEL_STORE_SUBSCRIPTIONS (1 << 0) +#define CAMEL_STORE_SUBSCRIPTIONS (1 << 0) +#define CAMEL_STORE_VTRASH (1 << 1) struct _CamelStore { diff --git a/camel/camel-vee-folder.c b/camel/camel-vee-folder.c index fde38fa1d5..e2e224da92 100644 --- a/camel/camel-vee-folder.c +++ b/camel/camel-vee-folder.c @@ -194,14 +194,10 @@ vee_folder_construct (CamelVeeFolder *vf, CamelStore *parent_store, const char * vf->flags = flags; - tmp = strchr(name, '?'); - if (tmp) { - vf->vname = g_strndup(name, tmp-name); - vf->expression = g_strdup(tmp+1); - } else { - vf->vname = g_strdup(name); - } + /* We dont support ? syntax anymore */ + g_assert(strchr(name, '?') == NULL); + vf->vname = g_strdup(name); tmp = strrchr(vf->vname, '/'); if (tmp) tmp++; @@ -247,7 +243,6 @@ CamelFolder * camel_vee_folder_new(CamelStore *parent_store, const char *name, guint32 flags) { CamelVeeFolder *vf; - char *path, *query; UNMATCHED_LOCK(); @@ -261,13 +256,7 @@ camel_vee_folder_new(CamelStore *parent_store, const char *name, guint32 flags) UNMATCHED_UNLOCK(); - path = alloca(strlen(name)+1); - strcpy(path, name); - query = strchr(path, '?'); - if (query) - *query++ = 0; - - if (strcmp(path, "UNMATCHED") == 0) { + if (strcmp(name, "UNMATCHED") == 0) { camel_object_ref((CamelObject *)folder_unmatched); printf("returning unmatched %p, count = %d\n", folder_unmatched, camel_folder_get_message_count((CamelFolder *)folder_unmatched)); return (CamelFolder *)folder_unmatched; @@ -289,6 +278,17 @@ camel_vee_folder_set_expression(CamelVeeFolder *vf, const char *query) CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock); + /* no change, do nothing */ + if ((vf->expression && query && strcmp(vf->expression, query) == 0) + || (vf->expression == NULL && query == NULL)) { + CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock); + return; + } + + g_free(vf->expression); + if (query) + vf->expression = g_strdup(query); + node = p->folders; while (node) { CamelFolder *f = node->data; @@ -372,6 +372,54 @@ camel_vee_folder_remove_folder(CamelVeeFolder *vf, CamelFolder *sub) camel_object_unref((CamelObject *)sub); } +static void +remove_folders(CamelFolder *folder, CamelFolder *foldercopy, CamelVeeFolder *vf) +{ + camel_vee_folder_remove_folder(vf, folder); + camel_object_unref((CamelObject *)folder); +} + +/** + * camel_vee_folder_set_folders: + * @vf: + * @folders: + * + * Set the whole list of folder sources on a vee folder. + **/ +void +camel_vee_folder_set_folders(CamelVeeFolder *vf, GList *folders) +{ + GHashTable *remove = g_hash_table_new(NULL, NULL); + GList *l; + CamelFolder *folder; + + /* setup a table of all folders we have currently */ + CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock); + l = vf->priv->folders; + while (l) { + g_hash_table_insert(remove, l->data, l->data); + camel_object_ref((CamelObject *)l->data); + l = l->next; + } + CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock); + + /* if we already have the folder, ignore it, otherwise add it */ + l = folders; + while (l) { + if ((folder = g_hash_table_lookup(remove, l->data))) { + g_hash_table_remove(remove, folder); + camel_object_unref((CamelObject *)folder); + } else { + camel_vee_folder_add_folder(vf, l->data); + } + l = l->next; + } + + /* then remove any we still have */ + g_hash_table_foreach(remove, (GHFunc)remove_folders, vf); + g_hash_table_destroy(remove); +} + /** * camel_vee_folder_hash_folder: * @folder: @@ -750,9 +798,14 @@ vee_folder_build_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException if (vf == folder_unmatched) return 0; - match = camel_folder_search_by_expression(f, vf->expression, ex); - if (match == NULL) - return -1; + /* if we have no expression, or its been cleared, then act as if no matches */ + if (vf->expression == NULL) { + match = g_ptr_array_new(); + } else { + match = camel_folder_search_by_expression(f, vf->expression, ex); + if (match == NULL) + return -1; + } u.source = source; u.vf = vf; @@ -847,7 +900,11 @@ vee_folder_build_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException g_hash_table_destroy(matchhash); g_hash_table_destroy(allhash); - camel_folder_search_free(f, match); + /* if expression not set, we only had a null list */ + if (vf->expression == NULL) + g_ptr_array_free(match, TRUE); + else + camel_folder_search_free(f, match); camel_folder_free_uids(f, all); if (unmatched_changes) { diff --git a/camel/camel-vee-folder.h b/camel/camel-vee-folder.h index 8c7deb6e41..83705751c7 100644 --- a/camel/camel-vee-folder.h +++ b/camel/camel-vee-folder.h @@ -62,6 +62,7 @@ void camel_vee_folder_construct (CamelVeeFolder *vf, CamelStore *parent void camel_vee_folder_add_folder (CamelVeeFolder *vf, CamelFolder *sub); void camel_vee_folder_remove_folder (CamelVeeFolder *vf, CamelFolder *sub); +void camel_vee_folder_set_folders (CamelVeeFolder *vf, GList *folders); void camel_vee_folder_set_expression (CamelVeeFolder *vf, const char *expr); void camel_vee_folder_hash_folder (CamelFolder *folder, char buffer[8]); diff --git a/camel/camel-vee-store.c b/camel/camel-vee-store.c index 2d44b456d5..f5de80fd56 100644 --- a/camel/camel-vee-store.c +++ b/camel/camel-vee-store.c @@ -19,15 +19,22 @@ * USA */ +#include "camel-exception.h" #include "camel-vee-store.h" #include "camel-vee-folder.h" +#include "camel-private.h" + #include static CamelFolder *vee_get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex); +static void vee_delete_folder(CamelStore *store, const char *folder_name, CamelException *ex); +static void vee_rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex); static void vee_init_trash (CamelStore *store); static CamelFolder *vee_get_trash (CamelStore *store, CamelException *ex); +static CamelFolderInfo *vee_get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex); + struct _CamelVeeStorePrivate { CamelFolderInfo *folder_info; }; @@ -67,6 +74,11 @@ camel_vee_store_class_init (CamelVeeStoreClass *klass) /* virtual method overload */ store_class->get_folder = vee_get_folder; + store_class->rename_folder = vee_rename_folder; + store_class->delete_folder = vee_delete_folder; + store_class->get_folder_info = vee_get_folder_info; + store_class->free_folder_info = camel_store_free_folder_info_full; + store_class->init_trash = vee_init_trash; store_class->get_trash = vee_get_trash; } @@ -75,6 +87,10 @@ static void camel_vee_store_init (CamelVeeStore *obj) { struct _CamelVeeStorePrivate *p; + CamelStore *store = (CamelStore *)obj; + + /* we dont want a vtrash on this one */ + store->flags &= ~(CAMEL_STORE_VTRASH); p = _PRIVATE(obj) = g_malloc0(sizeof(*p)); } @@ -138,3 +154,158 @@ vee_get_trash (CamelStore *store, CamelException *ex) { return NULL; } + +struct _build_info { + const char *top; + guint32 flags; + GPtrArray *infos; +}; + +static void +build_info(char *name, CamelVeeFolder *folder, struct _build_info *data) +{ + CamelFolderInfo *info; + + /* check we have to include this one */ + if (data->top) { + if (data->flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) { + if (strncmp(name, data->top, strlen(data->top) != 0)) + return; + } else { + if (strcmp(name, data->top)) + return; + } + } else { + if ((data->flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) == 0) { + if (strchr(name, '/')) + return; + } + } + + info = g_malloc0(sizeof(*info)); + info->url = g_strdup_printf("vfolder:%s#%s", ((CamelService *)((CamelFolder *)folder)->parent_store)->url->path, + ((CamelFolder *)folder)->full_name); + info->full_name = g_strdup(((CamelFolder *)folder)->full_name); + info->name = g_strdup(((CamelFolder *)folder)->name); + info->unread_message_count = camel_folder_get_unread_message_count((CamelFolder *)folder); + g_ptr_array_add(data->infos, info); +} + +static CamelFolderInfo * +vee_get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex) +{ + struct _build_info data; + CamelFolderInfo *info; + + /* first, build the info list */ + data.top = top; + data.flags = flags; + data.infos = g_ptr_array_new(); + CAMEL_STORE_LOCK(store, cache_lock); + g_hash_table_foreach(store->folders, (GHFunc)build_info, &data); + CAMEL_STORE_UNLOCK(store, cache_lock); + + /* and always add UNMATCHED, if scanning from top/etc */ + if (top == NULL || top[0] == 0 || strncmp(top, "UNMATCHED", strlen("UNMATCHED")) == 0) { + info = g_malloc0(sizeof(*info)); + info->url = g_strdup_printf("vfolder:%s#UNMATCHED", ((CamelService *)store)->url->path); + info->full_name = g_strdup("UNMATCHED"); + info->name = g_strdup("UNMATCHED"); + info->unread_message_count = -1; + g_ptr_array_add(data.infos, info); + } + + /* convert it into a tree */ + info = camel_folder_info_build(data.infos, (top&&top[0])?top:"", '/', TRUE); + g_ptr_array_free(data.infos, TRUE); + + return info; +} + +static void +vee_delete_folder(CamelStore *store, const char *folder_name, CamelException *ex) +{ + CamelFolder *folder; + char *key; + + if (strcmp(folder_name, "UNMATCHED") == 0) { + camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, + _("Cannot delete folder: %s: Invalid operation"), folder_name); + return; + } + + CAMEL_STORE_LOCK(store, cache_lock); + if (g_hash_table_lookup_extended(store->folders, folder_name, (void **)&key, (void **)&folder)) { + int update; + + update = (((CamelVeeFolder *)folder)->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0; + g_hash_table_remove(store->folders, key); + CAMEL_STORE_UNLOCK(store, cache_lock); + if (store->vtrash) + camel_vee_folder_remove_folder((CamelVeeFolder *)store->vtrash, folder); + + /* FIXME: deleted event shoudl just pass out the folder name, not all this shit?? */ + if (update) { + CamelFolderInfo *fi = g_malloc0(sizeof(*fi)); + + fi->full_name = g_strdup(key); + fi->name = strrchr(key, '/'); + if (fi->name == NULL) + fi->name = g_strdup(key); + else + fi->name = g_strdup(fi->name); + fi->url = g_strdup_printf("vfolder:%s#%s", ((CamelService *)store)->url->path, key); + fi->unread_message_count = -1; + + camel_object_trigger_event(CAMEL_OBJECT(store), "folder_deleted", fi); + camel_folder_info_free(fi); + } + g_free(key); + } else { + CAMEL_STORE_UNLOCK(store, cache_lock); + + camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, + _("Cannot delete folder: %s: No such folder"), folder_name); + } +} + +static void +vee_rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex) +{ + CamelFolder *folder; + char *key, *oldname, *full_oldname; + + if (strcmp(old, "UNMATCHED") == 0) { + camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, + _("Cannot rename folder: %s: Invalid operation"), old); + return; + } + + CAMEL_STORE_LOCK(store, cache_lock); + if (g_hash_table_lookup_extended(store->folders, old, (void **)&key, (void **)&folder)) { + g_hash_table_remove(store->folders, key); + g_free(key); + + /* this should really be atomic */ + oldname = folder->name; + full_oldname = folder->full_name; + key = folder->name; + folder->full_name = g_strdup(new); + key = strrchr(new, '/'); + key = key?key+1:(char *)new; + folder->name = g_strdup(key); + g_hash_table_insert(store->folders, g_strdup(new), folder); + + g_free(oldname); + g_free(full_oldname); + CAMEL_STORE_UNLOCK(store, cache_lock); + + + } else { + CAMEL_STORE_UNLOCK(store, cache_lock); + + camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, + _("Cannot rename folder: %s: No such folder"), new); + } +} + diff --git a/camel/camel-vtrash-folder.c b/camel/camel-vtrash-folder.c index d76c9f851c..be662022f6 100644 --- a/camel/camel-vtrash-folder.c +++ b/camel/camel-vtrash-folder.c @@ -83,15 +83,12 @@ CamelFolder * camel_vtrash_folder_new (CamelStore *parent_store, const char *name) { CamelFolder *vtrash; - char *vtrash_name; - guint32 flags; vtrash = (CamelFolder *)camel_object_new (camel_vtrash_folder_get_type ()); - vtrash_name = g_strdup_printf ("%s?(match-all (system-flag \"Deleted\"))", name); - flags = CAMEL_STORE_FOLDER_PRIVATE | CAMEL_STORE_FOLDER_CREATE | CAMEL_STORE_VEE_FOLDER_AUTO; - - camel_vee_folder_construct (CAMEL_VEE_FOLDER (vtrash), parent_store, vtrash_name, flags); - + camel_vee_folder_construct (CAMEL_VEE_FOLDER (vtrash), parent_store, name, + CAMEL_STORE_FOLDER_PRIVATE | CAMEL_STORE_FOLDER_CREATE | CAMEL_STORE_VEE_FOLDER_AUTO); + camel_vee_folder_set_expression((CamelVeeFolder *)vtrash, "(match-all (system-flag \"Deleted\"))"); + return vtrash; } -- cgit v1.2.3