2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2002 Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #include <sys/types.h>
40 #include "mbox_folder.h"
44 #include "prefs_gtk.h"
46 #include "filtering.h"
48 #include "prefs_folder_item.h"
49 #include "procheader.h"
53 /* Dependecies to be removed ?! */
54 #include "prefs_common.h"
55 #include "prefs_account.h"
56 #include "prefs_folder_item.h"
58 static GList *folder_list = NULL;
60 static void folder_init (Folder *folder,
63 static gboolean folder_read_folder_func (GNode *node,
65 static gchar *folder_get_list_path (void);
66 static void folder_write_list_recursive (GNode *node,
68 static void folder_update_op_count_rec (GNode *node);
71 static void folder_get_persist_prefs_recursive
72 (GNode *node, GHashTable *pptable);
73 static gboolean persist_prefs_free (gpointer key, gpointer val, gpointer data);
74 void folder_item_read_cache (FolderItem *item);
75 void folder_item_free_cache (FolderItem *item);
77 Folder *folder_new(FolderType type, const gchar *name, const gchar *path)
79 Folder *folder = NULL;
82 name = name ? name : path;
85 folder = mbox_folder_new(name, path);
88 folder = mh_folder_new(name, path);
91 folder = imap_folder_new(name, path);
94 folder = news_folder_new(name, path);
100 /* Create root folder item */
101 item = folder_item_new(folder, name, NULL);
102 item->folder = folder;
103 folder->node = g_node_new(item);
109 static void folder_init(Folder *folder, const gchar *name)
111 g_return_if_fail(folder != NULL);
113 folder_set_name(folder, name);
115 /* Init folder data */
116 folder->account = NULL;
117 folder->inbox = NULL;
118 folder->outbox = NULL;
119 folder->draft = NULL;
120 folder->queue = NULL;
121 folder->trash = NULL;
123 /* Init Folder functions */
124 folder->item_new = NULL;
125 folder->item_destroy = NULL;
126 folder->fetch_msg = NULL;
127 folder->get_msginfo = NULL;
128 folder->get_msginfos = NULL;
129 folder->get_num_list = NULL;
130 folder->ui_func = NULL;
131 folder->ui_func_data = NULL;
132 folder->change_flags = NULL;
133 folder->check_msgnum_validity = NULL;
136 void folder_local_folder_init(Folder *folder, const gchar *name,
139 folder_init(folder, name);
140 LOCAL_FOLDER(folder)->rootpath = g_strdup(path);
143 void folder_remote_folder_init(Folder *folder, const gchar *name,
146 folder_init(folder, name);
147 REMOTE_FOLDER(folder)->session = NULL;
150 void folder_destroy(Folder *folder)
152 g_return_if_fail(folder != NULL);
153 g_return_if_fail(folder->destroy != NULL);
155 folder->destroy(folder);
157 folder_list = g_list_remove(folder_list, folder);
159 folder_tree_destroy(folder);
160 g_free(folder->name);
164 void folder_local_folder_destroy(LocalFolder *lfolder)
166 g_return_if_fail(lfolder != NULL);
168 g_free(lfolder->rootpath);
171 void folder_remote_folder_destroy(RemoteFolder *rfolder)
173 g_return_if_fail(rfolder != NULL);
175 if (rfolder->session)
176 session_destroy(rfolder->session);
180 Folder *mbox_folder_new(const gchar *name, const gchar *path)
182 /* not yet implemented */
186 Folder *maildir_folder_new(const gchar *name, const gchar *path)
188 /* not yet implemented */
193 FolderItem *folder_item_new(Folder *folder, const gchar *name, const gchar *path)
195 FolderItem *item = NULL;
197 if (folder->item_new) {
198 item = folder->item_new(folder);
200 item = g_new0(FolderItem, 1);
203 g_return_val_if_fail(item != NULL, NULL);
205 item->stype = F_NORMAL;
206 item->name = g_strdup(name);
207 item->path = g_strdup(path);
211 item->unreadmarked = 0;
215 item->no_sub = FALSE;
216 item->no_select = FALSE;
217 item->collapsed = FALSE;
218 item->threaded = TRUE;
219 item->ret_rcpt = FALSE;
220 item->opened = FALSE;
223 item->account = NULL;
224 item->apply_sub = FALSE;
225 item->mark_queue = NULL;
228 item->prefs = prefs_folder_item_new();
233 void folder_item_append(FolderItem *parent, FolderItem *item)
237 g_return_if_fail(parent != NULL);
238 g_return_if_fail(parent->folder != NULL);
239 g_return_if_fail(item != NULL);
241 node = parent->folder->node;
242 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, parent);
243 g_return_if_fail(node != NULL);
245 item->parent = parent;
246 item->folder = parent->folder;
247 g_node_append_data(node, item);
250 gboolean folder_item_remove_func(GNode *node, gpointer data)
252 folder_item_destroy((FolderItem *)node->data);
255 void folder_item_remove(FolderItem *item)
259 g_return_if_fail(item != NULL);
260 g_return_if_fail(item->folder != NULL);
262 node = item->folder->node;
263 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
264 g_return_if_fail(node != NULL);
266 g_node_traverse(node, G_POST_ORDER, G_TRAVERSE_ALL, -1,
267 folder_item_remove_func, NULL);
269 /* TODO: free all FolderItem's first */
270 if (item->folder->node == node)
271 item->folder->node = NULL;
272 g_node_destroy(node);
275 void folder_item_destroy(FolderItem *item)
277 g_return_if_fail(item != NULL);
279 debug_print("Destroying folder item %s\n", item->path);
282 folder_item_free_cache(item);
286 if (item->folder != NULL) {
287 if(item->folder->item_destroy) {
288 item->folder->item_destroy(item->folder, item);
295 void folder_set_ui_func(Folder *folder, FolderUIFunc func, gpointer data)
297 g_return_if_fail(folder != NULL);
299 folder->ui_func = func;
300 folder->ui_func_data = data;
303 void folder_set_name(Folder *folder, const gchar *name)
305 g_return_if_fail(folder != NULL);
307 g_free(folder->name);
308 folder->name = name ? g_strdup(name) : NULL;
309 if (folder->node && folder->node->data) {
310 FolderItem *item = (FolderItem *)folder->node->data;
313 item->name = name ? g_strdup(name) : NULL;
317 gboolean folder_tree_destroy_func(GNode *node, gpointer data) {
318 FolderItem *item = (FolderItem *) node->data;
320 folder_item_destroy(item);
324 void folder_tree_destroy(Folder *folder)
326 g_return_if_fail(folder != NULL);
327 g_return_if_fail(folder->node != NULL);
329 prefs_scoring_clear();
330 prefs_filtering_clear();
332 g_node_traverse(folder->node, G_POST_ORDER, G_TRAVERSE_ALL, -1, folder_tree_destroy_func, NULL);
334 g_node_destroy(folder->node);
336 folder->inbox = NULL;
337 folder->outbox = NULL;
338 folder->draft = NULL;
339 folder->queue = NULL;
340 folder->trash = NULL;
344 void folder_add(Folder *folder)
350 g_return_if_fail(folder != NULL);
352 for (i = 0, cur = folder_list; cur != NULL; cur = cur->next, i++) {
353 cur_folder = FOLDER(cur->data);
354 if (folder->type == F_MH) {
355 if (cur_folder->type != F_MH) break;
356 } else if (folder->type == F_MBOX) {
357 if (cur_folder->type != F_MH &&
358 cur_folder->type != F_MBOX) break;
359 } else if (folder->type == F_IMAP) {
360 if (cur_folder->type != F_MH &&
361 cur_folder->type != F_MBOX &&
362 cur_folder->type != F_IMAP) break;
363 } else if (folder->type == F_NEWS) {
364 if (cur_folder->type != F_MH &&
365 cur_folder->type != F_MBOX &&
366 cur_folder->type != F_IMAP &&
367 cur_folder->type != F_NEWS) break;
371 folder_list = g_list_insert(folder_list, folder, i);
374 GList *folder_get_list(void)
379 gint folder_read_list(void)
385 path = folder_get_list_path();
386 if (!is_file_exist(path)) return -1;
387 node = xml_parse_file(path);
388 if (!node) return -1;
390 xmlnode = node->data;
391 if (strcmp2(xmlnode->tag->tag, "folderlist") != 0) {
392 g_warning("wrong folder list\n");
397 g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, 2,
398 folder_read_folder_func, NULL);
407 void folder_write_list(void)
414 path = folder_get_list_path();
415 if ((pfile = prefs_write_open(path)) == NULL) return;
417 fprintf(pfile->fp, "<?xml version=\"1.0\" encoding=\"%s\"?>\n",
418 conv_get_current_charset_str());
419 fputs("\n<folderlist>\n", pfile->fp);
421 for (list = folder_list; list != NULL; list = list->next) {
423 folder_write_list_recursive(folder->node, pfile->fp);
426 fputs("</folderlist>\n", pfile->fp);
428 if (prefs_file_close(pfile) < 0)
429 g_warning("failed to write folder list.\n");
432 gboolean folder_scan_tree_func(GNode *node, gpointer data)
434 GHashTable *pptable = (GHashTable *)data;
435 FolderItem *item = (FolderItem *)node->data;
437 folder_item_restore_persist_prefs(item, pptable);
442 void folder_scan_tree(Folder *folder)
446 if (!folder->scan_tree)
449 pptable = folder_persist_prefs_new(folder);
450 folder_tree_destroy(folder);
452 folder->scan_tree(folder);
454 g_node_traverse(folder->node, G_POST_ORDER, G_TRAVERSE_ALL, -1, folder_scan_tree_func, pptable);
455 folder_persist_prefs_free(pptable);
457 prefs_matcher_read_config();
462 FolderItem *folder_create_folder(FolderItem *parent, const gchar *name)
464 FolderItem *new_item;
466 new_item = parent->folder->create_folder(parent->folder, parent, name);
468 new_item->cache = msgcache_new();
481 struct FuncToAllFoldersData
483 FolderItemFunc function;
487 static gboolean folder_func_to_all_folders_func(GNode *node, gpointer data)
490 struct FuncToAllFoldersData *function_data = (struct FuncToAllFoldersData *) data;
492 g_return_val_if_fail(node->data != NULL, FALSE);
494 item = FOLDER_ITEM(node->data);
495 g_return_val_if_fail(item != NULL, FALSE);
497 function_data->function(item, function_data->data);
502 void folder_func_to_all_folders(FolderItemFunc function, gpointer data)
506 struct FuncToAllFoldersData function_data;
508 function_data.function = function;
509 function_data.data = data;
511 for (list = folder_list; list != NULL; list = list->next) {
512 folder = FOLDER(list->data);
514 g_node_traverse(folder->node, G_PRE_ORDER,
516 folder_func_to_all_folders_func,
521 static void folder_count_total_msgs_func(FolderItem *item, gpointer data)
523 struct TotalMsgCount *count = (struct TotalMsgCount *)data;
525 count->new += item->new;
526 count->unread += item->unread;
527 count->unreadmarked += item->unreadmarked;
528 count->total += item->total;
531 void folder_count_total_msgs(guint *new, guint *unread, guint *unreadmarked, guint *total)
533 struct TotalMsgCount count;
535 count.new = count.unread = count.unreadmarked = count.total = 0;
537 debug_print("Counting total number of messages...\n");
539 folder_func_to_all_folders(folder_count_total_msgs_func, &count);
542 *unread = count.unread;
543 *unreadmarked = count.unreadmarked;
544 *total = count.total;
547 Folder *folder_find_from_path(const gchar *path)
552 for (list = folder_list; list != NULL; list = list->next) {
554 if ((folder->type == F_MH || folder->type == F_MBOX) &&
555 !path_cmp(LOCAL_FOLDER(folder)->rootpath, path))
562 Folder *folder_find_from_name(const gchar *name, FolderType type)
567 for (list = folder_list; list != NULL; list = list->next) {
569 if (folder->type == type && strcmp2(name, folder->name) == 0)
576 static gboolean folder_item_find_func(GNode *node, gpointer data)
578 FolderItem *item = node->data;
580 const gchar *path = d[0];
582 if (path_cmp(path, item->path) != 0)
590 FolderItem *folder_find_item_from_path(const gchar *path)
595 folder = folder_get_default_folder();
596 g_return_val_if_fail(folder != NULL, NULL);
598 d[0] = (gpointer)path;
600 g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
601 folder_item_find_func, d);
605 static const struct {
608 } type_str_table[] = {
611 {"#maildir", F_MAILDIR},
616 static gchar *folder_get_type_string(FolderType type)
620 for (i = 0; i < sizeof(type_str_table) / sizeof(type_str_table[0]);
622 if (type_str_table[i].type == type)
623 return type_str_table[i].str;
629 static FolderType folder_get_type_from_string(const gchar *str)
633 for (i = 0; i < sizeof(type_str_table) / sizeof(type_str_table[0]);
635 if (g_strcasecmp(type_str_table[i].str, str) == 0)
636 return type_str_table[i].type;
642 gchar *folder_get_identifier(Folder *folder)
646 g_return_val_if_fail(folder != NULL, NULL);
648 type_str = folder_get_type_string(folder->type);
649 return g_strconcat(type_str, "/", folder->name, NULL);
652 gchar *folder_item_get_identifier(FolderItem *item)
657 g_return_val_if_fail(item != NULL, NULL);
658 g_return_val_if_fail(item->path != NULL, NULL);
660 folder_id = folder_get_identifier(item->folder);
661 id = g_strconcat(folder_id, "/", item->path, NULL);
667 FolderItem *folder_find_item_from_identifier(const gchar *identifier)
677 g_return_val_if_fail(identifier != NULL, NULL);
679 if (*identifier != '#')
680 return folder_find_item_from_path(identifier);
682 Xstrdup_a(str, identifier, return NULL);
684 p = strchr(str, '/');
686 return folder_find_item_from_path(identifier);
689 type = folder_get_type_from_string(str);
690 if (type == F_UNKNOWN)
691 return folder_find_item_from_path(identifier);
696 return folder_find_item_from_path(identifier);
700 folder = folder_find_from_name(name, type);
702 return folder_find_item_from_path(identifier);
706 d[0] = (gpointer)path;
708 g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
709 folder_item_find_func, d);
713 Folder *folder_get_default_folder(void)
715 return folder_list ? FOLDER(folder_list->data) : NULL;
718 FolderItem *folder_get_default_inbox(void)
722 if (!folder_list) return NULL;
723 folder = FOLDER(folder_list->data);
724 g_return_val_if_fail(folder != NULL, NULL);
725 return folder->inbox;
728 FolderItem *folder_get_default_outbox(void)
732 if (!folder_list) return NULL;
733 folder = FOLDER(folder_list->data);
734 g_return_val_if_fail(folder != NULL, NULL);
735 return folder->outbox;
738 FolderItem *folder_get_default_draft(void)
742 if (!folder_list) return NULL;
743 folder = FOLDER(folder_list->data);
744 g_return_val_if_fail(folder != NULL, NULL);
745 return folder->draft;
748 FolderItem *folder_get_default_queue(void)
752 if (!folder_list) return NULL;
753 folder = FOLDER(folder_list->data);
754 g_return_val_if_fail(folder != NULL, NULL);
755 return folder->queue;
758 FolderItem *folder_get_default_trash(void)
762 if (!folder_list) return NULL;
763 folder = FOLDER(folder_list->data);
764 g_return_val_if_fail(folder != NULL, NULL);
765 return folder->trash;
768 #define CREATE_FOLDER_IF_NOT_EXIST(member, dir, type) \
770 if (!folder->member) { \
771 item = folder_item_new(folder, dir, dir); \
772 item->stype = type; \
773 folder_item_append(rootitem, item); \
774 folder->member = item; \
778 void folder_set_missing_folders(void)
781 FolderItem *rootitem;
785 for (list = folder_list; list != NULL; list = list->next) {
787 if (folder->type != F_MH) continue;
788 rootitem = FOLDER_ITEM(folder->node->data);
789 g_return_if_fail(rootitem != NULL);
791 if (folder->inbox && folder->outbox && folder->draft &&
792 folder->queue && folder->trash)
795 if (folder->create_tree(folder) < 0) {
796 g_warning("%s: can't create the folder tree.\n",
797 LOCAL_FOLDER(folder)->rootpath);
801 CREATE_FOLDER_IF_NOT_EXIST(inbox, INBOX_DIR, F_INBOX);
802 CREATE_FOLDER_IF_NOT_EXIST(outbox, OUTBOX_DIR, F_OUTBOX);
803 CREATE_FOLDER_IF_NOT_EXIST(draft, DRAFT_DIR, F_DRAFT);
804 CREATE_FOLDER_IF_NOT_EXIST(queue, QUEUE_DIR, F_QUEUE);
805 CREATE_FOLDER_IF_NOT_EXIST(trash, TRASH_DIR, F_TRASH);
809 static gboolean folder_unref_account_func(GNode *node, gpointer data)
811 FolderItem *item = node->data;
812 PrefsAccount *account = data;
814 if (item->account == account)
815 item->account = NULL;
820 void folder_unref_account_all(PrefsAccount *account)
825 if (!account) return;
827 for (list = folder_list; list != NULL; list = list->next) {
829 if (folder->account == account)
830 folder->account = NULL;
831 g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
832 folder_unref_account_func, account);
836 #undef CREATE_FOLDER_IF_NOT_EXIST
838 gchar *folder_get_path(Folder *folder)
842 g_return_val_if_fail(folder != NULL, NULL);
844 switch(FOLDER_TYPE(folder)) {
847 path = g_strdup(LOCAL_FOLDER(folder)->rootpath);
851 g_return_val_if_fail(folder->account != NULL, NULL);
852 path = g_strconcat(get_imap_cache_dir(),
854 folder->account->recv_server,
856 folder->account->userid,
861 g_return_val_if_fail(folder->account != NULL, NULL);
862 path = g_strconcat(get_news_cache_dir(),
864 folder->account->nntp_server,
876 gchar *folder_item_get_path(FolderItem *item)
881 g_return_val_if_fail(item != NULL, NULL);
883 if(FOLDER_TYPE(item->folder) != F_MBOX) {
884 folder_path = folder_get_path(item->folder);
885 g_return_val_if_fail(folder_path != NULL, NULL);
887 if (folder_path[0] == G_DIR_SEPARATOR) {
889 path = g_strconcat(folder_path, G_DIR_SEPARATOR_S,
892 path = g_strdup(folder_path);
895 path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
896 folder_path, G_DIR_SEPARATOR_S,
899 path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
907 itempath = mbox_get_virtual_path(item);
908 if (itempath == NULL)
910 path = g_strconcat(get_mbox_cache_dir(),
911 G_DIR_SEPARATOR_S, itempath, NULL);
917 void folder_item_set_default_flags(FolderItem *dest, MsgFlags *flags)
919 if (!(dest->stype == F_OUTBOX ||
920 dest->stype == F_QUEUE ||
921 dest->stype == F_DRAFT ||
922 dest->stype == F_TRASH)) {
923 flags->perm_flags = MSG_NEW|MSG_UNREAD;
925 flags->perm_flags = 0;
927 flags->tmp_flags = MSG_CACHED;
928 if (dest->folder->type == F_MH) {
929 if (dest->stype == F_QUEUE) {
930 MSG_SET_TMP_FLAGS(*flags, MSG_QUEUED);
931 } else if (dest->stype == F_DRAFT) {
932 MSG_SET_TMP_FLAGS(*flags, MSG_DRAFT);
934 } else if (dest->folder->type == F_IMAP) {
935 MSG_SET_TMP_FLAGS(*flags, MSG_IMAP);
936 } else if (dest->folder->type == F_NEWS) {
937 MSG_SET_TMP_FLAGS(*flags, MSG_NEWS);
941 static gint folder_sort_cache_list_by_msgnum(gconstpointer a, gconstpointer b)
943 MsgInfo *msginfo_a = (MsgInfo *) a;
944 MsgInfo *msginfo_b = (MsgInfo *) b;
946 return (msginfo_a->msgnum - msginfo_b->msgnum);
949 static gint folder_sort_folder_list(gconstpointer a, gconstpointer b)
951 guint gint_a = GPOINTER_TO_INT(a);
952 guint gint_b = GPOINTER_TO_INT(b);
954 return (gint_a - gint_b);
957 gint folder_item_open(FolderItem *item)
959 if(((item->folder->type == F_IMAP) && !item->no_select) || (item->folder->type == F_NEWS)) {
960 folder_item_scan(item);
964 if(item->prefs->processing != NULL) {
967 buf = g_strdup_printf(_("Processing (%s)...\n"), item->path);
968 debug_print("%s\n", buf);
971 folder_item_apply_processing(item);
973 debug_print("done.\n");
979 void folder_item_close(FolderItem *item)
983 g_return_if_fail(item != NULL);
986 mlist = folder_item_get_msg_list(item);
987 for (cur = mlist ; cur != NULL ; cur = cur->next) {
990 msginfo = (MsgInfo *) cur->data;
991 if (MSG_IS_NEW(msginfo->flags))
992 procmsg_msginfo_unset_flags(msginfo, MSG_NEW, 0);
993 procmsg_msginfo_free(msginfo);
998 folder_item_write_cache(item);
1000 folder_item_update(item, F_ITEM_UPDATE_MSGCNT);
1003 gint folder_item_scan(FolderItem *item)
1006 GSList *folder_list = NULL, *cache_list = NULL, *folder_list_cur, *cache_list_cur, *new_list = NULL;
1007 guint newcnt = 0, unreadcnt = 0, totalcnt = 0, unreadmarkedcnt = 0;
1008 guint cache_max_num, folder_max_num, cache_cur_num, folder_cur_num;
1009 gboolean update_flags = 0;
1011 g_return_val_if_fail(item != NULL, -1);
1012 if (item->path == NULL) return -1;
1014 folder = item->folder;
1016 g_return_val_if_fail(folder != NULL, -1);
1017 g_return_val_if_fail(folder->get_num_list != NULL, -1);
1019 debug_print("Scanning folder %s for cache changes.\n", item->path);
1021 /* Get list of messages for folder and cache */
1022 if (folder->get_num_list(item->folder, item, &folder_list) < 0) {
1023 debug_print("Error fetching list of message numbers\n");
1027 if (!folder->check_msgnum_validity ||
1028 folder->check_msgnum_validity(folder, item)) {
1030 folder_item_read_cache(item);
1031 cache_list = msgcache_get_msg_list(item->cache);
1034 msgcache_destroy(item->cache);
1035 item->cache = msgcache_new();
1039 /* Sort both lists */
1040 cache_list = g_slist_sort(cache_list, folder_sort_cache_list_by_msgnum);
1041 folder_list = g_slist_sort(folder_list, folder_sort_folder_list);
1043 cache_list_cur = cache_list;
1044 folder_list_cur = folder_list;
1046 if (cache_list_cur != NULL) {
1047 GSList *cache_list_last;
1049 cache_cur_num = ((MsgInfo *)cache_list_cur->data)->msgnum;
1050 cache_list_last = g_slist_last(cache_list);
1051 cache_max_num = ((MsgInfo *)cache_list_last->data)->msgnum;
1053 cache_cur_num = G_MAXINT;
1057 if (folder_list_cur != NULL) {
1058 GSList *folder_list_last;
1060 folder_cur_num = GPOINTER_TO_INT(folder_list_cur->data);
1061 folder_list_last = g_slist_last(folder_list);
1062 folder_max_num = GPOINTER_TO_INT(folder_list_last->data);
1064 folder_cur_num = G_MAXINT;
1068 while ((cache_cur_num != G_MAXINT) || (folder_cur_num != G_MAXINT)) {
1070 * Message only exists in the folder
1071 * Remember message for fetching
1073 if (folder_cur_num < cache_cur_num) {
1074 gboolean add = FALSE;
1076 switch(folder->type) {
1078 if (folder_cur_num < cache_max_num)
1081 if (prefs_common.max_articles == 0) {
1085 if (folder_max_num <= prefs_common.max_articles) {
1087 } else if (folder_cur_num > (folder_max_num - prefs_common.max_articles)) {
1097 new_list = g_slist_prepend(new_list, GINT_TO_POINTER(folder_cur_num));
1098 debug_print("Remembered message %d for fetching\n", folder_cur_num);
1101 /* Move to next folder number */
1102 folder_list_cur = folder_list_cur->next;
1104 if (folder_list_cur != NULL)
1105 folder_cur_num = GPOINTER_TO_INT(folder_list_cur->data);
1107 folder_cur_num = G_MAXINT;
1113 * Message only exists in the cache
1114 * Remove the message from the cache
1116 if (cache_cur_num < folder_cur_num) {
1117 msgcache_remove_msg(item->cache, cache_cur_num);
1118 debug_print("Removed message %d from cache.\n", cache_cur_num);
1120 /* Move to next cache number */
1121 cache_list_cur = cache_list_cur->next;
1123 if (cache_list_cur != NULL)
1124 cache_cur_num = ((MsgInfo *)cache_list_cur->data)->msgnum;
1126 cache_cur_num = G_MAXINT;
1128 update_flags |= F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT;
1134 * Message number exists in folder and cache!
1135 * Check if the message has been modified
1137 if (cache_cur_num == folder_cur_num) {
1140 msginfo = msgcache_get_msg(item->cache, folder_cur_num);
1141 if (folder->is_msg_changed && folder->is_msg_changed(folder, item, msginfo)) {
1142 MsgInfo *newmsginfo;
1144 msgcache_remove_msg(item->cache, msginfo->msgnum);
1146 if (NULL != (newmsginfo = folder->get_msginfo(folder, item, folder_cur_num))) {
1147 msgcache_add_msg(item->cache, newmsginfo);
1148 if (MSG_IS_NEW(newmsginfo->flags) && !MSG_IS_IGNORE_THREAD(newmsginfo->flags))
1150 if (MSG_IS_UNREAD(newmsginfo->flags) && !MSG_IS_IGNORE_THREAD(newmsginfo->flags))
1152 if (MSG_IS_UNREAD(newmsginfo->flags) && procmsg_msg_has_marked_parent(newmsginfo))
1154 if (procmsg_msg_has_flagged_parent(newmsginfo, MSG_IGNORE_THREAD))
1155 procmsg_msginfo_set_flags(newmsginfo, MSG_IGNORE_THREAD, 0);
1156 procmsg_msginfo_free(newmsginfo);
1159 debug_print("Updated msginfo for message %d.\n", folder_cur_num);
1161 if (MSG_IS_NEW(msginfo->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags))
1163 if (MSG_IS_UNREAD(msginfo->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags))
1165 if (MSG_IS_UNREAD(msginfo->flags) && procmsg_msg_has_marked_parent(msginfo))
1167 if (!MSG_IS_IGNORE_THREAD(msginfo->flags) && procmsg_msg_has_flagged_parent(msginfo, MSG_IGNORE_THREAD))
1168 procmsg_msginfo_set_flags(msginfo, MSG_IGNORE_THREAD, 0);
1171 procmsg_msginfo_free(msginfo);
1173 /* Move to next folder and cache number */
1174 cache_list_cur = cache_list_cur->next;
1175 folder_list_cur = folder_list_cur->next;
1177 if (cache_list_cur != NULL)
1178 cache_cur_num = ((MsgInfo *)cache_list_cur->data)->msgnum;
1180 cache_cur_num = G_MAXINT;
1182 if (folder_list_cur != NULL)
1183 folder_cur_num = GPOINTER_TO_INT(folder_list_cur->data);
1185 folder_cur_num = G_MAXINT;
1187 update_flags |= F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT;
1193 for(cache_list_cur = cache_list; cache_list_cur != NULL; cache_list_cur = g_slist_next(cache_list_cur)) {
1194 procmsg_msginfo_free((MsgInfo *) cache_list_cur->data);
1197 g_slist_free(cache_list);
1198 g_slist_free(folder_list);
1200 if (folder->get_msginfos) {
1202 GSList *newmsg_list;
1206 newmsg_list = folder->get_msginfos(folder, item, new_list);
1207 for (elem = newmsg_list; elem != NULL; elem = g_slist_next(elem)) {
1208 msginfo = (MsgInfo *) elem->data;
1209 msgcache_add_msg(item->cache, msginfo);
1210 if (MSG_IS_NEW(msginfo->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags))
1212 if (MSG_IS_UNREAD(msginfo->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags))
1214 if (MSG_IS_UNREAD(msginfo->flags) && procmsg_msg_has_marked_parent(msginfo))
1216 if (procmsg_msg_has_flagged_parent(msginfo, MSG_IGNORE_THREAD))
1217 procmsg_msginfo_set_flags(msginfo, MSG_IGNORE_THREAD, 0);
1219 procmsg_msginfo_free(msginfo);
1221 update_flags |= F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT;
1223 g_slist_free(newmsg_list);
1225 } else if (folder->get_msginfo) {
1228 for (elem = new_list; elem != NULL; elem = g_slist_next(elem)) {
1232 num = GPOINTER_TO_INT(elem->data);
1233 msginfo = folder->get_msginfo(folder, item, num);
1234 if (msginfo != NULL) {
1235 msgcache_add_msg(item->cache, msginfo);
1236 if (MSG_IS_NEW(msginfo->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags))
1238 if (MSG_IS_UNREAD(msginfo->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags))
1240 if (MSG_IS_UNREAD(msginfo->flags) && procmsg_msg_has_marked_parent(msginfo))
1242 if (procmsg_msg_has_flagged_parent(msginfo, MSG_IGNORE_THREAD))
1243 procmsg_msginfo_set_flags(msginfo, MSG_IGNORE_THREAD, 0);
1245 procmsg_msginfo_free(msginfo);
1246 debug_print("Added newly found message %d to cache.\n", num);
1249 update_flags |= F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT;
1254 item->unread = unreadcnt;
1255 item->total = totalcnt;
1256 item->unreadmarked = unreadmarkedcnt;
1257 g_slist_free(new_list);
1259 folder_item_update(item, update_flags);
1264 static void folder_item_scan_foreach_func(gpointer key, gpointer val,
1267 folder_item_scan(FOLDER_ITEM(key));
1270 void folder_item_scan_foreach(GHashTable *table)
1272 g_hash_table_foreach(table, folder_item_scan_foreach_func, NULL);
1275 void folder_count_total_cache_memusage(FolderItem *item, gpointer data)
1277 gint *memusage = (gint *)data;
1279 if (item->cache == NULL)
1282 *memusage += msgcache_get_memory_usage(item->cache);
1285 gint folder_cache_time_compare_func(gconstpointer a, gconstpointer b)
1287 FolderItem *fa = (FolderItem *)a;
1288 FolderItem *fb = (FolderItem *)b;
1290 return (gint) (msgcache_get_last_access_time(fa->cache) - msgcache_get_last_access_time(fb->cache));
1293 void folder_find_expired_caches(FolderItem *item, gpointer data)
1295 GSList **folder_item_list = (GSList **)data;
1296 gint difftime, expiretime;
1298 if (item->cache == NULL)
1301 if (item->opened > 0)
1304 difftime = (gint) (time(NULL) - msgcache_get_last_access_time(item->cache));
1305 expiretime = prefs_common.cache_min_keep_time * 60;
1306 debug_print("Cache unused time: %d (Expire time: %d)\n", difftime, expiretime);
1307 if (difftime > expiretime) {
1308 *folder_item_list = g_slist_insert_sorted(*folder_item_list, item, folder_cache_time_compare_func);
1312 void folder_item_free_cache(FolderItem *item)
1314 g_return_if_fail(item != NULL);
1316 if (item->cache == NULL)
1319 if (item->opened > 0)
1322 folder_item_write_cache(item);
1323 msgcache_destroy(item->cache);
1327 void folder_clean_cache_memory()
1331 folder_func_to_all_folders(folder_count_total_cache_memusage, &memusage);
1332 debug_print("Total cache memory usage: %d\n", memusage);
1334 if (memusage > (prefs_common.cache_max_mem_usage * 1024)) {
1335 GSList *folder_item_list = NULL, *listitem;
1337 debug_print("Trying to free cache memory\n");
1339 folder_func_to_all_folders(folder_find_expired_caches, &folder_item_list);
1340 listitem = folder_item_list;
1341 while((listitem != NULL) && (memusage > (prefs_common.cache_max_mem_usage * 1024))) {
1342 FolderItem *item = (FolderItem *)(listitem->data);
1344 debug_print("Freeing cache memory for %s\n", item->path);
1345 memusage -= msgcache_get_memory_usage(item->cache);
1346 folder_item_free_cache(item);
1347 listitem = listitem->next;
1349 g_slist_free(folder_item_list);
1353 void folder_item_read_cache(FolderItem *item)
1355 gchar *cache_file, *mark_file;
1357 g_return_if_fail(item != NULL);
1359 cache_file = folder_item_get_cache_file(item);
1360 mark_file = folder_item_get_mark_file(item);
1361 item->cache = msgcache_read_cache(item, cache_file);
1363 item->cache = msgcache_new();
1364 folder_item_scan(item);
1366 msgcache_read_mark(item->cache, mark_file);
1370 folder_clean_cache_memory();
1373 void folder_item_write_cache(FolderItem *item)
1375 gchar *cache_file, *mark_file;
1376 PrefsFolderItem *prefs;
1380 if (!item || !item->path || !item->cache)
1383 id = folder_item_get_identifier(item);
1384 debug_print("Save cache for folder %s\n", id);
1387 cache_file = folder_item_get_cache_file(item);
1388 mark_file = folder_item_get_mark_file(item);
1389 if (msgcache_write(cache_file, mark_file, item->cache) < 0) {
1390 prefs = item->prefs;
1391 if (prefs && prefs->enable_folder_chmod && prefs->folder_chmod) {
1392 /* for cache file */
1393 filemode = prefs->folder_chmod;
1394 if (filemode & S_IRGRP) filemode |= S_IWGRP;
1395 if (filemode & S_IROTH) filemode |= S_IWOTH;
1396 chmod(cache_file, filemode);
1404 MsgInfo *folder_item_get_msginfo(FolderItem *item, gint num)
1409 g_return_val_if_fail(item != NULL, NULL);
1411 folder = item->folder;
1413 folder_item_read_cache(item);
1415 if ((msginfo = msgcache_get_msg(item->cache, num)) != NULL)
1418 g_return_val_if_fail(folder->get_msginfo, NULL);
1419 if ((msginfo = folder->get_msginfo(folder, item, num)) != NULL) {
1420 msgcache_add_msg(item->cache, msginfo);
1427 MsgInfo *folder_item_get_msginfo_by_msgid(FolderItem *item, const gchar *msgid)
1432 g_return_val_if_fail(item != NULL, NULL);
1434 folder = item->folder;
1436 folder_item_read_cache(item);
1438 if ((msginfo = msgcache_get_msg_by_id(item->cache, msgid)) != NULL)
1444 GSList *folder_item_get_msg_list(FolderItem *item)
1446 g_return_val_if_fail(item != NULL, NULL);
1448 if (item->cache == 0)
1449 folder_item_read_cache(item);
1451 g_return_val_if_fail(item->cache != NULL, NULL);
1453 return msgcache_get_msg_list(item->cache);
1456 gchar *folder_item_fetch_msg(FolderItem *item, gint num)
1460 g_return_val_if_fail(item != NULL, NULL);
1462 folder = item->folder;
1464 g_return_val_if_fail(folder->fetch_msg != NULL, NULL);
1466 return folder->fetch_msg(folder, item, num);
1469 gint folder_item_add_msg(FolderItem *dest, const gchar *file,
1470 gboolean remove_source)
1476 g_return_val_if_fail(dest != NULL, -1);
1477 g_return_val_if_fail(file != NULL, -1);
1479 folder = dest->folder;
1481 g_return_val_if_fail(folder->add_msg != NULL, -1);
1484 folder_item_read_cache(dest);
1486 num = folder->add_msg(folder, dest, file, remove_source);
1489 msginfo = folder->get_msginfo(folder, dest, num);
1491 if (msginfo != NULL) {
1492 if (MSG_IS_NEW(msginfo->flags))
1494 if (MSG_IS_UNREAD(msginfo->flags))
1496 if (MSG_IS_UNREAD(msginfo->flags) && procmsg_msg_has_marked_parent(msginfo))
1497 dest->unreadmarked++;
1498 if (procmsg_msg_has_flagged_parent(msginfo, MSG_IGNORE_THREAD))
1499 procmsg_msginfo_set_flags(msginfo, MSG_IGNORE_THREAD, 0);
1501 folder_item_update(dest, F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT);
1503 msgcache_add_msg(dest->cache, msginfo);
1505 procmsg_msginfo_free(msginfo);
1508 dest->last_num = num;
1515 gint folder_item_move_msg(FolderItem *dest, MsgInfo *msginfo)
1520 g_return_val_if_fail(dest != NULL, -1);
1521 g_return_val_if_fail(msginfo != NULL, -1);
1523 folder = dest->folder;
1524 if (dest->last_num < 0) folder->scan(folder, dest);
1526 num = folder->move_msg(folder, dest, msginfo);
1527 if (num > 0) dest->last_num = num;
1533 FolderItem *folder_item_move_recursive (FolderItem *src, FolderItem *dest)
1537 FolderItem *new_item;
1538 FolderItem *next_item;
1541 gchar *old_id, *new_id;
1543 mlist = folder_item_get_msg_list(src);
1546 debug_print("Moving %s to %s\n", src->path, dest->path);
1547 new_item = folder_create_folder(dest, g_basename(src->path));
1548 if (new_item == NULL) {
1549 printf("Can't create folder\n");
1553 if (new_item->folder == NULL)
1554 new_item->folder = dest->folder;
1557 for (cur = mlist ; cur != NULL ; cur = cur->next) {
1561 log_message(_("Moving %s to %s (%d%%)...\n"), src->name,
1563 100*cnt/g_slist_length(mlist));
1564 msginfo = (MsgInfo *) cur->data;
1565 folder_item_move_msg(new_item, msginfo);
1567 procmsg_msginfo_free(msginfo);
1571 prefs_folder_item_copy_prefs(src, new_item);
1572 new_item->collapsed = src->collapsed;
1573 new_item->threaded = src->threaded;
1574 new_item->ret_rcpt = src->ret_rcpt;
1575 new_item->hide_read_msgs = src->hide_read_msgs;
1576 new_item->sort_key = src->sort_key;
1577 new_item->sort_type = src->sort_type;
1579 prefs_matcher_write_config();
1582 srcnode = src->folder->node;
1583 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, src);
1584 srcnode = srcnode->children;
1585 while (srcnode != NULL) {
1586 if (srcnode && srcnode->data) {
1587 next_item = (FolderItem*) srcnode->data;
1588 srcnode = srcnode->next;
1589 if (folder_item_move_recursive(next_item, new_item) == NULL)
1593 old_id = folder_item_get_identifier(src);
1594 new_id = folder_item_get_identifier(new_item);
1595 debug_print("updating rules : %s => %s\n", old_id, new_id);
1597 src->folder->remove_folder(src->folder, src);
1598 folder_write_list();
1600 if (old_id != NULL && new_id != NULL)
1601 prefs_filtering_rename_path(old_id, new_id);
1608 gint folder_item_move_to(FolderItem *src, FolderItem *dest, FolderItem **new_item)
1610 FolderItem *tmp = dest->parent;
1611 gchar * src_identifier, * dst_identifier;
1612 gchar * phys_srcpath, * phys_dstpath;
1617 return F_MOVE_FAILED_DEST_IS_CHILD;
1624 src_identifier = folder_item_get_identifier(src);
1625 dst_identifier = folder_item_get_identifier(dest);
1627 if(dst_identifier == NULL && dest->folder && dest->parent == NULL) {
1628 /* dest can be a root folder */
1629 dst_identifier = folder_get_identifier(dest->folder);
1631 if (src_identifier == NULL || dst_identifier == NULL) {
1632 printf("Can't get identifiers\n");
1633 return F_MOVE_FAILED;
1636 if (src->folder != dest->folder) {
1637 return F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX;
1640 phys_srcpath = folder_item_get_path(src);
1641 phys_dstpath = g_strconcat(folder_item_get_path(dest),G_DIR_SEPARATOR_S,g_basename(phys_srcpath),NULL);
1643 if (src->parent == dest || src == dest) {
1644 g_free(src_identifier);
1645 g_free(dst_identifier);
1646 g_free(phys_srcpath);
1647 g_free(phys_dstpath);
1648 return F_MOVE_FAILED_DEST_IS_PARENT;
1650 debug_print("moving \"%s\" to \"%s\"\n", phys_srcpath, phys_dstpath);
1651 if ((tmp = folder_item_move_recursive(src, dest)) == NULL) {
1652 return F_MOVE_FAILED;
1656 src_node = g_node_find(src->folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, src);
1658 g_node_destroy(src_node);
1660 debug_print("can't remove node: it's null!\n");
1661 /* not to much worry if remove fails, move has been done */
1663 g_free(src_identifier);
1664 g_free(dst_identifier);
1665 g_free(phys_srcpath);
1666 g_free(phys_dstpath);
1673 gint folder_item_move_msg(FolderItem *dest, MsgInfo *msginfo)
1679 g_return_val_if_fail(dest != NULL, -1);
1680 g_return_val_if_fail(msginfo != NULL, -1);
1682 folder = dest->folder;
1684 g_return_val_if_fail(folder->remove_msg != NULL, -1);
1685 g_return_val_if_fail(folder->copy_msg != NULL, -1);
1687 if (!dest->cache) folder_item_read_cache(dest);
1689 src_folder = msginfo->folder->folder;
1691 num = folder->copy_msg(folder, dest, msginfo);
1694 MsgInfo *newmsginfo;
1696 /* Add new msginfo to dest folder */
1697 if (NULL != (newmsginfo = folder->get_msginfo(folder, dest, num))) {
1698 newmsginfo->flags.perm_flags = msginfo->flags.perm_flags;
1700 if (dest->stype == F_OUTBOX || dest->stype == F_QUEUE ||
1701 dest->stype == F_DRAFT || dest->stype == F_TRASH)
1702 MSG_UNSET_PERM_FLAGS(newmsginfo->flags,
1703 MSG_NEW|MSG_UNREAD|MSG_DELETED);
1704 msgcache_add_msg(dest->cache, newmsginfo);
1706 if (MSG_IS_NEW(newmsginfo->flags))
1708 if (MSG_IS_UNREAD(newmsginfo->flags))
1710 if (MSG_IS_UNREAD(newmsginfo->flags) && procmsg_msg_has_marked_parent(newmsginfo))
1711 dest->unreadmarked++;
1712 if (procmsg_msg_has_flagged_parent(newmsginfo, MSG_IGNORE_THREAD))
1713 procmsg_msginfo_set_flags(newmsginfo, MSG_IGNORE_THREAD, 0);
1715 folder_item_update(dest, F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT);
1717 procmsg_msginfo_free(newmsginfo);
1720 /* remove source message from it's folder */
1721 if (src_folder->remove_msg) {
1722 src_folder->remove_msg(src_folder, msginfo->folder,
1724 msgcache_remove_msg(msginfo->folder->cache, msginfo->msgnum);
1726 if (MSG_IS_NEW(msginfo->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags))
1727 msginfo->folder->new--;
1728 if (MSG_IS_UNREAD(msginfo->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags))
1729 msginfo->folder->unread--;
1730 if (MSG_IS_UNREAD(msginfo->flags) && procmsg_msg_has_marked_parent(msginfo))
1731 msginfo->folder->unreadmarked--;
1732 msginfo->folder->total--;
1733 folder_item_update(dest, F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT);
1737 if (folder->finished_copy)
1738 folder->finished_copy(folder, dest);
1744 gint folder_item_move_msgs_with_dest(FolderItem *dest, GSList *msglist)
1749 g_return_val_if_fail(dest != NULL, -1);
1750 g_return_val_if_fail(msglist != NULL, -1);
1752 folder = dest->folder;
1753 if (dest->last_num < 0) folder->scan(folder, dest);
1755 num = folder->move_msgs_with_dest(folder, dest, msglist);
1756 if (num > 0) dest->last_num = num;
1757 else dest->op_count = 0;
1763 gint folder_item_move_msgs_with_dest(FolderItem *dest, GSList *msglist)
1767 GSList *newmsgnums = NULL;
1771 g_return_val_if_fail(dest != NULL, -1);
1772 g_return_val_if_fail(msglist != NULL, -1);
1774 folder = dest->folder;
1776 g_return_val_if_fail(folder->copy_msg != NULL, -1);
1777 g_return_val_if_fail(folder->remove_msg != NULL, -1);
1780 * Copy messages to destination folder and
1781 * store new message numbers in newmsgnums
1784 for (l = msglist ; l != NULL ; l = g_slist_next(l)) {
1785 MsgInfo * msginfo = (MsgInfo *) l->data;
1787 if (!item && msginfo->folder != NULL)
1788 item = msginfo->folder;
1790 num = folder->copy_msg(folder, dest, msginfo);
1791 newmsgnums = g_slist_append(newmsgnums, GINT_TO_POINTER(num));
1794 /* Read cache for dest folder */
1795 if (!dest->cache) folder_item_read_cache(dest);
1798 * Fetch new MsgInfos for new messages in dest folder,
1799 * add them to the msgcache and update folder message counts
1802 for (l = msglist; l != NULL; l = g_slist_next(l)) {
1803 MsgInfo *msginfo = (MsgInfo *) l->data;
1805 num = GPOINTER_TO_INT(l2->data);
1808 MsgInfo *newmsginfo;
1810 newmsginfo = folder->get_msginfo(folder, dest, num);
1812 newmsginfo->flags.perm_flags = msginfo->flags.perm_flags;
1813 if (dest->stype == F_OUTBOX ||
1814 dest->stype == F_QUEUE ||
1815 dest->stype == F_DRAFT ||
1816 dest->stype == F_TRASH)
1817 MSG_UNSET_PERM_FLAGS(newmsginfo->flags,
1818 MSG_NEW|MSG_UNREAD|MSG_DELETED);
1819 msgcache_add_msg(dest->cache, newmsginfo);
1821 if (MSG_IS_NEW(newmsginfo->flags))
1823 if (MSG_IS_UNREAD(newmsginfo->flags))
1825 if (MSG_IS_UNREAD(newmsginfo->flags) && procmsg_msg_has_marked_parent(newmsginfo))
1826 dest->unreadmarked++;
1827 if (procmsg_msg_has_flagged_parent(newmsginfo, MSG_IGNORE_THREAD))
1828 procmsg_msginfo_set_flags(newmsginfo, MSG_IGNORE_THREAD, 0);
1830 folder_item_update(dest, F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT);
1832 procmsg_msginfo_free(newmsginfo);
1835 l2 = g_slist_next(l2);
1839 * Remove source messages from their folders if
1840 * copying was successfull and update folder
1844 for (l = msglist; l != NULL; l = g_slist_next(l)) {
1845 MsgInfo *msginfo = (MsgInfo *) l->data;
1847 num = GPOINTER_TO_INT(l2->data);
1850 item->folder->remove_msg(item->folder,
1854 folder_item_read_cache(item);
1855 msgcache_remove_msg(item->cache, msginfo->msgnum);
1857 if (MSG_IS_NEW(msginfo->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags))
1858 msginfo->folder->new--;
1859 if (MSG_IS_UNREAD(msginfo->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags))
1860 msginfo->folder->unread--;
1861 if (MSG_IS_UNREAD(msginfo->flags) && procmsg_msg_has_marked_parent(msginfo))
1862 msginfo->folder->unreadmarked--;
1863 msginfo->folder->total--;
1864 folder_item_update(msginfo->folder, F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT);
1867 l2 = g_slist_next(l2);
1871 if (folder->finished_copy)
1872 folder->finished_copy(folder, dest);
1874 g_slist_free(newmsgnums);
1875 return dest->last_num;
1879 gint folder_item_copy_msg(FolderItem *dest, MsgInfo *msginfo)
1884 g_return_val_if_fail(dest != NULL, -1);
1885 g_return_val_if_fail(msginfo != NULL, -1);
1887 folder = dest->folder;
1888 if (dest->last_num < 0) folder->scan(folder, dest);
1890 num = folder->copy_msg(folder, dest, msginfo);
1891 if (num > 0) dest->last_num = num;
1897 gint folder_item_copy_msg(FolderItem *dest, MsgInfo *msginfo)
1902 g_return_val_if_fail(dest != NULL, -1);
1903 g_return_val_if_fail(msginfo != NULL, -1);
1905 folder = dest->folder;
1907 g_return_val_if_fail(folder->copy_msg != NULL, -1);
1909 if (!dest->cache) folder_item_read_cache(dest);
1911 num = folder->copy_msg(folder, dest, msginfo);
1913 MsgInfo *newmsginfo;
1915 if (NULL != (newmsginfo = folder->get_msginfo(folder, dest, num))) {
1916 newmsginfo->flags.perm_flags = msginfo->flags.perm_flags;
1917 if (dest->stype == F_OUTBOX ||
1918 dest->stype == F_QUEUE ||
1919 dest->stype == F_DRAFT ||
1920 dest->stype == F_TRASH)
1921 MSG_UNSET_PERM_FLAGS(newmsginfo->flags,
1922 MSG_NEW|MSG_UNREAD|MSG_DELETED);
1923 msgcache_add_msg(dest->cache, newmsginfo);
1925 if (MSG_IS_NEW(newmsginfo->flags))
1927 if (MSG_IS_UNREAD(newmsginfo->flags))
1929 if (MSG_IS_UNREAD(newmsginfo->flags) && procmsg_msg_has_marked_parent(newmsginfo))
1930 dest->unreadmarked++;
1931 if (procmsg_msg_has_flagged_parent(newmsginfo, MSG_IGNORE_THREAD))
1932 procmsg_msginfo_set_flags(newmsginfo, MSG_IGNORE_THREAD, 0);
1934 folder_item_update(dest, F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT);
1936 procmsg_msginfo_free(newmsginfo);
1940 if (folder->finished_copy)
1941 folder->finished_copy(folder, dest);
1947 gint folder_item_copy_msgs_with_dest(FolderItem *dest, GSList *msglist)
1952 g_return_val_if_fail(dest != NULL, -1);
1953 g_return_val_if_fail(msglist != NULL, -1);
1955 folder = dest->folder;
1956 if (dest->last_num < 0) folder->scan(folder, dest);
1958 num = folder->copy_msgs_with_dest(folder, dest, msglist);
1959 if (num > 0) dest->last_num = num;
1960 else dest->op_count = 0;
1966 gint folder_item_copy_msgs_with_dest(FolderItem *dest, GSList *msglist)
1970 GSList *newmsgnums = NULL;
1973 g_return_val_if_fail(dest != NULL, -1);
1974 g_return_val_if_fail(msglist != NULL, -1);
1976 folder = dest->folder;
1978 g_return_val_if_fail(folder->copy_msg != NULL, -1);
1981 * Copy messages to destination folder and
1982 * store new message numbers in newmsgnums
1984 for (l = msglist ; l != NULL ; l = g_slist_next(l)) {
1985 MsgInfo * msginfo = (MsgInfo *) l->data;
1987 num = folder->copy_msg(folder, dest, msginfo);
1988 newmsgnums = g_slist_append(newmsgnums, GINT_TO_POINTER(num));
1991 /* Read cache for dest folder */
1992 if (!dest->cache) folder_item_read_cache(dest);
1995 * Fetch new MsgInfos for new messages in dest folder,
1996 * add them to the msgcache and update folder message counts
1999 for (l = msglist; l != NULL; l = g_slist_next(l)) {
2000 MsgInfo *msginfo = (MsgInfo *) l->data;
2002 num = GPOINTER_TO_INT(l2->data);
2005 MsgInfo *newmsginfo;
2007 newmsginfo = folder->get_msginfo(folder, dest, num);
2009 newmsginfo->flags.perm_flags = msginfo->flags.perm_flags;
2010 if (dest->stype == F_OUTBOX ||
2011 dest->stype == F_QUEUE ||
2012 dest->stype == F_DRAFT ||
2013 dest->stype == F_TRASH)
2014 MSG_UNSET_PERM_FLAGS(newmsginfo->flags,
2015 MSG_NEW|MSG_UNREAD|MSG_DELETED);
2016 msgcache_add_msg(dest->cache, newmsginfo);
2018 if (MSG_IS_NEW(newmsginfo->flags))
2020 if (MSG_IS_UNREAD(newmsginfo->flags))
2022 if (MSG_IS_UNREAD(newmsginfo->flags) && procmsg_msg_has_marked_parent(newmsginfo))
2023 dest->unreadmarked++;
2024 if (procmsg_msg_has_flagged_parent(newmsginfo, MSG_IGNORE_THREAD))
2025 procmsg_msginfo_set_flags(newmsginfo, MSG_IGNORE_THREAD, 0);
2027 folder_item_update(dest, F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT);
2029 procmsg_msginfo_free(newmsginfo);
2032 l2 = g_slist_next(l2);
2035 if (folder->finished_copy)
2036 folder->finished_copy(folder, dest);
2038 g_slist_free(newmsgnums);
2039 return dest->last_num;
2042 gint folder_item_remove_msg(FolderItem *item, gint num)
2048 g_return_val_if_fail(item != NULL, -1);
2050 folder = item->folder;
2051 if (!item->cache) folder_item_read_cache(item);
2053 ret = folder->remove_msg(folder, item, num);
2055 msginfo = msgcache_get_msg(item->cache, num);
2056 if (msginfo != NULL) {
2057 if (MSG_IS_NEW(msginfo->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags))
2059 if (MSG_IS_UNREAD(msginfo->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags))
2061 if (MSG_IS_UNREAD(msginfo->flags) && procmsg_msg_has_marked_parent(msginfo))
2062 item->unreadmarked--;
2063 procmsg_msginfo_free(msginfo);
2064 msgcache_remove_msg(item->cache, num);
2067 folder_item_update(item, F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT);
2072 gint folder_item_remove_msgs(FolderItem *item, GSList *msglist)
2077 g_return_val_if_fail(item != NULL, -1);
2078 folder = item->folder;
2079 g_return_val_if_fail(folder != NULL, -1);
2081 if (!item->cache) folder_item_read_cache(item);
2083 if (folder->remove_msgs) {
2084 ret = folder->remove_msgs(folder, item, msglist);
2086 folder_item_scan(item);
2090 while (msglist != NULL) {
2091 MsgInfo *msginfo = (MsgInfo *)msglist->data;
2093 ret = folder_item_remove_msg(item, msginfo->msgnum);
2094 if (ret != 0) break;
2095 msgcache_remove_msg(item->cache, msginfo->msgnum);
2096 msglist = msglist->next;
2102 gint folder_item_remove_all_msg(FolderItem *item)
2107 g_return_val_if_fail(item != NULL, -1);
2109 folder = item->folder;
2111 g_return_val_if_fail(folder->remove_all_msg != NULL, -1);
2113 result = folder->remove_all_msg(folder, item);
2116 if (folder->finished_remove)
2117 folder->finished_remove(folder, item);
2119 folder_item_free_cache(item);
2120 item->cache = msgcache_new();
2124 item->unreadmarked = 0;
2126 folder_item_update(item, F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT);
2132 gboolean folder_item_is_msg_changed(FolderItem *item, MsgInfo *msginfo)
2136 g_return_val_if_fail(item != NULL, FALSE);
2138 folder = item->folder;
2140 g_return_val_if_fail(folder->is_msg_changed != NULL, -1);
2142 return folder->is_msg_changed(folder, item, msginfo);
2145 gchar *folder_item_get_cache_file(FolderItem *item)
2150 g_return_val_if_fail(item != NULL, NULL);
2151 g_return_val_if_fail(item->path != NULL, NULL);
2153 path = folder_item_get_path(item);
2154 g_return_val_if_fail(path != NULL, NULL);
2155 if (!is_dir_exist(path))
2156 make_dir_hier(path);
2157 file = g_strconcat(path, G_DIR_SEPARATOR_S, CACHE_FILE, NULL);
2163 gchar *folder_item_get_mark_file(FolderItem *item)
2168 g_return_val_if_fail(item != NULL, NULL);
2169 g_return_val_if_fail(item->path != NULL, NULL);
2171 path = folder_item_get_path(item);
2172 g_return_val_if_fail(path != NULL, NULL);
2173 if (!is_dir_exist(path))
2174 make_dir_hier(path);
2175 file = g_strconcat(path, G_DIR_SEPARATOR_S, MARK_FILE, NULL);
2181 static gboolean folder_build_tree(GNode *node, gpointer data)
2183 Folder *folder = FOLDER(data);
2187 SpecialFolderItemType stype = F_NORMAL;
2188 const gchar *name = NULL;
2189 const gchar *path = NULL;
2190 PrefsAccount *account = NULL;
2191 gboolean no_sub = FALSE, no_select = FALSE, collapsed = FALSE,
2192 threaded = TRUE, apply_sub = FALSE;
2193 gboolean ret_rcpt = FALSE, hidereadmsgs = FALSE; /* CLAWS */
2194 FolderSortKey sort_key = SORT_BY_NONE;
2195 FolderSortType sort_type = SORT_ASCENDING;
2196 gint new = 0, unread = 0, total = 0, unreadmarked = 0;
2199 g_return_val_if_fail(node->data != NULL, FALSE);
2200 if (!node->parent) return FALSE;
2202 xmlnode = node->data;
2203 if (strcmp2(xmlnode->tag->tag, "folderitem") != 0) {
2204 g_warning("tag name != \"folderitem\"\n");
2208 list = xmlnode->tag->attr;
2209 for (; list != NULL; list = list->next) {
2210 XMLAttr *attr = list->data;
2212 if (!attr || !attr->name || !attr->value) continue;
2213 if (!strcmp(attr->name, "type")) {
2214 if (!strcasecmp(attr->value, "normal"))
2216 else if (!strcasecmp(attr->value, "inbox"))
2218 else if (!strcasecmp(attr->value, "outbox"))
2220 else if (!strcasecmp(attr->value, "draft"))
2222 else if (!strcasecmp(attr->value, "queue"))
2224 else if (!strcasecmp(attr->value, "trash"))
2226 } else if (!strcmp(attr->name, "name"))
2228 else if (!strcmp(attr->name, "path"))
2230 else if (!strcmp(attr->name, "mtime"))
2231 mtime = strtoul(attr->value, NULL, 10);
2232 else if (!strcmp(attr->name, "new"))
2233 new = atoi(attr->value);
2234 else if (!strcmp(attr->name, "unread"))
2235 unread = atoi(attr->value);
2236 else if (!strcmp(attr->name, "unreadmarked"))
2237 unreadmarked = atoi(attr->value);
2238 else if (!strcmp(attr->name, "total"))
2239 total = atoi(attr->value);
2240 else if (!strcmp(attr->name, "no_sub"))
2241 no_sub = *attr->value == '1' ? TRUE : FALSE;
2242 else if (!strcmp(attr->name, "no_select"))
2243 no_select = *attr->value == '1' ? TRUE : FALSE;
2244 else if (!strcmp(attr->name, "collapsed"))
2245 collapsed = *attr->value == '1' ? TRUE : FALSE;
2246 else if (!strcmp(attr->name, "threaded"))
2247 threaded = *attr->value == '1' ? TRUE : FALSE;
2248 else if (!strcmp(attr->name, "hidereadmsgs"))
2249 hidereadmsgs = *attr->value == '1' ? TRUE : FALSE;
2250 else if (!strcmp(attr->name, "reqretrcpt"))
2251 ret_rcpt = *attr->value == '1' ? TRUE : FALSE;
2252 else if (!strcmp(attr->name, "sort_key")) {
2253 if (!strcmp(attr->value, "none"))
2254 sort_key = SORT_BY_NONE;
2255 else if (!strcmp(attr->value, "number"))
2256 sort_key = SORT_BY_NUMBER;
2257 else if (!strcmp(attr->value, "size"))
2258 sort_key = SORT_BY_SIZE;
2259 else if (!strcmp(attr->value, "date"))
2260 sort_key = SORT_BY_DATE;
2261 else if (!strcmp(attr->value, "from"))
2262 sort_key = SORT_BY_FROM;
2263 else if (!strcmp(attr->value, "subject"))
2264 sort_key = SORT_BY_SUBJECT;
2265 else if (!strcmp(attr->value, "score"))
2266 sort_key = SORT_BY_SCORE;
2267 else if (!strcmp(attr->value, "label"))
2268 sort_key = SORT_BY_LABEL;
2269 else if (!strcmp(attr->value, "mark"))
2270 sort_key = SORT_BY_MARK;
2271 else if (!strcmp(attr->value, "unread"))
2272 sort_key = SORT_BY_UNREAD;
2273 else if (!strcmp(attr->value, "mime"))
2274 sort_key = SORT_BY_MIME;
2275 else if (!strcmp(attr->value, "to"))
2276 sort_key = SORT_BY_TO;
2277 else if (!strcmp(attr->value, "locked"))
2278 sort_key = SORT_BY_LOCKED;
2279 } else if (!strcmp(attr->name, "sort_type")) {
2280 if (!strcmp(attr->value, "ascending"))
2281 sort_type = SORT_ASCENDING;
2283 sort_type = SORT_DESCENDING;
2284 } else if (!strcmp(attr->name, "account_id")) {
2285 account = account_find_from_id(atoi(attr->value));
2286 if (!account) g_warning("account_id: %s not found\n",
2288 } else if (!strcmp(attr->name, "apply_sub"))
2289 apply_sub = *attr->value == '1' ? TRUE : FALSE;
2292 item = folder_item_new(folder, name, path);
2293 item->stype = stype;
2294 item->mtime = mtime;
2296 item->unread = unread;
2297 item->unreadmarked = unreadmarked;
2298 item->total = total;
2299 item->no_sub = no_sub;
2300 item->no_select = no_select;
2301 item->collapsed = collapsed;
2302 item->threaded = threaded;
2303 item->hide_read_msgs = hidereadmsgs;
2304 item->ret_rcpt = ret_rcpt;
2305 item->sort_key = sort_key;
2306 item->sort_type = sort_type;
2307 item->parent = FOLDER_ITEM(node->parent->data);
2308 item->folder = folder;
2310 case F_INBOX: folder->inbox = item; break;
2311 case F_OUTBOX: folder->outbox = item; break;
2312 case F_DRAFT: folder->draft = item; break;
2313 case F_QUEUE: folder->queue = item; break;
2314 case F_TRASH: folder->trash = item; break;
2317 item->account = account;
2318 item->apply_sub = apply_sub;
2319 prefs_folder_item_read_config(item);
2322 xml_free_node(xmlnode);
2327 static gboolean folder_read_folder_func(GNode *node, gpointer data)
2332 FolderType type = F_UNKNOWN;
2333 const gchar *name = NULL;
2334 const gchar *path = NULL;
2335 PrefsAccount *account = NULL;
2336 gboolean collapsed = FALSE, threaded = TRUE, apply_sub = FALSE;
2337 gboolean ret_rcpt = FALSE; /* CLAWS */
2339 if (g_node_depth(node) != 2) return FALSE;
2340 g_return_val_if_fail(node->data != NULL, FALSE);
2342 xmlnode = node->data;
2343 if (strcmp2(xmlnode->tag->tag, "folder") != 0) {
2344 g_warning("tag name != \"folder\"\n");
2347 g_node_unlink(node);
2348 list = xmlnode->tag->attr;
2349 for (; list != NULL; list = list->next) {
2350 XMLAttr *attr = list->data;
2352 if (!attr || !attr->name || !attr->value) continue;
2353 if (!strcmp(attr->name, "type")) {
2354 if (!strcasecmp(attr->value, "mh"))
2356 else if (!strcasecmp(attr->value, "mbox"))
2358 else if (!strcasecmp(attr->value, "maildir"))
2360 else if (!strcasecmp(attr->value, "imap"))
2362 else if (!strcasecmp(attr->value, "news"))
2364 } else if (!strcmp(attr->name, "name"))
2366 else if (!strcmp(attr->name, "path"))
2368 else if (!strcmp(attr->name, "collapsed"))
2369 collapsed = *attr->value == '1' ? TRUE : FALSE;
2370 else if (!strcmp(attr->name, "threaded"))
2371 threaded = *attr->value == '1' ? TRUE : FALSE;
2372 else if (!strcmp(attr->name, "account_id")) {
2373 account = account_find_from_id(atoi(attr->value));
2374 if (!account) g_warning("account_id: %s not found\n",
2376 } else if (!strcmp(attr->name, "apply_sub"))
2377 apply_sub = *attr->value == '1' ? TRUE : FALSE;
2378 else if (!strcmp(attr->name, "reqretrcpt"))
2379 ret_rcpt = *attr->value == '1' ? TRUE : FALSE;
2382 folder = folder_new(type, name, path);
2383 g_return_val_if_fail(folder != NULL, FALSE);
2384 folder->account = account;
2385 if (account && (type == F_IMAP || type == F_NEWS))
2386 account->folder = REMOTE_FOLDER(folder);
2387 node->data = folder->node->data;
2388 g_node_destroy(folder->node);
2389 folder->node = node;
2391 FOLDER_ITEM(node->data)->collapsed = collapsed;
2392 FOLDER_ITEM(node->data)->threaded = threaded;
2393 FOLDER_ITEM(node->data)->account = account;
2394 FOLDER_ITEM(node->data)->apply_sub = apply_sub;
2395 FOLDER_ITEM(node->data)->ret_rcpt = ret_rcpt;
2397 g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
2398 folder_build_tree, folder);
2403 static gchar *folder_get_list_path(void)
2405 static gchar *filename = NULL;
2408 filename = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
2414 #define PUT_ESCAPE_STR(fp, attr, str) \
2416 fputs(" " attr "=\"", fp); \
2417 xml_file_put_escape_str(fp, str); \
2421 static void folder_write_list_recursive(GNode *node, gpointer data)
2423 FILE *fp = (FILE *)data;
2426 static gchar *folder_type_str[] = {"mh", "mbox", "maildir", "imap",
2428 static gchar *folder_item_stype_str[] = {"normal", "inbox", "outbox",
2429 "draft", "queue", "trash"};
2430 static gchar *sort_key_str[] = {"none", "number", "size", "date",
2431 "from", "subject", "score", "label",
2432 "mark", "unread", "mime", "to",
2434 g_return_if_fail(node != NULL);
2435 g_return_if_fail(fp != NULL);
2437 item = FOLDER_ITEM(node->data);
2438 g_return_if_fail(item != NULL);
2440 depth = g_node_depth(node);
2441 for (i = 0; i < depth; i++)
2444 Folder *folder = item->folder;
2446 fprintf(fp, "<folder type=\"%s\"", folder_type_str[folder->type]);
2448 PUT_ESCAPE_STR(fp, "name", folder->name);
2449 if (folder->type == F_MH || folder->type == F_MBOX)
2450 PUT_ESCAPE_STR(fp, "path",
2451 LOCAL_FOLDER(folder)->rootpath);
2452 if (item->collapsed && node->children)
2453 fputs(" collapsed=\"1\"", fp);
2454 if (folder->account)
2455 fprintf(fp, " account_id=\"%d\"",
2456 folder->account->account_id);
2457 if (item->apply_sub)
2458 fputs(" apply_sub=\"1\"", fp);
2460 fputs(" reqretrcpt=\"1\"", fp);
2462 fprintf(fp, "<folderitem type=\"%s\"",
2463 folder_item_stype_str[item->stype]);
2465 PUT_ESCAPE_STR(fp, "name", item->name);
2467 PUT_ESCAPE_STR(fp, "path", item->path);
2470 fputs(" no_sub=\"1\"", fp);
2471 if (item->no_select)
2472 fputs(" no_select=\"1\"", fp);
2473 if (item->collapsed && node->children)
2474 fputs(" collapsed=\"1\"", fp);
2476 fputs(" threaded=\"1\"", fp);
2478 fputs(" threaded=\"0\"", fp);
2479 if (item->hide_read_msgs)
2480 fputs(" hidereadmsgs=\"1\"", fp);
2482 fputs(" hidereadmsgs=\"0\"", fp);
2484 fputs(" reqretrcpt=\"1\"", fp);
2486 if (item->sort_key != SORT_BY_NONE) {
2487 fprintf(fp, " sort_key=\"%s\"",
2488 sort_key_str[item->sort_key]);
2489 if (item->sort_type == SORT_ASCENDING)
2490 fprintf(fp, " sort_type=\"ascending\"");
2492 fprintf(fp, " sort_type=\"descending\"");
2496 " mtime=\"%lu\" new=\"%d\" unread=\"%d\" unreadmarked=\"%d\" total=\"%d\"",
2497 item->mtime, item->new, item->unread, item->unreadmarked, item->total);
2500 fprintf(fp, " account_id=\"%d\"",
2501 item->account->account_id);
2502 if (item->apply_sub)
2503 fputs(" apply_sub=\"1\"", fp);
2506 if (node->children) {
2510 child = node->children;
2516 folder_write_list_recursive(cur, data);
2519 for (i = 0; i < depth; i++)
2521 fprintf(fp, "</%s>\n", depth == 1 ? "folder" : "folderitem");
2526 static void folder_update_op_count_rec(GNode *node)
2528 FolderItem *fitem = FOLDER_ITEM(node->data);
2530 if (g_node_depth(node) > 0) {
2531 if (fitem->op_count > 0) {
2532 fitem->op_count = 0;
2533 folder_item_update(fitem, F_ITEM_UPDATE_MSGCNT);
2535 if (node->children) {
2538 child = node->children;
2544 folder_update_op_count_rec(cur);
2550 void folder_update_op_count() {
2554 for (cur = folder_list; cur != NULL; cur = cur->next) {
2556 folder_update_op_count_rec(folder->node);
2560 typedef struct _type_str {
2567 static gchar * folder_item_get_tree_identifier(FolderItem * item)
2569 if (item->parent != NULL) {
2573 path = folder_item_get_tree_identifier(item->parent);
2577 id = g_strconcat(path, "/", item->name, NULL);
2583 return g_strconcat("/", item->name, NULL);
2588 /* CLAWS: temporary local folder for filtering */
2589 static Folder *processing_folder;
2590 static FolderItem *processing_folder_item;
2592 static void folder_create_processing_folder(void)
2594 #define PROCESSING_FOLDER ".processing"
2598 tmpparent = folder_get_default_folder();
2599 g_assert(tmpparent);
2600 debug_print("tmpparentroot %s\n", LOCAL_FOLDER(tmpparent)->rootpath);
2601 if (LOCAL_FOLDER(tmpparent)->rootpath[0] == '/')
2602 tmpname = g_strconcat(LOCAL_FOLDER(tmpparent)->rootpath,
2603 G_DIR_SEPARATOR_S, PROCESSING_FOLDER,
2606 tmpname = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
2607 LOCAL_FOLDER(tmpparent)->rootpath,
2608 G_DIR_SEPARATOR_S, PROCESSING_FOLDER,
2611 processing_folder = folder_new(F_MH, "PROCESSING", LOCAL_FOLDER(tmpparent)->rootpath);
2612 g_assert(processing_folder);
2614 if (!is_dir_exist(tmpname)) {
2615 debug_print("*TMP* creating %s\n", tmpname);
2616 processing_folder_item = processing_folder->create_folder(processing_folder,
2617 processing_folder->node->data,
2619 g_assert(processing_folder_item);
2622 debug_print("*TMP* already created\n");
2623 processing_folder_item = folder_item_new(processing_folder, ".processing", ".processing");
2624 g_assert(processing_folder_item);
2625 folder_item_append(processing_folder->node->data, processing_folder_item);
2630 FolderItem *folder_get_default_processing(void)
2632 if (!processing_folder_item) {
2633 folder_create_processing_folder();
2635 return processing_folder_item;
2638 /* folder_persist_prefs_new() - return hash table with persistent
2639 * settings (and folder name as key).
2640 * (note that in claws other options are in the PREFS_FOLDER_ITEM_RC
2641 * file, so those don't need to be included in PersistPref yet)
2643 GHashTable *folder_persist_prefs_new(Folder *folder)
2645 GHashTable *pptable;
2647 g_return_val_if_fail(folder, NULL);
2648 pptable = g_hash_table_new(g_str_hash, g_str_equal);
2649 folder_get_persist_prefs_recursive(folder->node, pptable);
2653 void folder_persist_prefs_free(GHashTable *pptable)
2655 g_return_if_fail(pptable);
2656 g_hash_table_foreach_remove(pptable, persist_prefs_free, NULL);
2657 g_hash_table_destroy(pptable);
2660 const PersistPrefs *folder_get_persist_prefs(GHashTable *pptable, const char *name)
2662 if (pptable == NULL || name == NULL) return NULL;
2663 return g_hash_table_lookup(pptable, name);
2666 void folder_item_restore_persist_prefs(FolderItem *item, GHashTable *pptable)
2668 const PersistPrefs *pp;
2669 gchar *id = folder_item_get_identifier(item);
2671 pp = folder_get_persist_prefs(pptable, id);
2676 /* CLAWS: since not all folder properties have been migrated to
2677 * folderlist.xml, we need to call the old stuff first before
2678 * setting things that apply both to Main and Claws. */
2679 prefs_folder_item_read_config(item);
2681 item->collapsed = pp->collapsed;
2682 item->threaded = pp->threaded;
2683 item->ret_rcpt = pp->ret_rcpt;
2684 item->hide_read_msgs = pp->hide_read_msgs;
2685 item->sort_key = pp->sort_key;
2686 item->sort_type = pp->sort_type;
2689 static void folder_get_persist_prefs_recursive(GNode *node, GHashTable *pptable)
2691 FolderItem *item = FOLDER_ITEM(node->data);
2696 g_return_if_fail(node != NULL);
2697 g_return_if_fail(item != NULL);
2699 /* NOTE: item->path == NULL means top level folder; not interesting
2700 * to store preferences of that one. */
2702 id = folder_item_get_identifier(item);
2703 pp = g_new0(PersistPrefs, 1);
2704 g_return_if_fail(pp != NULL);
2705 pp->collapsed = item->collapsed;
2706 pp->threaded = item->threaded;
2707 pp->ret_rcpt = item->ret_rcpt;
2708 pp->hide_read_msgs = item->hide_read_msgs;
2709 pp->sort_key = item->sort_key;
2710 pp->sort_type = item->sort_type;
2711 g_hash_table_insert(pptable, id, pp);
2714 if (node->children) {
2715 child = node->children;
2719 folder_get_persist_prefs_recursive(cur, pptable);
2724 static gboolean persist_prefs_free(gpointer key, gpointer val, gpointer data)
2733 void folder_item_apply_processing(FolderItem *item)
2735 GSList *processing_list;
2736 GSList *mlist, *cur;
2738 g_return_if_fail(item != NULL);
2740 processing_list = item->prefs->processing;
2741 if (processing_list == NULL)
2744 folder_item_update_freeze();
2746 mlist = folder_item_get_msg_list(item);
2747 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2750 msginfo = (MsgInfo *) cur->data;
2751 filter_message_by_msginfo(processing_list, msginfo);
2752 procmsg_msginfo_free(msginfo);
2754 g_slist_free(mlist);
2756 folder_item_update_thaw();
2760 * functions for handling FolderItem content changes
2762 static gint folder_item_update_freeze_cnt = 0;
2765 * Notify the folder system about changes to a folder. If the
2766 * update system is not frozen the FOLDER_ITEM_UPDATE_HOOKLIST will
2767 * be invoked, otherwise the changes will be remebered until
2768 * the folder system is thawed.
2770 * \param item The FolderItem that was changed
2771 * \param update_flags Type of changed that was made
2773 void folder_item_update(FolderItem *item, FolderItemUpdateFlags update_flags)
2775 if (folder_item_update_freeze_cnt == 0) {
2776 FolderItemUpdateData source;
2779 source.update_flags = update_flags;
2780 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &source);
2782 item->update_flags |= update_flags;
2786 void folder_item_update_recursive(FolderItem *item, FolderItemUpdateFlags update_flags)
2788 GNode *node = item->folder->node;
2790 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2791 node = node->children;
2793 folder_item_update(item, update_flags);
2794 while (node != NULL) {
2795 if (node && node->data) {
2796 FolderItem *next_item = (FolderItem*) node->data;
2798 folder_item_update(next_item, update_flags);
2804 void folder_item_update_freeze()
2806 folder_item_update_freeze_cnt++;
2809 static void folder_item_update_func(FolderItem *item, gpointer data)
2811 FolderItemUpdateData source;
2813 if (item->update_flags) {
2815 source.update_flags = item->update_flags;
2816 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &source);
2817 item->update_flags = 0;
2821 void folder_item_update_thaw()
2823 if (folder_item_update_freeze_cnt > 0)
2824 folder_item_update_freeze_cnt--;
2825 if (folder_item_update_freeze_cnt == 0) {
2826 /* Update all folders */
2827 folder_func_to_all_folders(folder_item_update_func, NULL);
2831 #undef PUT_ESCAPE_STR