From c4d87ba45ad016d5a6607df96ed27ba02910e2e6 Mon Sep 17 00:00:00 2001 From: 7 Date: Sat, 27 Oct 2001 06:00:34 +0000 Subject: Finished implementation. 2001-10-27 * providers/imap/camel-imap-store.c (rename_folder): Finished implementation. * providers/local/camel-local-folder.c (local_rename): Implement local rename of folder objects. 2001-10-26 * camel-vee-folder.c (camel_vee_folder_class_init): Hook into rename function. (vee_rename): Implement the veefolder rename function. (camel_vee_folder_class_init): (folder_changed_change): Kill a warning with a cast. * camel-vee-store.c (vee_rename_folder): Emit a folder_renamed event properly, also call parent to do some rename stuff. * camel-store.h: Added a CamelRenameInfo for the rename event. * camel-folder.c (camel_folder_rename): New function to rename a folder object. (camel_folder_class_init): Added a renamed event. (folder_rename): Default impl, set full_name, and set name assuming the dir separator is '/'. * camel-store.c (camel_store_class_init): Added folder_renamed event. (camel_store_rename_folder): Rename an active folder object if we have one, and update the folder table. (rename_folder): Make a default implementation that handles updating the folder tree. svn path=/trunk/; revision=14204 --- camel/ChangeLog | 34 ++++++++++ camel/camel-folder.c | 69 ++++++++++++++------ camel/camel-folder.h | 2 + camel/camel-store.c | 100 +++++++++++++++++++++++------ camel/camel-store.h | 5 ++ camel/camel-vee-folder.c | 15 ++++- camel/camel-vee-store.c | 34 +++------- camel/providers/imap/camel-imap-store.c | 23 +------ camel/providers/local/camel-local-folder.c | 28 ++++++++ 9 files changed, 227 insertions(+), 83 deletions(-) diff --git a/camel/ChangeLog b/camel/ChangeLog index 92e89a5c55..6776cb0b34 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,37 @@ +2001-10-27 + + * providers/imap/camel-imap-store.c (rename_folder): Finished + implementation. + + * providers/local/camel-local-folder.c (local_rename): Implement + local rename of folder objects. + +2001-10-26 + + * camel-vee-folder.c (camel_vee_folder_class_init): Hook into + rename function. + (vee_rename): Implement the veefolder rename function. + (camel_vee_folder_class_init): + (folder_changed_change): Kill a warning with a cast. + + * camel-vee-store.c (vee_rename_folder): Emit a folder_renamed + event properly, also call parent to do some rename stuff. + + * camel-store.h: Added a CamelRenameInfo for the rename event. + + * camel-folder.c (camel_folder_rename): New function to rename a + folder object. + (camel_folder_class_init): Added a renamed event. + (folder_rename): Default impl, set full_name, and set name + assuming the dir separator is '/'. + + * camel-store.c (camel_store_class_init): Added folder_renamed + event. + (camel_store_rename_folder): Rename an active folder object if we + have one, and update the folder table. + (rename_folder): Make a default implementation that handles + updating the folder tree. + 2001-10-26 Jeffrey Stedfast * providers/imap/camel-imap-store.c (delete_folder): Don't bother diff --git a/camel/camel-folder.c b/camel/camel-folder.c index f28572f8ba..9bc38df846 100644 --- a/camel/camel-folder.c +++ b/camel/camel-folder.c @@ -87,29 +87,21 @@ static GPtrArray *get_summary (CamelFolder *folder); static void free_summary (CamelFolder *folder, GPtrArray *array); -static CamelMimeMessage *get_message (CamelFolder *folder, - const gchar *uid, - CamelException *ex); +static CamelMimeMessage *get_message (CamelFolder *folder, const gchar *uid, CamelException *ex); -static CamelMessageInfo *get_message_info (CamelFolder *folder, const char *uid); -static void free_message_info (CamelFolder *folder, CamelMessageInfo *info); -static void ref_message_info (CamelFolder *folder, CamelMessageInfo *info); +static CamelMessageInfo *get_message_info (CamelFolder *folder, const char *uid); +static void free_message_info (CamelFolder *folder, CamelMessageInfo *info); +static void ref_message_info (CamelFolder *folder, CamelMessageInfo *info); static GPtrArray *search_by_expression (CamelFolder *folder, const char *exp, CamelException *ex); static GPtrArray *search_by_uids (CamelFolder *folder, const char *exp, GPtrArray *uids, CamelException *ex); static void search_free (CamelFolder * folder, GPtrArray *result); -static void copy_messages_to (CamelFolder *source, - GPtrArray *uids, - CamelFolder *dest, - CamelException *ex); +static void copy_messages_to (CamelFolder *source, GPtrArray *uids, CamelFolder *dest, CamelException *ex); +static void move_messages_to (CamelFolder *source, GPtrArray *uids, CamelFolder *dest, CamelException *ex); -static void move_messages_to (CamelFolder *source, - GPtrArray *uids, - CamelFolder *dest, - CamelException *ex); - -static void delete (CamelFolder *folder); +static void delete (CamelFolder *folder); +static void folder_rename (CamelFolder *folder, const char *new); static void freeze (CamelFolder *folder); static void thaw (CamelFolder *folder); @@ -159,6 +151,7 @@ camel_folder_class_init (CamelFolderClass *camel_folder_class) camel_folder_class->copy_messages_to = copy_messages_to; camel_folder_class->move_messages_to = move_messages_to; camel_folder_class->delete = delete; + camel_folder_class->rename = folder_rename; camel_folder_class->freeze = freeze; camel_folder_class->thaw = thaw; camel_folder_class->is_frozen = is_frozen; @@ -169,6 +162,7 @@ camel_folder_class_init (CamelFolderClass *camel_folder_class) camel_object_class_declare_event (camel_object_class, "message_changed", message_changed); camel_object_class_declare_event (camel_object_class, "deleted", NULL); + camel_object_class_declare_event (camel_object_class, "renamed", NULL); } static void @@ -1324,7 +1318,7 @@ delete (CamelFolder *folder) * camel_folder_delete: * @folder: folder * - * Marks a folder as deleted and performs any required cleanup. + * Marks a folder object as deleted and performs any required cleanup. **/ void camel_folder_delete (CamelFolder *folder) @@ -1340,12 +1334,49 @@ camel_folder_delete (CamelFolder *folder) folder->folder_flags |= CAMEL_FOLDER_HAS_BEEN_DELETED; CF_CLASS (folder)->delete (folder); - + CAMEL_FOLDER_UNLOCK (folder, lock); - + camel_object_trigger_event (CAMEL_OBJECT (folder), "deleted", NULL); } +static void +folder_rename (CamelFolder *folder, const char *new) +{ + char *tmp; + + printf("CamelFolder:rename('%s')\n", new); + + g_free(folder->full_name); + folder->full_name = g_strdup(new); + g_free(folder->name); + tmp = strrchr(new, '/'); + folder->name = g_strdup(tmp?tmp+1:new); +} + +/** + * camel_folder_rename: + * @folder: + * @new: + * + * Mark an active folder object as renamed. + * + * NOTE: This is an internal function used by camel stores, no locking + * is performed on the folder. + **/ +void +camel_folder_rename(CamelFolder *folder, const char *new) +{ + char *old; + + old = g_strdup(folder->full_name); + + CF_CLASS (folder)->rename(folder, new); + + camel_object_trigger_event (CAMEL_OBJECT (folder), "renamed", old); + g_free(old); +} + static void freeze (CamelFolder *folder) { diff --git a/camel/camel-folder.h b/camel/camel-folder.h index 22398b6436..4ba36e9d03 100644 --- a/camel/camel-folder.h +++ b/camel/camel-folder.h @@ -156,6 +156,7 @@ typedef struct { CamelException *ex); void (*delete) (CamelFolder *folder); + void (*rename) (CamelFolder *folder, const char *newname); void (*freeze) (CamelFolder *folder); void (*thaw) (CamelFolder *folder); @@ -273,6 +274,7 @@ void camel_folder_move_messages_to (CamelFolder *source, CamelException *ex); void camel_folder_delete (CamelFolder *folder); +void camel_folder_rename (CamelFolder *folder, const char *new); /* stop/restart getting events */ void camel_folder_freeze (CamelFolder *folder); diff --git a/camel/camel-store.c b/camel/camel-store.c index 85f618be5b..f4b15a045c 100644 --- a/camel/camel-store.c +++ b/camel/camel-store.c @@ -104,6 +104,7 @@ camel_store_class_init (CamelStoreClass *camel_store_class) camel_object_class_declare_event(camel_object_class, "folder_created", NULL); camel_object_class_declare_event(camel_object_class, "folder_deleted", NULL); + camel_object_class_declare_event(camel_object_class, "folder_renamed", NULL); camel_object_class_declare_event(camel_object_class, "folder_subscribed", NULL); camel_object_class_declare_event(camel_object_class, "folder_unsubscribed", NULL); } @@ -267,7 +268,6 @@ camel_store_get_folder (CamelStore *store, const char *folder_name, guint32 flag return folder; } - static CamelFolderInfo * create_folder (CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex) @@ -365,15 +365,32 @@ camel_store_delete_folder (CamelStore *store, const char *folder_name, CamelExce CAMEL_STORE_UNLOCK(store, folder_lock); } - 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, CamelException *ex) { w(g_warning ("CamelStore::rename_folder not implemented for `%s'", camel_type_to_name (CAMEL_OBJECT_GET_TYPE (store)))); } +struct _get_info { + CamelStore *store; + GPtrArray *folders; + const char *old; + const char *new; +}; + +static void +get_subfolders(char *key, CamelFolder *folder, struct _get_info *info) +{ + /* If this is a subfolder of the one to be renamed, we need to get it, AND lock it */ + if (strncmp(folder->full_name, info->old, strlen(info->old)) == 0) { + d(printf("Found subfolder of '%s' == '%s'\n", info->old, folder->full_name)); + camel_object_ref((CamelObject *)folder); + g_ptr_array_add(info->folders, folder); + CAMEL_FOLDER_LOCK(folder, lock); + } +} + /** * camel_store_rename_folder: * @store: a CamelStore @@ -387,32 +404,79 @@ void camel_store_rename_folder (CamelStore *store, const char *old_name, const char *new_name, CamelException *ex) { char *key; - CamelFolder *folder; + CamelFolder *folder, *oldfolder; + struct _get_info info = { store, NULL, old_name, new_name }; + int i; + + printf("store rename folder '%s' '%s'\n", old_name, new_name); if (strcmp(old_name, new_name) == 0) return; + info.folders = g_ptr_array_new(); + CAMEL_STORE_LOCK(store, folder_lock); + + /* If the folder is open (or any subfolders of the open folder) + We need to rename them atomically with renaming the actual folder path */ + if (store->folders) { + CAMEL_STORE_LOCK(store, cache_lock); + /* Get all subfolders that are about to have their name changed */ + g_hash_table_foreach(store->folders, (GHFunc)get_subfolders, &info); + CAMEL_STORE_UNLOCK(store, cache_lock); + } + + /* Now try the real rename (will emit renamed event) */ 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, (void **)&key, (void **)&folder)) { - g_hash_table_remove(store->folders, key); - g_free(key); - - camel_object_ref (CAMEL_OBJECT (folder)); + + /* If it worked, update all open folders/unlock them */ + if (!camel_exception_is_set(ex)) { + guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE; + CamelRenameInfo reninfo; + + /* Emit changed signal */ + if (store->flags & CAMEL_STORE_SUBSCRIPTIONS) + flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED; + reninfo.old_base = (char *)old_name; + reninfo.new = ((CamelStoreClass *)((CamelObject *)store)->classfuncs)->get_folder_info(store, new_name, flags, ex); + if (info.new != NULL) { + camel_object_trigger_event(CAMEL_OBJECT(store), "folder_renamed", &reninfo); + ((CamelStoreClass *)((CamelObject *)store)->classfuncs)->free_folder_info(store, reninfo.new); + } + + CAMEL_STORE_LOCK(store, cache_lock); + for (i=0;ilen;i++) { + char *new; + + folder = info.folders->pdata[i]; + + new = g_strdup_printf("%s%s", new_name, folder->full_name+strlen(old_name)); + + if (g_hash_table_lookup_extended(store->folders, folder->full_name, (void **)&key, (void **)&oldfolder)) { + g_hash_table_remove(store->folders, key); + g_free(key); + g_hash_table_insert(store->folders, new, oldfolder); + } + + camel_folder_rename(folder, new); + + CAMEL_FOLDER_UNLOCK(folder, lock); + camel_object_unref((CamelObject *)folder); + } CAMEL_STORE_UNLOCK(store, cache_lock); - - if (store->vtrash) - camel_vee_folder_remove_folder (CAMEL_VEE_FOLDER (store->vtrash), folder); - camel_object_unref (CAMEL_OBJECT (folder)); } else { - CAMEL_STORE_UNLOCK(store, cache_lock); + /* Failed, just unlock our folders for re-use */ + for (i=0;ilen;i++) { + folder = info.folders->pdata[i]; + CAMEL_FOLDER_UNLOCK(folder, lock); + camel_object_unref((CamelObject *)folder); + } } CAMEL_STORE_UNLOCK(store, folder_lock); + + g_ptr_array_free(info.folders, TRUE); } diff --git a/camel/camel-store.h b/camel/camel-store.h index df69505e62..157bc196a0 100644 --- a/camel/camel-store.h +++ b/camel/camel-store.h @@ -51,6 +51,11 @@ typedef struct _CamelFolderInfo { int unread_message_count; } CamelFolderInfo; +/* Structure of rename event's event_data */ +typedef struct _CamelRenameInfo { + char *old_base; + struct _CamelFolderInfo *new; +} CamelRenameInfo; #define CAMEL_STORE_TYPE (camel_store_get_type ()) #define CAMEL_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_STORE_TYPE, CamelStore)) diff --git a/camel/camel-vee-folder.c b/camel/camel-vee-folder.c index 7e31e94cb9..dccc76c369 100644 --- a/camel/camel-vee-folder.c +++ b/camel/camel-vee-folder.c @@ -62,6 +62,7 @@ static GPtrArray *vee_search_by_uids(CamelFolder *folder, const char *expression static void vee_set_message_flags (CamelFolder *folder, const char *uid, guint32 flags, guint32 set); static void vee_set_message_user_flag (CamelFolder *folder, const char *uid, const char *name, gboolean value); +static void vee_rename(CamelFolder *folder, const char *new); static void camel_vee_folder_class_init (CamelVeeFolderClass *klass); static void camel_vee_folder_init (CamelVeeFolder *obj); @@ -130,6 +131,8 @@ camel_vee_folder_class_init (CamelVeeFolderClass *klass) folder_class->set_message_flags = vee_set_message_flags; folder_class->set_message_user_flag = vee_set_message_user_flag; + + folder_class->rename = vee_rename; } static void @@ -749,6 +752,16 @@ vee_move_messages_to (CamelFolder *folder, GPtrArray *uids, CamelFolder *dest, C } } +static void vee_rename(CamelFolder *folder, const char *new) +{ + CamelVeeFolder *vf = (CamelVeeFolder *)folder; + + g_free(vf->vname); + vf->vname = g_strdup(new); + + ((CamelFolderClass *)camel_vee_folder_parent)->rename(folder, new); +} + /* ********************************************************************** * utility functions */ @@ -1320,7 +1333,7 @@ folder_changed_change(CamelSession *session, CamelSessionThreadMsg *msg) strcpy(vuid+8, uid); vinfo = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, vuid); if (vinfo == NULL) - g_ptr_array_add(newchanged, uid); + g_ptr_array_add(newchanged, (char *)uid); else camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)vinfo); } diff --git a/camel/camel-vee-store.c b/camel/camel-vee-store.c index 4530c34ee2..1d9a5c61d4 100644 --- a/camel/camel-vee-store.c +++ b/camel/camel-vee-store.c @@ -27,6 +27,8 @@ #include +#define d(x) + 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); @@ -290,7 +292,8 @@ static void vee_rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex) { CamelFolder *folder; - char *key, *oldname, *full_oldname; + + d(printf("vee rename folder '%s' '%s'\n", old, new)); if (strcmp(old, CAMEL_UNMATCHED_NAME) == 0) { camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, @@ -298,31 +301,12 @@ vee_rename_folder(CamelStore *store, const char *old, const char *new, CamelExce return; } + /* See if it exists, for vfolders, all folders are in the folders hash */ 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); - + if ((folder = g_hash_table_lookup(store->folders, old)) == NULL) { camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Cannot rename folder: %s: No such folder"), new); + _("Cannot rename folder: %s: No such folder"), old); } -} + CAMEL_STORE_UNLOCK(store, cache_lock); +} diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c index 32899b20e5..1fea5a27b9 100644 --- a/camel/providers/imap/camel-imap-store.c +++ b/camel/providers/imap/camel-imap-store.c @@ -1103,18 +1103,11 @@ static void rename_folder (CamelStore *store, const char *old_name, const char *new_name, CamelException *ex) { CamelImapStore *imap_store = CAMEL_IMAP_STORE (store); - CamelFolderInfo *old_fi, *new_fi; CamelImapResponse *response; - + if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex)) return; - old_fi = get_folder_info_online (store, old_name, CAMEL_STORE_FOLDER_INFO_FAST | - CAMEL_STORE_FOLDER_INFO_RECURSIVE, ex); - - if (old_fi == NULL) - return; - /* make sure this folder isn't currently SELECTed - it's actually possible to rename INBOX but if you do another INBOX will immediately be created by the server */ @@ -1129,20 +1122,10 @@ rename_folder (CamelStore *store, const char *old_name, const char *new_name, Ca } else return; - response = camel_imap_command (imap_store, NULL, ex, "RENAME %F %F", - old_name, new_name); + response = camel_imap_command(imap_store, NULL, ex, "RENAME %F %F", old_name, new_name); - if (response) { + if (response) camel_imap_response_free (imap_store, response); - - new_fi = get_folder_info_online (store, new_name, CAMEL_STORE_FOLDER_INFO_FAST | - CAMEL_STORE_FOLDER_INFO_RECURSIVE, ex); - - if (new_fi == NULL) - return; - - /* emit the renamed event */ - } } static CamelFolderInfo * diff --git a/camel/providers/local/camel-local-folder.c b/camel/providers/local/camel-local-folder.c index cc4a703006..985081a266 100644 --- a/camel/providers/local/camel-local-folder.c +++ b/camel/providers/local/camel-local-folder.c @@ -65,6 +65,8 @@ static GPtrArray *local_search_by_expression(CamelFolder *folder, const char *ex static GPtrArray *local_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex); static void local_search_free(CamelFolder *folder, GPtrArray * result); +static void local_rename(CamelFolder *folder, const char *newname); + static void local_finalize(CamelObject * object); static void @@ -84,6 +86,8 @@ camel_local_folder_class_init(CamelLocalFolderClass * camel_local_folder_class) camel_folder_class->search_by_uids = local_search_by_uids; camel_folder_class->search_free = local_search_free; + camel_folder_class->rename = local_rename; + camel_local_folder_class->lock = local_lock; camel_local_folder_class->unlock = local_unlock; } @@ -308,6 +312,30 @@ local_expunge(CamelFolder *folder, CamelException *ex) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, TRUE, ex); } +static void +local_rename(CamelFolder *folder, const char *newname) +{ + CamelLocalFolder *lf = (CamelLocalFolder *)folder; + + d(printf("renaming local folder paths to '%s'\n", newname)); + + /* Sync? */ + + g_free(lf->folder_path); + g_free(lf->summary_path); + g_free(lf->index_path); + lf->folder_path = g_strdup_printf("%s/%s", lf->base_path, newname); + lf->summary_path = g_strdup_printf("%s/%s.ev-summary", lf->base_path, newname); + lf->index_path = g_strdup_printf("%s/%s.ibex", lf->base_path, newname); + + /* FIXME: Poke some internals, sigh */ + camel_folder_summary_set_filename(folder->summary, lf->summary_path); + g_free(((CamelLocalSummary *)folder->summary)->folder_path); + ((CamelLocalSummary *)folder->summary)->folder_path = g_strdup(lf->folder_path); + + parent_class->rename(folder, newname); +} + static GPtrArray * local_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex) { -- cgit v1.2.3