/* * $Id: $ */ /* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: */ /* * Virtual folder plugin for claws-mail * * Claws Mail is Copyright (C) 1999-2012 by the Claws Mail Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * 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, see . * */ #ifdef HAVE_CONFIG_H # include #endif #include #include "procmsg.h" #include "procheader.h" #include "folder.h" #include "alertpanel.h" #include "main.h" #include "localfolder.h" #include "statusbar.h" #include "vfolder.h" #include "vfolder_gtk.h" #include "vfolder_prop.h" typedef struct { LocalFolder folder; } VFolder; FolderClass vfolder_class; static gboolean existing_tree_found = FALSE; static GList* vfolders = NULL; static void vfolder_get_last_num(Folder *folder, FolderItem *item) { gchar *path; DIR *dp; struct dirent *d; gint max = 0; gint num; g_return_if_fail(item != NULL); debug_print("vfolder_get_last_num(): Scanning %s ...\n", item->path); path = folder_item_get_path(item); g_return_if_fail(path != NULL); if( change_dir(path) < 0 ) { g_free(path); return; } g_free(path); if( (dp = opendir(".")) == NULL ) { FILE_OP_ERROR(item->path, "opendir"); return; } while( (d = readdir(dp)) != NULL ) { if( (num = to_number(d->d_name)) > 0 && dirent_is_regular_file(d) ) { if( max < num ) max = num; } } closedir(dp); debug_print("Last number in dir %s = %d\n", item->path, max); item->last_num = max; } static void vfolder_init_read_func(FolderItem* item, gpointer data) { g_return_if_fail(item != NULL); if (! IS_VFOLDER_FOLDER_ITEM(item)) return; existing_tree_found = TRUE; if (folder_item_parent(item) == NULL) return; vfolder_folder_item_props_read(VFOLDER_ITEM(item)); vfolder_set_msgs_filter(VFOLDER_ITEM(item)); /* if (! IS_VFOLDER_FROZEN(VFOLDER_ITEM(item))) { folder_item_scan(VFOLDER_ITEM(item)->source); }*/ } static void vfolder_make_rc_dir(void) { gchar* vfolder_dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, VFOLDER_DIR, NULL); if (! is_dir_exist(vfolder_dir)) { if (make_dir(vfolder_dir) < 0) { g_warning("couldn't create directory %s\n", vfolder_dir); } debug_print("created directorty %s\n", vfolder_dir); } g_free(vfolder_dir); } static void vfolder_create_default_mailbox(void) { Folder* root = NULL; vfolder_make_rc_dir(); root = folder_new(vfolder_folder_get_class(), VFOLDER_DEFAULT_MAILBOX, NULL); g_return_if_fail(root != NULL); folder_add(root); } static gboolean vfolder_scan_required(Folder* folder, FolderItem* item) { return TRUE; } static Folder* vfolder_new_folder(const gchar* name, const gchar* path) { VFolder* folder; debug_print("VFolder: new_folder\n"); vfolder_make_rc_dir(); folder = g_new0(VFolder, 1); FOLDER(folder)->klass = &vfolder_class; folder_init(FOLDER(folder), name); return FOLDER(folder); } static void vfolder_destroy_folder(Folder* _folder) { VFolder* folder = VFOLDER(_folder); folder_local_folder_destroy(LOCAL_FOLDER(folder)); } static gint vfolder_remove_folder(Folder* folder, FolderItem* item) { GDir* dp; const gchar* name; gchar* cwd; gint ret = -1; g_return_val_if_fail(folder != NULL, -1); g_return_val_if_fail(item != NULL, -1); g_return_val_if_fail(item->path != NULL, -1); g_return_val_if_fail(item->stype == F_NORMAL, -1); debug_print("VFolder: removing folder item %s\n", item->path); gchar* path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, VFOLDER_DIR, G_DIR_SEPARATOR_S, item->name, NULL); remove_numbered_files(path, item->last_num - item->total_msgs + 1, item->last_num); folder_item_remove(item); cwd = g_get_current_dir(); if (change_dir(path) < 0 ) { g_free(path); return ret; } if( (dp = g_dir_open(".", 0, NULL)) == NULL ) { FILE_OP_ERROR(path, "g_dir_open"); change_dir(cwd); g_free(cwd); return ret; } while ((name = g_dir_read_name(dp)) != NULL) { debug_print("Removing: %s\n", name); claws_unlink(name); } g_dir_close(dp); change_dir(cwd); if (g_rmdir(path) == 0) ret = 0; g_free(cwd); g_free(path); return ret; } static void vfolder_remove_hashtables(VFolderItem* item) { if (item->me_to_claws) { g_hash_table_destroy(item->me_to_claws); item->me_to_claws = NULL; } if (item->claws_to_me) { g_hash_table_destroy(item->claws_to_me); item->claws_to_me = NULL; } } static gboolean vfolder_remove_msg_from_bridge(VFolderItem* item, guint src, guint dest) { gboolean ret = FALSE; debug_print("Removing from hashtable: src->%u dest->%u\n", src, dest); ret = g_hash_table_remove(item->me_to_claws, GUINT_TO_POINTER(dest)); ret = g_hash_table_remove(item->claws_to_me, GUINT_TO_POINTER(src)); return (ret == FALSE); } /* static gboolean vfolder_remove_msg_bridge_claws(VFolderItem* item, guint num) { return vfolder_remove_msg_from_bridge_rel(item, num, TRUE); } static gboolean vfolder_remove_msg_bridge_vfolder(VFolderItem* item, guint num) { return vfolder_remove_msg_from_bridge_rel(item, num, FALSE); } */ static void vfolder_free_hashtable_data(gpointer data) { g_free(data); } static MsgBridge* vfolder_create_bridge(guint src, guint dest) { MsgBridge* bridge; bridge = g_new0(MsgBridge, 1); bridge->my_num = dest; bridge->claws_num = src; return bridge; } static GHashTable* vfolder_hashtable_new() { return g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, vfolder_free_hashtable_data); } static gboolean vfolder_add_msg_to_message_bridge(VFolderItem* item, guint src, guint dest) { gboolean ret = FALSE; MsgBridge* bridge; if (! item->me_to_claws) item->me_to_claws = vfolder_hashtable_new(); if (! item->claws_to_me) item->claws_to_me = vfolder_hashtable_new(); debug_print("Adding to hashtable: src->%u dest->%u\n", src, dest); bridge = vfolder_create_bridge(src, dest); g_hash_table_replace(item->me_to_claws, GUINT_TO_POINTER(dest), bridge); bridge = vfolder_create_bridge(src, dest); g_hash_table_replace(item->claws_to_me, GUINT_TO_POINTER(src), bridge); return ret; } static FolderItem* vfolder_item_new(Folder* folder) { VFolderItem* vitem; debug_print("VFolder: item_new\n"); vitem = g_new0(VFolderItem, 1); gchar* id = folder_get_identifier(folder); gchar* cmp = g_strconcat("#", VFOLDER_DIR, G_DIR_SEPARATOR_S, NULL); if (id && strcmp(cmp, id) != 0) { debug_print("Creating folder item: %s\n", id); g_free(id); vfolders = g_list_prepend(vfolders, vitem); } g_free(cmp); return FOLDER_ITEM(vitem); } static void vfolder_item_destroy(Folder* folder, FolderItem* item) { VFolderItem* vitem = VFOLDER_ITEM(item); g_return_if_fail(vitem != NULL); debug_print("Number of elements in 'vfolders': %d\n", g_list_length(vfolders)); vfolders = g_list_remove(vfolders, vitem); debug_print("Number of elements in 'vfolders': %d\n", g_list_length(vfolders)); g_free(vitem->filter); vfolder_remove_hashtables(vitem); vitem->source = NULL; g_free(item); item = NULL; } static FolderItem* vfolder_create_folder(Folder* folder, FolderItem* parent, const gchar* name) { gchar* path = NULL; FolderItem* newitem = NULL; g_return_val_if_fail(folder != NULL, NULL); g_return_val_if_fail(parent != NULL, NULL); g_return_val_if_fail(name != NULL, NULL); if (parent->no_sub) return NULL; path = g_strconcat((parent->path != NULL) ? parent->path : "", ".", name, NULL); newitem = folder_item_new(folder, name, path); newitem->no_sub = TRUE; folder_item_append(parent, newitem); g_free(path); return newitem; } static gchar* vfolder_item_get_path(Folder* folder, FolderItem* item) { gchar* result; result = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, VFOLDER_DIR, G_DIR_SEPARATOR_S, item->name, NULL); return result; } static gint vfolder_get_num_list(Folder* folder, FolderItem* item, MsgNumberList** list, gboolean* old_uids_valid) { gchar* path; DIR* dp; struct dirent* d; gint num, nummsgs = 0; g_return_val_if_fail(item != NULL, -1); debug_print("VFolder: scanning '%s'...\n", item->path); *old_uids_valid = TRUE; path = folder_item_get_path(item); g_return_val_if_fail(path != NULL, -1); if (change_dir(path) < 0 ) { g_free(path); return -1; } g_free(path); if( (dp = opendir(".")) == NULL ) { FILE_OP_ERROR(item->path, "opendir"); return -1; } while ((d = readdir(dp)) != NULL ) { if( (num = to_number(d->d_name)) > 0 ) { debug_print("Adding %d to list\n", num); *list = g_slist_prepend(*list, GINT_TO_POINTER(num)); nummsgs++; } } closedir(dp); return nummsgs; } static gint vfolder_create_tree(Folder* folder) { FolderItem* rootitem; GNode* rootnode; vfolder_make_rc_dir(); if (!folder->node) { rootitem = folder_item_new(folder, folder->name, NULL); rootitem->folder = folder; rootnode = g_node_new(rootitem); folder->node = rootnode; rootitem->node = rootnode; } else { rootitem = FOLDER_ITEM(folder->node->data); rootnode = folder->node; } debug_print("VFolder: created new vfolder tree\n"); return 0; } static gint vfolder_scan_tree(Folder *folder) { g_return_val_if_fail(folder != NULL, -1); folder->outbox = NULL; folder->draft = NULL; folder->queue = NULL; folder->trash = NULL; debug_print("VFolder: scanning tree\n"); vfolder_create_tree(folder); return 0; } static gchar* vfolder_get_new_msg_filename(FolderItem* dest) { gchar* destfile; gchar* destpath; destpath = folder_item_get_path(dest); g_return_val_if_fail(destpath != NULL, NULL); if( !is_dir_exist(destpath) ) make_dir_hier(destpath); for( ; ; ) { destfile = g_strdup_printf("%s%c%d", destpath, G_DIR_SEPARATOR, dest->last_num + 1); if( is_file_entry_exist(destfile) ) { dest->last_num++; g_free(destfile); } else break; } g_free(destpath); return destfile; } static gint vfolder_add_msgs(Folder* folder, FolderItem* dest, GSList* file_list, GHashTable* relation) { gchar* destfile; GSList* cur; MsgFileInfo* fileinfo; gint r = -1; VFolderItem* vitem; g_return_val_if_fail(dest != NULL, -1); g_return_val_if_fail(file_list != NULL, -1); vitem = VFOLDER_ITEM(dest); if( dest->last_num < 0 ) { vfolder_get_last_num(folder, dest); if( dest->last_num < 0 ) return -1; } for( cur = file_list; cur != NULL; cur = cur->next ) { fileinfo = (MsgFileInfo *)cur->data; destfile = vfolder_get_new_msg_filename(dest); if (! destfile) goto bail; #ifdef G_OS_UNIX if (! vitem->deep_copy) r = symlink(fileinfo->file, destfile); if (r < 0) { if (! vitem->deep_copy) { g_warning("Requested sparse folder is not possible.\n" "Using plain file copy instead\n"); } #endif if (copy_file(fileinfo->file, destfile, TRUE) < 0) { g_warning("can't copy message %s to %s\n", fileinfo->file, destfile); g_free(destfile); destfile = NULL; goto bail; } vitem->deep_copy = TRUE; #ifdef G_OS_UNIX } #endif if( relation != NULL ) g_hash_table_insert(relation, fileinfo, GINT_TO_POINTER(dest->last_num + 1) ); g_free(destfile); vfolder_add_msg_to_message_bridge(vitem, fileinfo->msginfo->msgnum, dest->last_num + 1); dest->last_num++; vfolder_folder_item_props_write(VFOLDER_ITEM(dest)); } bail: return (destfile) ? dest->last_num : -1; } static gint vfolder_add_msg(Folder* folder, FolderItem* dest, const gchar* file, MsgFlags* flags) { gint ret; GSList file_list; MsgFileInfo fileinfo; g_return_val_if_fail(file != NULL, -1); fileinfo.msginfo = NULL; fileinfo.file = (gchar *)file; fileinfo.flags = flags; file_list.data = &fileinfo; file_list.next = NULL; ret = vfolder_add_msgs(folder, dest, &file_list, NULL); return ret; } static gint vfolder_copy_msgs(Folder *folder, FolderItem *dest, MsgInfoList *msglist, GHashTable *relation) { MsgInfo *msginfo; FolderItem *src; GSList* cur = NULL; gint last_num = 0; g_return_val_if_fail(dest != NULL && IS_VFOLDER_FOLDER_ITEM(dest), -1); if (! VFOLDER_ITEM(dest)->deep_copy) return -1; g_return_val_if_fail(folder != NULL, -1); g_return_val_if_fail(msglist != NULL, -1); if( dest->last_num < 0 ) { vfolder_get_last_num(folder, dest); if( dest->last_num < 0 ) return -1; } msginfo = (MsgInfo *)msglist->data; g_return_val_if_fail(msginfo->folder != NULL, -1); statusbar_print_all(_("Copying messages...")); src = msginfo->folder; if (src->folder != dest->folder) { GSList *infolist = NULL, *cur; int res = -1; for (cur = msglist; cur; cur = cur->next) { msginfo = (MsgInfo *)cur->data; MsgFileInfo *fileinfo = g_new0(MsgFileInfo, 1); fileinfo->file = procmsg_get_message_file(msginfo); fileinfo->flags = &(msginfo->flags); infolist = g_slist_prepend(infolist, fileinfo); } infolist = g_slist_reverse(infolist); res = folder_item_add_msgs(dest, infolist, FALSE); for (cur = infolist; cur; cur = cur->next) { MsgFileInfo *info = (MsgFileInfo *)cur->data; g_free(info->file); g_free(info); } g_slist_free(infolist); statusbar_pop_all(); return res; } for (cur = msglist; cur != NULL; cur = g_slist_next(cur)) { MsgInfo* msginfo = (MsgInfo *)cur->data; /* put the local file in the folder cache, so that we don't * have to fetch it back later. */ if (msginfo) { gchar *cache_path = folder_item_get_path(msginfo->folder); debug_print("cache_path: %s\n", cache_path); gchar *real_file = g_strconcat( cache_path, G_DIR_SEPARATOR_S, itos(msginfo->msgnum), NULL); debug_print("real_file: %s\n", real_file); gchar *cache_file = NULL; g_free(cache_path); cache_path = folder_item_get_path(dest); debug_print("cache_path: %s\n", cache_path); cache_file = vfolder_get_new_msg_filename(dest); debug_print("cache_file: %s\n", cache_file); if (!is_dir_exist(cache_path)) make_dir_hier(cache_path); if (is_file_exist(real_file) && is_dir_exist(cache_path)) { g_hash_table_insert(relation, msginfo, GINT_TO_POINTER(dest->last_num)); if (dest->last_num > last_num) last_num = dest->last_num; copy_file(real_file, cache_file, TRUE); debug_print("copied to cache: %s\n", cache_file); } g_free(real_file); g_free(cache_file); g_free(cache_path); } } statusbar_pop_all(); //dest->cache_dirty = 1; //folder_item_update_thaw(); return last_num; } static gint vfolder_copy_msg(Folder* folder, FolderItem* dest, MsgInfo* msginfo) { GSList msglist; g_return_val_if_fail(dest != NULL && IS_VFOLDER_FOLDER_ITEM(dest), -1); if (! VFOLDER_ITEM(dest)->deep_copy) return -1; g_return_val_if_fail(folder != NULL, -1); g_return_val_if_fail(msginfo != NULL, -1); g_return_val_if_fail(msginfo != NULL, -1); msglist.data = msginfo; msglist.next = NULL; return vfolder_copy_msgs(folder, dest, &msglist, NULL); } static gchar* vfolder_fetch_msg(Folder* folder, FolderItem* item, gint num) { gchar* snum = g_strdup_printf("%d", num); gchar* file = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, VFOLDER_DIR, G_DIR_SEPARATOR_S, item->name, G_DIR_SEPARATOR_S, snum, NULL); debug_print("VFolder: fetch_msg: '%s'\n", file); g_free(snum); return file; } static MsgInfo* vfolder_get_msginfo(Folder* folder, FolderItem* item, gint num) { MsgInfo* msginfo = NULL; gchar* file; MsgFlags flags; debug_print("VFolder: get_msginfo: %d\n", num); g_return_val_if_fail(folder != NULL, NULL); g_return_val_if_fail(item != NULL, NULL); g_return_val_if_fail(num > 0, NULL); file = vfolder_fetch_msg(folder, item, num); if (! g_file_test(file, G_FILE_TEST_EXISTS)) { g_free(file); return NULL; } flags.perm_flags = MSG_NEW | MSG_UNREAD; flags.tmp_flags = 0; msginfo = procheader_parse_file(file, flags, TRUE, TRUE); if (msginfo) msginfo->msgnum = num; if (!msginfo->folder) msginfo->folder = item; g_free(file); return msginfo; } static gint vfolder_remove_msg(Folder* folder, FolderItem* item, gint num) { gboolean need_scan = FALSE; gchar *file, *tmp; g_return_val_if_fail(item != NULL, -1); file = vfolder_fetch_msg(folder, item, num); g_return_val_if_fail(file != NULL, -1); need_scan = vfolder_scan_required(folder, item); /* are we doing a folder move ? */ tmp = g_strdup_printf("%s.tmp", file); if (is_file_exist(tmp)) { claws_unlink(tmp); g_free(tmp); g_free(file); return 0; } g_free(tmp); if( claws_unlink(file) < 0 ) { FILE_OP_ERROR(file, "unlink"); g_free(file); return -1; } MsgInfo* msginfo = vfolder_find_msg_from_vfolder_num(VFOLDER_ITEM(item), num); if (msginfo) { vfolder_remove_msg_from_bridge(VFOLDER_ITEM(item), msginfo->msgnum, num); vfolder_folder_item_props_write(VFOLDER_ITEM(item)); } else { MsgBridge* bridge = g_hash_table_lookup(VFOLDER_ITEM(item)->me_to_claws, GUINT_TO_POINTER(num)); if (bridge) { vfolder_remove_msg_from_bridge(VFOLDER_ITEM(item), bridge->claws_num, num); vfolder_folder_item_props_write(VFOLDER_ITEM(item)); } } if( !need_scan ) item->mtime = time(NULL); g_free(file); return 0; } static gint vfolder_remove_all_msg(Folder* folder, FolderItem* item) { GSList *msg_list, *list; g_return_val_if_fail(item != NULL, -1); msg_list = folder_item_get_msg_list(item); if (msg_list) { for (list = msg_list; list; list = g_slist_next(list)) { MsgInfo* msginfo = (MsgInfo *) list->data; folder_item_remove_msg(item, msginfo->msgnum); } } g_slist_free(msg_list); vfolder_remove_hashtables(VFOLDER_ITEM(item)); return 0; } static gboolean vfolder_subscribe_uri(Folder* folder, const gchar* uri) { return FALSE; } static void vfolder_print_hash_table(GHashTable* hash) { GHashTableIter iter; gpointer key, value; if (hash) { g_hash_table_iter_init (&iter, hash); while (g_hash_table_iter_next(&iter, &key, &value)) { guint key = GPOINTER_TO_UINT(key); MsgBridge* bridge = (MsgBridge *) value; fprintf(stderr, "key: %u ----- me: %u -> claws: %u\n", key, bridge->my_num, bridge->claws_num); } } } static MsgInfo* vfolder_find_msg_from_num_rel(VFolderItem* item, guint msgnum, gboolean claws_to_me) { MsgInfo* msginfo = NULL; GHashTable* hash; g_return_val_if_fail(item != NULL, NULL); if (msgnum < 1) return NULL; vfolder_print_hash_table(item->claws_to_me); vfolder_print_hash_table(item->me_to_claws); if (claws_to_me) hash = item->claws_to_me; else hash = item->me_to_claws; MsgBridge* msgbridge = g_hash_table_lookup(hash, GUINT_TO_POINTER(msgnum)); if (msgbridge) { if (claws_to_me) msginfo = folder_item_get_msginfo(FOLDER_ITEM(item), msgbridge->my_num); else msginfo = folder_item_get_msginfo(item->source, msgbridge->claws_num); } return msginfo; } gboolean vfolder_replace_key_in_bridge(VFolderItem* item, guint from, guint to) { gboolean ret = FALSE; MsgBridge *bridge, *old; if (! item->me_to_claws || ! item->claws_to_me) return TRUE; old = g_hash_table_lookup(item->claws_to_me, GUINT_TO_POINTER(from)); if (!old) return TRUE; debug_print("Replace key in hashtable: from->%u to->%u\n", from, to); bridge = vfolder_create_bridge(to, old->my_num); ret = g_hash_table_remove(item->me_to_claws, GUINT_TO_POINTER(old->my_num)); if (!ret) { g_free(bridge); return TRUE; } ret = g_hash_table_remove(item->claws_to_me, GUINT_TO_POINTER(old->claws_num)); if (!ret) { bridge->claws_num = from; g_hash_table_replace(item->me_to_claws, GUINT_TO_POINTER(bridge->my_num), bridge); return TRUE; } g_hash_table_replace(item->claws_to_me, GUINT_TO_POINTER(bridge->claws_num), bridge); g_hash_table_replace(item->me_to_claws, GUINT_TO_POINTER(bridge->my_num), bridge); return ret; } gboolean vfolder_add_message_to_bridge(VFolderItem* item, MsgBridge* bridge) { if (!item || !bridge) return TRUE; return vfolder_add_msg_to_message_bridge(item, bridge->claws_num, bridge->my_num); } MsgInfo* vfolder_find_msg_from_claws_num(VFolderItem* item, guint msgnum) { return vfolder_find_msg_from_num_rel(item, msgnum, TRUE); } MsgInfo* vfolder_find_msg_from_vfolder_num(VFolderItem* item, guint msgnum) { return vfolder_find_msg_from_num_rel(item, msgnum, FALSE); } GList* vfolder_get_vfolder_items(void) { return g_list_copy(vfolders); } VFolderItem* vfolder_get_vfolder_item(const gchar* name) { VFolderItem* item = NULL; gchar* folder_name = NULL; gchar* this_name = NULL; GList* list = vfolders; if (! name) folder_name = g_strdup(VFOLDER_DEFAULT_MAILBOX); else folder_name = g_strdup(name); while (list && item == NULL) { this_name = FOLDER_ITEM(list->data)->name; if (this_name && strcmp(folder_name, this_name) == 0) item = VFOLDER_ITEM(list->data); else list = list->next; } g_free(folder_name); return item; } GList* vfolder_get_vfolder_from_source(FolderItem* source) { GList* items = NULL; FolderItem* src = NULL; GList* list = vfolders; gchar* src_id = NULL; if (! source) return NULL; src_id = folder_item_get_identifier(source); if (!src_id) return NULL; while (list) { src = VFOLDER_ITEM(list->data)->source; if (strcmp(folder_item_get_identifier(src), src_id) == 0) { items = g_list_prepend(items, list->data); } list = list->next; } return items; } typedef struct { GSList* msgnumlist; guint remove; } RemoveInfo; static void find_msg_to_remove(gpointer key, gpointer value, gpointer user_data) { RemoveInfo* remove_info = (RemoveInfo *) user_data; if (remove_info->remove == 0) { if (g_slist_index(remove_info->msgnumlist, key) < 0) { MsgBridge* bridge = (MsgBridge *) value; remove_info->remove = bridge->my_num; } } }; static void vfolder_add_msg_to_folder(VFolderItem* item) { GSList *msgnumlist, *cur; GSList file_list; MsgFileInfo fileinfo; MsgInfoList msgs; if (! item->msg_filter_func) return; msgnumlist = folder_item_get_number_list(item->source); for (cur = msgnumlist; cur; cur = g_slist_next(cur)) { MsgBridge* bridge = g_hash_table_lookup(item->claws_to_me, cur->data); if (! bridge) { msgs.data = folder_item_get_msginfo(item->source, GPOINTER_TO_UINT(cur->data)); msgs.next = NULL; MsgInfoList* list = item->msg_filter_func(&msgs, item); if (list) { fileinfo.msginfo = list->data; fileinfo.file = procmsg_get_message_file_path(fileinfo.msginfo); fileinfo.flags = &fileinfo.msginfo->flags; file_list.data = &fileinfo; file_list.next = NULL; vfolder_add_msgs(item->source->folder, FOLDER_ITEM(item), &file_list, NULL); FOLDER_ITEM(item)->update_flags = F_ITEM_UPDATE_ADDMSG; g_slist_free(list); } } } g_slist_free(msgnumlist); } static void vfolder_remove_msg_from_folder(VFolderItem* item) { RemoveInfo remove_info; remove_info.msgnumlist = folder_item_get_number_list(item->source); remove_info.remove = 0; g_hash_table_foreach(item->claws_to_me, find_msg_to_remove, &remove_info); vfolder_remove_msg(FOLDER_ITEM(item)->folder, FOLDER_ITEM(item), remove_info.remove); g_slist_free(remove_info.msgnumlist); FOLDER_ITEM(item)->update_flags = F_ITEM_UPDATE_REMOVEMSG; } void vfolder_folder_item_update_msgs(VFolderItem* item, FolderItemUpdateFlags flag) { guint c; if (item->frozen || item->updating) return; if (item->claws_to_me) { item->updating = TRUE; switch (flag) { case F_ITEM_UPDATE_MSGCNT: break; case F_ITEM_UPDATE_CONTENT: c = g_hash_table_size(item->claws_to_me); if (c < item->source->total_msgs) { /* add messages */ vfolder_add_msg_to_folder(item); } else if (c > item->source->total_msgs) { /* remove messages */ vfolder_remove_msg_from_folder(item); } break; case F_ITEM_UPDATE_ADDMSG: vfolder_add_msg_to_folder(item); break; case F_ITEM_UPDATE_REMOVEMSG: vfolder_remove_msg_from_folder(item); break; case F_ITEM_UPDATE_NAME: break; } item->updating = FALSE; } } FolderClass* vfolder_folder_get_class() { if (vfolder_class.idstr == NULL ) { vfolder_class.type = F_UNKNOWN; vfolder_class.idstr = "vfolder"; vfolder_class.uistr = "VFolder"; /* Folder functions */ vfolder_class.new_folder = vfolder_new_folder; vfolder_class.destroy_folder = vfolder_destroy_folder; vfolder_class.set_xml = folder_set_xml; vfolder_class.get_xml = folder_get_xml; vfolder_class.scan_tree = vfolder_scan_tree; vfolder_class.create_tree = vfolder_create_tree; /* FolderItem functions */ vfolder_class.item_new = vfolder_item_new; vfolder_class.item_destroy = vfolder_item_destroy; vfolder_class.item_get_path = vfolder_item_get_path; vfolder_class.create_folder = vfolder_create_folder; vfolder_class.rename_folder = NULL; vfolder_class.remove_folder = vfolder_remove_folder; vfolder_class.get_num_list = vfolder_get_num_list; vfolder_class.scan_required = vfolder_scan_required; /* Message functions */ vfolder_class.get_msginfo = vfolder_get_msginfo; vfolder_class.fetch_msg = vfolder_fetch_msg; vfolder_class.copy_msgs = vfolder_copy_msgs; vfolder_class.copy_msg = vfolder_copy_msg; vfolder_class.add_msg = vfolder_add_msg; vfolder_class.add_msgs = vfolder_add_msgs; vfolder_class.remove_msg = vfolder_remove_msg; vfolder_class.remove_msgs = NULL; vfolder_class.remove_all_msg = vfolder_remove_all_msg; vfolder_class.change_flags = NULL; vfolder_class.subscribe = vfolder_subscribe_uri; debug_print("VFolder: registered folderclass\n"); } return &vfolder_class; } /* Local functions */ gboolean vfolder_init(void) { gchar* error = g_new0(gchar, 1); folder_register_class(vfolder_folder_get_class()); if (! vfolder_gtk_init(&error)) { alertpanel_error("%s", error); vfolder_done(); return FALSE; } folder_func_to_all_folders((FolderItemFunc)vfolder_init_read_func, NULL); if (existing_tree_found == FALSE) vfolder_create_default_mailbox(); return TRUE; } void vfolder_done(void) { vfolder_gtk_done(); if (!claws_is_exiting()) folder_unregister_class(vfolder_folder_get_class()); }