/*
* $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());
}