]> git.datanom.net - vfolder.git/blob - src/vfolder.c
initial upload
[vfolder.git] / src / vfolder.c
1 /*
2 * $Id: $
3 */
4 /* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: */
5
6 /*
7 * Virtual folder plugin for claws-mail
8 *
9 * Claws Mail is Copyright (C) 1999-2012 by the Claws Mail Team
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 *
24 */
25
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29
30 #include <glib.h>
31 #include "procmsg.h"
32 #include "procheader.h"
33 #include "folder.h"
34 #include "alertpanel.h"
35 #include "main.h"
36 #include "localfolder.h"
37 #include "statusbar.h"
38
39 #include "vfolder.h"
40 #include "vfolder_gtk.h"
41 #include "vfolder_prop.h"
42
43 typedef struct {
44 LocalFolder folder;
45 } VFolder;
46
47 FolderClass vfolder_class;
48 static gboolean existing_tree_found = FALSE;
49 static GList* vfolders = NULL;
50
51 static void vfolder_get_last_num(Folder *folder, FolderItem *item)
52 {
53 gchar *path;
54 DIR *dp;
55 struct dirent *d;
56 gint max = 0;
57 gint num;
58
59 g_return_if_fail(item != NULL);
60
61 debug_print("vfolder_get_last_num(): Scanning %s ...\n", item->path);
62 path = folder_item_get_path(item);
63 g_return_if_fail(path != NULL);
64 if( change_dir(path) < 0 ) {
65 g_free(path);
66 return;
67 }
68 g_free(path);
69
70 if( (dp = opendir(".")) == NULL ) {
71 FILE_OP_ERROR(item->path, "opendir");
72 return;
73 }
74
75 while( (d = readdir(dp)) != NULL ) {
76 if( (num = to_number(d->d_name)) > 0 && dirent_is_regular_file(d) ) {
77 if( max < num )
78 max = num;
79 }
80 }
81 closedir(dp);
82
83 debug_print("Last number in dir %s = %d\n", item->path, max);
84 item->last_num = max;
85 }
86
87 static void vfolder_init_read_func(FolderItem* item, gpointer data) {
88 g_return_if_fail(item != NULL);
89
90 if (! IS_VFOLDER_FOLDER_ITEM(item))
91 return;
92
93 existing_tree_found = TRUE;
94
95 if (folder_item_parent(item) == NULL)
96 return;
97
98 vfolder_folder_item_props_read(VFOLDER_ITEM(item));
99 vfolder_set_msgs_filter(VFOLDER_ITEM(item));
100
101 /* if (! IS_VFOLDER_FROZEN(VFOLDER_ITEM(item))) {
102 folder_item_scan(VFOLDER_ITEM(item)->source);
103 }*/
104 }
105
106 static void vfolder_make_rc_dir(void) {
107 gchar* vfolder_dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, VFOLDER_DIR, NULL);
108
109 if (! is_dir_exist(vfolder_dir)) {
110 if (make_dir(vfolder_dir) < 0) {
111 g_warning("couldn't create directory %s\n", vfolder_dir);
112 }
113
114 debug_print("created directorty %s\n", vfolder_dir);
115 }
116
117 g_free(vfolder_dir);
118 }
119
120 static void vfolder_create_default_mailbox(void) {
121 Folder* root = NULL;
122
123 vfolder_make_rc_dir();
124
125 root = folder_new(vfolder_folder_get_class(), VFOLDER_DEFAULT_MAILBOX, NULL);
126
127 g_return_if_fail(root != NULL);
128
129 folder_add(root);
130 }
131
132 static gboolean vfolder_scan_required(Folder* folder, FolderItem* item) {
133 return TRUE;
134 }
135
136 static Folder* vfolder_new_folder(const gchar* name, const gchar* path) {
137 VFolder* folder;
138
139 debug_print("VFolder: new_folder\n");
140
141 vfolder_make_rc_dir();
142
143 folder = g_new0(VFolder, 1);
144 FOLDER(folder)->klass = &vfolder_class;
145 folder_init(FOLDER(folder), name);
146
147 return FOLDER(folder);
148 }
149
150 static void vfolder_destroy_folder(Folder* _folder)
151 {
152 VFolder* folder = VFOLDER(_folder);
153
154 folder_local_folder_destroy(LOCAL_FOLDER(folder));
155 }
156
157 static gint vfolder_remove_folder(Folder* folder, FolderItem* item) {
158 GDir* dp;
159 const gchar* name;
160 gchar* cwd;
161 gint ret = -1;
162
163 g_return_val_if_fail(folder != NULL, -1);
164 g_return_val_if_fail(item != NULL, -1);
165 g_return_val_if_fail(item->path != NULL, -1);
166 g_return_val_if_fail(item->stype == F_NORMAL, -1);
167
168 debug_print("VFolder: removing folder item %s\n", item->path);
169
170 gchar* path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
171 VFOLDER_DIR, G_DIR_SEPARATOR_S, item->name, NULL);
172 remove_numbered_files(path, item->last_num - item->total_msgs + 1, item->last_num);
173
174 folder_item_remove(item);
175
176 cwd = g_get_current_dir();
177
178 if (change_dir(path) < 0 ) {
179 g_free(path);
180 return ret;
181 }
182
183 if( (dp = g_dir_open(".", 0, NULL)) == NULL ) {
184 FILE_OP_ERROR(path, "g_dir_open");
185 change_dir(cwd);
186 g_free(cwd);
187 return ret;
188 }
189
190 while ((name = g_dir_read_name(dp)) != NULL) {
191 debug_print("Removing: %s\n", name);
192 claws_unlink(name);
193 }
194 g_dir_close(dp);
195 change_dir(cwd);
196 if (g_rmdir(path) == 0)
197 ret = 0;
198
199 g_free(cwd);
200 g_free(path);
201
202 return ret;
203 }
204
205 static void vfolder_remove_hashtables(VFolderItem* item) {
206 if (item->me_to_claws) {
207 g_hash_table_destroy(item->me_to_claws);
208 item->me_to_claws = NULL;
209 }
210 if (item->claws_to_me) {
211 g_hash_table_destroy(item->claws_to_me);
212 item->claws_to_me = NULL;
213 }
214 }
215
216 static gboolean vfolder_remove_msg_from_bridge(VFolderItem* item,
217 guint src,
218 guint dest) {
219 gboolean ret = FALSE;
220
221 debug_print("Removing from hashtable: src->%u dest->%u\n", src, dest);
222 ret = g_hash_table_remove(item->me_to_claws, GUINT_TO_POINTER(dest));
223 ret = g_hash_table_remove(item->claws_to_me, GUINT_TO_POINTER(src));
224
225 return (ret == FALSE);
226 }
227 /*
228 static gboolean vfolder_remove_msg_bridge_claws(VFolderItem* item, guint num) {
229 return vfolder_remove_msg_from_bridge_rel(item, num, TRUE);
230 }
231
232 static gboolean vfolder_remove_msg_bridge_vfolder(VFolderItem* item, guint num) {
233 return vfolder_remove_msg_from_bridge_rel(item, num, FALSE);
234 }
235 */
236 static void vfolder_free_hashtable_data(gpointer data) {
237 g_free(data);
238 }
239
240 static MsgBridge* vfolder_create_bridge(guint src, guint dest) {
241 MsgBridge* bridge;
242
243 bridge = g_new0(MsgBridge, 1);
244 bridge->my_num = dest;
245 bridge->claws_num = src;
246
247 return bridge;
248 }
249
250 static GHashTable* vfolder_hashtable_new() {
251 return g_hash_table_new_full(g_direct_hash,
252 g_direct_equal, NULL, vfolder_free_hashtable_data);
253 }
254
255 static gboolean vfolder_add_msg_to_message_bridge(VFolderItem* item,
256 guint src,
257 guint dest) {
258 gboolean ret = FALSE;
259 MsgBridge* bridge;
260
261 if (! item->me_to_claws)
262 item->me_to_claws = vfolder_hashtable_new();
263 if (! item->claws_to_me)
264 item->claws_to_me = vfolder_hashtable_new();
265
266 debug_print("Adding to hashtable: src->%u dest->%u\n", src, dest);
267 bridge = vfolder_create_bridge(src, dest);
268 g_hash_table_replace(item->me_to_claws, GUINT_TO_POINTER(dest), bridge);
269
270 bridge = vfolder_create_bridge(src, dest);
271 g_hash_table_replace(item->claws_to_me, GUINT_TO_POINTER(src), bridge);
272
273 return ret;
274 }
275
276 static FolderItem* vfolder_item_new(Folder* folder) {
277 VFolderItem* vitem;
278
279 debug_print("VFolder: item_new\n");
280
281 vitem = g_new0(VFolderItem, 1);
282
283 gchar* id = folder_get_identifier(folder);
284 gchar* cmp = g_strconcat("#", VFOLDER_DIR, G_DIR_SEPARATOR_S, NULL);
285 if (id && strcmp(cmp, id) != 0) {
286 debug_print("Creating folder item: %s\n", id);
287 g_free(id);
288 vfolders = g_list_prepend(vfolders, vitem);
289 }
290 g_free(cmp);
291
292 return FOLDER_ITEM(vitem);
293 }
294
295 static void vfolder_item_destroy(Folder* folder, FolderItem* item) {
296 VFolderItem* vitem = VFOLDER_ITEM(item);
297
298 g_return_if_fail(vitem != NULL);
299
300 debug_print("Number of elements in 'vfolders': %d\n", g_list_length(vfolders));
301 vfolders = g_list_remove(vfolders, vitem);
302 debug_print("Number of elements in 'vfolders': %d\n", g_list_length(vfolders));
303
304 g_free(vitem->filter);
305
306 vfolder_remove_hashtables(vitem);
307 vitem->source = NULL;
308
309 g_free(item);
310 item = NULL;
311 }
312
313 static FolderItem* vfolder_create_folder(Folder* folder,
314 FolderItem* parent,
315 const gchar* name) {
316 gchar* path = NULL;
317 FolderItem* newitem = NULL;
318
319 g_return_val_if_fail(folder != NULL, NULL);
320 g_return_val_if_fail(parent != NULL, NULL);
321 g_return_val_if_fail(name != NULL, NULL);
322
323 if (parent->no_sub)
324 return NULL;
325
326 path = g_strconcat((parent->path != NULL) ? parent->path : "", ".",
327 name, NULL);
328 newitem = folder_item_new(folder, name, path);
329 newitem->no_sub = TRUE;
330
331 folder_item_append(parent, newitem);
332 g_free(path);
333
334 return newitem;
335 }
336
337 static gchar* vfolder_item_get_path(Folder* folder, FolderItem* item) {
338 gchar* result;
339 result = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, VFOLDER_DIR,
340 G_DIR_SEPARATOR_S, item->name, NULL);
341 return result;
342 }
343
344 static gint vfolder_get_num_list(Folder* folder, FolderItem* item,
345 MsgNumberList** list, gboolean* old_uids_valid) {
346 gchar* path;
347 DIR* dp;
348 struct dirent* d;
349 gint num, nummsgs = 0;
350
351 g_return_val_if_fail(item != NULL, -1);
352
353 debug_print("VFolder: scanning '%s'...\n", item->path);
354
355 *old_uids_valid = TRUE;
356
357 path = folder_item_get_path(item);
358 g_return_val_if_fail(path != NULL, -1);
359 if (change_dir(path) < 0 ) {
360 g_free(path);
361 return -1;
362 }
363 g_free(path);
364
365 if( (dp = opendir(".")) == NULL ) {
366 FILE_OP_ERROR(item->path, "opendir");
367 return -1;
368 }
369
370 while ((d = readdir(dp)) != NULL ) {
371 if( (num = to_number(d->d_name)) > 0 ) {
372 debug_print("Adding %d to list\n", num);
373 *list = g_slist_prepend(*list, GINT_TO_POINTER(num));
374 nummsgs++;
375 }
376 }
377 closedir(dp);
378
379 return nummsgs;
380 }
381
382 static gint vfolder_create_tree(Folder* folder) {
383 FolderItem* rootitem;
384 GNode* rootnode;
385
386 vfolder_make_rc_dir();
387
388 if (!folder->node) {
389 rootitem = folder_item_new(folder, folder->name, NULL);
390 rootitem->folder = folder;
391 rootnode = g_node_new(rootitem);
392 folder->node = rootnode;
393 rootitem->node = rootnode;
394 } else {
395 rootitem = FOLDER_ITEM(folder->node->data);
396 rootnode = folder->node;
397 }
398
399 debug_print("VFolder: created new vfolder tree\n");
400 return 0;
401 }
402
403 static gint vfolder_scan_tree(Folder *folder) {
404 g_return_val_if_fail(folder != NULL, -1);
405
406 folder->outbox = NULL;
407 folder->draft = NULL;
408 folder->queue = NULL;
409 folder->trash = NULL;
410
411 debug_print("VFolder: scanning tree\n");
412 vfolder_create_tree(folder);
413
414 return 0;
415 }
416
417 static gchar* vfolder_get_new_msg_filename(FolderItem* dest) {
418 gchar* destfile;
419 gchar* destpath;
420
421 destpath = folder_item_get_path(dest);
422 g_return_val_if_fail(destpath != NULL, NULL);
423
424 if( !is_dir_exist(destpath) )
425 make_dir_hier(destpath);
426
427 for( ; ; ) {
428 destfile = g_strdup_printf("%s%c%d", destpath, G_DIR_SEPARATOR,
429 dest->last_num + 1);
430 if( is_file_entry_exist(destfile) ) {
431 dest->last_num++;
432 g_free(destfile);
433 } else
434 break;
435 }
436
437 g_free(destpath);
438
439 return destfile;
440 }
441
442 static gint vfolder_add_msgs(Folder* folder, FolderItem* dest, GSList* file_list,
443 GHashTable* relation) {
444 gchar* destfile;
445 GSList* cur;
446 MsgFileInfo* fileinfo;
447 gint r = -1;
448 VFolderItem* vitem;
449
450 g_return_val_if_fail(dest != NULL, -1);
451 g_return_val_if_fail(file_list != NULL, -1);
452
453 vitem = VFOLDER_ITEM(dest);
454 if( dest->last_num < 0 ) {
455 vfolder_get_last_num(folder, dest);
456 if( dest->last_num < 0 ) return -1;
457 }
458
459 for( cur = file_list; cur != NULL; cur = cur->next ) {
460 fileinfo = (MsgFileInfo *)cur->data;
461
462 destfile = vfolder_get_new_msg_filename(dest);
463 if (! destfile)
464 goto bail;
465
466 #ifdef G_OS_UNIX
467 if (! vitem->deep_copy)
468 r = symlink(fileinfo->file, destfile);
469
470 if (r < 0) {
471 if (! vitem->deep_copy) {
472 g_warning("Requested sparse folder is not possible.\n"
473 "Using plain file copy instead\n");
474 }
475 #endif
476 if (copy_file(fileinfo->file, destfile, TRUE) < 0) {
477 g_warning("can't copy message %s to %s\n", fileinfo->file, destfile);
478 g_free(destfile);
479 destfile = NULL;
480 goto bail;
481 }
482 vitem->deep_copy = TRUE;
483
484 #ifdef G_OS_UNIX
485 }
486 #endif
487
488 if( relation != NULL )
489 g_hash_table_insert(relation, fileinfo,
490 GINT_TO_POINTER(dest->last_num + 1) );
491 g_free(destfile);
492 vfolder_add_msg_to_message_bridge(vitem,
493 fileinfo->msginfo->msgnum, dest->last_num + 1);
494 dest->last_num++;
495 vfolder_folder_item_props_write(VFOLDER_ITEM(dest));
496 }
497
498 bail:
499
500 return (destfile) ? dest->last_num : -1;
501 }
502
503 static gint vfolder_add_msg(Folder* folder, FolderItem* dest, const gchar* file,
504 MsgFlags* flags) {
505 gint ret;
506 GSList file_list;
507 MsgFileInfo fileinfo;
508
509 g_return_val_if_fail(file != NULL, -1);
510
511 fileinfo.msginfo = NULL;
512 fileinfo.file = (gchar *)file;
513 fileinfo.flags = flags;
514 file_list.data = &fileinfo;
515 file_list.next = NULL;
516
517 ret = vfolder_add_msgs(folder, dest, &file_list, NULL);
518 return ret;
519 }
520
521 static gint vfolder_copy_msgs(Folder *folder, FolderItem *dest,
522 MsgInfoList *msglist, GHashTable *relation) {
523 MsgInfo *msginfo;
524 FolderItem *src;
525 GSList* cur = NULL;
526 gint last_num = 0;
527
528 g_return_val_if_fail(dest != NULL && IS_VFOLDER_FOLDER_ITEM(dest), -1);
529
530 if (! VFOLDER_ITEM(dest)->deep_copy)
531 return -1;
532
533 g_return_val_if_fail(folder != NULL, -1);
534 g_return_val_if_fail(msglist != NULL, -1);
535
536 if( dest->last_num < 0 ) {
537 vfolder_get_last_num(folder, dest);
538 if( dest->last_num < 0 ) return -1;
539 }
540
541 msginfo = (MsgInfo *)msglist->data;
542 g_return_val_if_fail(msginfo->folder != NULL, -1);
543
544 statusbar_print_all(_("Copying messages..."));
545
546 src = msginfo->folder;
547 if (src->folder != dest->folder) {
548 GSList *infolist = NULL, *cur;
549 int res = -1;
550 for (cur = msglist; cur; cur = cur->next) {
551 msginfo = (MsgInfo *)cur->data;
552 MsgFileInfo *fileinfo = g_new0(MsgFileInfo, 1);
553 fileinfo->file = procmsg_get_message_file(msginfo);
554 fileinfo->flags = &(msginfo->flags);
555 infolist = g_slist_prepend(infolist, fileinfo);
556 }
557 infolist = g_slist_reverse(infolist);
558 res = folder_item_add_msgs(dest, infolist, FALSE);
559 for (cur = infolist; cur; cur = cur->next) {
560 MsgFileInfo *info = (MsgFileInfo *)cur->data;
561 g_free(info->file);
562 g_free(info);
563 }
564 g_slist_free(infolist);
565 statusbar_pop_all();
566 return res;
567 }
568
569 for (cur = msglist; cur != NULL; cur = g_slist_next(cur)) {
570 MsgInfo* msginfo = (MsgInfo *)cur->data;
571
572 /* put the local file in the folder cache, so that we don't
573 * have to fetch it back later. */
574 if (msginfo) {
575 gchar *cache_path = folder_item_get_path(msginfo->folder);
576 debug_print("cache_path: %s\n", cache_path);
577 gchar *real_file = g_strconcat(
578 cache_path, G_DIR_SEPARATOR_S,
579 itos(msginfo->msgnum), NULL);
580 debug_print("real_file: %s\n", real_file);
581 gchar *cache_file = NULL;
582 g_free(cache_path);
583 cache_path = folder_item_get_path(dest);
584 debug_print("cache_path: %s\n", cache_path);
585 cache_file = vfolder_get_new_msg_filename(dest);
586 debug_print("cache_file: %s\n", cache_file);
587 if (!is_dir_exist(cache_path))
588 make_dir_hier(cache_path);
589 if (is_file_exist(real_file) && is_dir_exist(cache_path)) {
590 g_hash_table_insert(relation, msginfo, GINT_TO_POINTER(dest->last_num));
591 if (dest->last_num > last_num)
592 last_num = dest->last_num;
593 copy_file(real_file, cache_file, TRUE);
594 debug_print("copied to cache: %s\n", cache_file);
595 }
596 g_free(real_file);
597 g_free(cache_file);
598 g_free(cache_path);
599 }
600 }
601 statusbar_pop_all();
602
603 //dest->cache_dirty = 1;
604 //folder_item_update_thaw();
605
606 return last_num;
607 }
608
609 static gint vfolder_copy_msg(Folder* folder, FolderItem* dest, MsgInfo* msginfo) {
610 GSList msglist;
611
612 g_return_val_if_fail(dest != NULL && IS_VFOLDER_FOLDER_ITEM(dest), -1);
613
614 if (! VFOLDER_ITEM(dest)->deep_copy)
615 return -1;
616
617 g_return_val_if_fail(folder != NULL, -1);
618 g_return_val_if_fail(msginfo != NULL, -1);
619
620 g_return_val_if_fail(msginfo != NULL, -1);
621
622 msglist.data = msginfo;
623 msglist.next = NULL;
624
625 return vfolder_copy_msgs(folder, dest, &msglist, NULL);
626 }
627
628 static gchar* vfolder_fetch_msg(Folder* folder, FolderItem* item, gint num) {
629 gchar* snum = g_strdup_printf("%d", num);
630 gchar* file = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, VFOLDER_DIR,
631 G_DIR_SEPARATOR_S, item->name, G_DIR_SEPARATOR_S, snum, NULL);
632
633 debug_print("VFolder: fetch_msg: '%s'\n", file);
634
635 g_free(snum);
636
637 return file;
638 }
639
640 static MsgInfo* vfolder_get_msginfo(Folder* folder, FolderItem* item, gint num) {
641 MsgInfo* msginfo = NULL;
642 gchar* file;
643 MsgFlags flags;
644
645 debug_print("VFolder: get_msginfo: %d\n", num);
646
647 g_return_val_if_fail(folder != NULL, NULL);
648 g_return_val_if_fail(item != NULL, NULL);
649 g_return_val_if_fail(num > 0, NULL);
650
651 file = vfolder_fetch_msg(folder, item, num);
652 if (! g_file_test(file, G_FILE_TEST_EXISTS)) {
653 g_free(file);
654 return NULL;
655 }
656
657 flags.perm_flags = MSG_NEW | MSG_UNREAD;
658 flags.tmp_flags = 0;
659
660 msginfo = procheader_parse_file(file, flags, TRUE, TRUE);
661
662 if (msginfo)
663 msginfo->msgnum = num;
664
665 if (!msginfo->folder)
666 msginfo->folder = item;
667
668 g_free(file);
669
670 return msginfo;
671 }
672
673 static gint vfolder_remove_msg(Folder* folder, FolderItem* item, gint num)
674 {
675 gboolean need_scan = FALSE;
676 gchar *file, *tmp;
677
678 g_return_val_if_fail(item != NULL, -1);
679
680 file = vfolder_fetch_msg(folder, item, num);
681 g_return_val_if_fail(file != NULL, -1);
682
683 need_scan = vfolder_scan_required(folder, item);
684
685 /* are we doing a folder move ? */
686 tmp = g_strdup_printf("%s.tmp", file);
687 if (is_file_exist(tmp)) {
688 claws_unlink(tmp);
689 g_free(tmp);
690 g_free(file);
691 return 0;
692 }
693 g_free(tmp);
694
695 if( claws_unlink(file) < 0 ) {
696 FILE_OP_ERROR(file, "unlink");
697 g_free(file);
698 return -1;
699 }
700
701 MsgInfo* msginfo = vfolder_find_msg_from_vfolder_num(VFOLDER_ITEM(item), num);
702 if (msginfo) {
703 vfolder_remove_msg_from_bridge(VFOLDER_ITEM(item), msginfo->msgnum, num);
704 vfolder_folder_item_props_write(VFOLDER_ITEM(item));
705 }
706 else {
707 MsgBridge* bridge = g_hash_table_lookup(VFOLDER_ITEM(item)->me_to_claws, GUINT_TO_POINTER(num));
708 if (bridge) {
709 vfolder_remove_msg_from_bridge(VFOLDER_ITEM(item), bridge->claws_num, num);
710 vfolder_folder_item_props_write(VFOLDER_ITEM(item));
711 }
712 }
713
714 if( !need_scan )
715 item->mtime = time(NULL);
716
717 g_free(file);
718
719 return 0;
720 }
721
722 static gint vfolder_remove_all_msg(Folder* folder, FolderItem* item) {
723 GSList *msg_list, *list;
724
725 g_return_val_if_fail(item != NULL, -1);
726
727 msg_list = folder_item_get_msg_list(item);
728 if (msg_list) {
729 for (list = msg_list; list; list = g_slist_next(list)) {
730 MsgInfo* msginfo = (MsgInfo *) list->data;
731 folder_item_remove_msg(item, msginfo->msgnum);
732 }
733 }
734 g_slist_free(msg_list);
735
736 vfolder_remove_hashtables(VFOLDER_ITEM(item));
737
738 return 0;
739 }
740
741 static gboolean vfolder_subscribe_uri(Folder* folder, const gchar* uri) {
742 return FALSE;
743 }
744
745 static void vfolder_print_hash_table(GHashTable* hash) {
746 GHashTableIter iter;
747 gpointer key, value;
748
749 if (hash) {
750 g_hash_table_iter_init (&iter, hash);
751 while (g_hash_table_iter_next(&iter, &key, &value)) {
752 guint key = GPOINTER_TO_UINT(key);
753 MsgBridge* bridge = (MsgBridge *) value;
754 fprintf(stderr, "key: %u ----- me: %u -> claws: %u\n",
755 key, bridge->my_num, bridge->claws_num);
756 }
757 }
758 }
759
760 static MsgInfo* vfolder_find_msg_from_num_rel(VFolderItem* item,
761 guint msgnum,
762 gboolean claws_to_me) {
763 MsgInfo* msginfo = NULL;
764 GHashTable* hash;
765
766 g_return_val_if_fail(item != NULL, NULL);
767 if (msgnum < 1)
768 return NULL;
769
770 vfolder_print_hash_table(item->claws_to_me);
771 vfolder_print_hash_table(item->me_to_claws);
772
773 if (claws_to_me)
774 hash = item->claws_to_me;
775 else
776 hash = item->me_to_claws;
777
778 MsgBridge* msgbridge = g_hash_table_lookup(hash, GUINT_TO_POINTER(msgnum));
779
780 if (msgbridge) {
781 if (claws_to_me)
782 msginfo = folder_item_get_msginfo(FOLDER_ITEM(item), msgbridge->my_num);
783 else
784 msginfo = folder_item_get_msginfo(item->source, msgbridge->claws_num);
785 }
786
787 return msginfo;
788 }
789
790 gboolean vfolder_replace_key_in_bridge(VFolderItem* item, guint from, guint to) {
791 gboolean ret = FALSE;
792 MsgBridge *bridge, *old;
793
794 if (! item->me_to_claws || ! item->claws_to_me)
795 return TRUE;
796
797 old = g_hash_table_lookup(item->claws_to_me, GUINT_TO_POINTER(from));
798 if (!old)
799 return TRUE;
800
801 debug_print("Replace key in hashtable: from->%u to->%u\n", from, to);
802 bridge = vfolder_create_bridge(to, old->my_num);
803
804 ret = g_hash_table_remove(item->me_to_claws, GUINT_TO_POINTER(old->my_num));
805 if (!ret) {
806 g_free(bridge);
807 return TRUE;
808 }
809 ret = g_hash_table_remove(item->claws_to_me, GUINT_TO_POINTER(old->claws_num));
810 if (!ret) {
811 bridge->claws_num = from;
812 g_hash_table_replace(item->me_to_claws, GUINT_TO_POINTER(bridge->my_num), bridge);
813 return TRUE;
814 }
815
816 g_hash_table_replace(item->claws_to_me, GUINT_TO_POINTER(bridge->claws_num), bridge);
817 g_hash_table_replace(item->me_to_claws, GUINT_TO_POINTER(bridge->my_num), bridge);
818
819 return ret;
820 }
821
822 gboolean vfolder_add_message_to_bridge(VFolderItem* item, MsgBridge* bridge) {
823 if (!item || !bridge)
824 return TRUE;
825
826 return vfolder_add_msg_to_message_bridge(item, bridge->claws_num, bridge->my_num);
827 }
828
829 MsgInfo* vfolder_find_msg_from_claws_num(VFolderItem* item, guint msgnum) {
830 return vfolder_find_msg_from_num_rel(item, msgnum, TRUE);
831 }
832
833 MsgInfo* vfolder_find_msg_from_vfolder_num(VFolderItem* item, guint msgnum) {
834 return vfolder_find_msg_from_num_rel(item, msgnum, FALSE);
835 }
836
837 GList* vfolder_get_vfolder_items(void) {
838 return g_list_copy(vfolders);
839 }
840
841 VFolderItem* vfolder_get_vfolder_item(const gchar* name) {
842 VFolderItem* item = NULL;
843 gchar* folder_name = NULL;
844 gchar* this_name = NULL;
845 GList* list = vfolders;
846
847 if (! name)
848 folder_name = g_strdup(VFOLDER_DEFAULT_MAILBOX);
849 else
850 folder_name = g_strdup(name);
851
852 while (list && item == NULL) {
853 this_name = FOLDER_ITEM(list->data)->name;
854 if (this_name && strcmp(folder_name, this_name) == 0)
855 item = VFOLDER_ITEM(list->data);
856 else
857 list = list->next;
858 }
859
860 g_free(folder_name);
861
862 return item;
863 }
864
865 GList* vfolder_get_vfolder_from_source(FolderItem* source) {
866 GList* items = NULL;
867 FolderItem* src = NULL;
868 GList* list = vfolders;
869 gchar* src_id = NULL;
870
871 if (! source)
872 return NULL;
873
874 src_id = folder_item_get_identifier(source);
875 if (!src_id)
876 return NULL;
877
878 while (list) {
879 src = VFOLDER_ITEM(list->data)->source;
880 if (strcmp(folder_item_get_identifier(src), src_id) == 0) {
881 items = g_list_prepend(items, list->data);
882 }
883 list = list->next;
884 }
885
886 return items;
887 }
888
889 typedef struct { GSList* msgnumlist; guint remove; } RemoveInfo;
890 static void find_msg_to_remove(gpointer key, gpointer value, gpointer user_data) {
891 RemoveInfo* remove_info = (RemoveInfo *) user_data;
892
893 if (remove_info->remove == 0) {
894 if (g_slist_index(remove_info->msgnumlist, key) < 0) {
895 MsgBridge* bridge = (MsgBridge *) value;
896 remove_info->remove = bridge->my_num;
897 }
898 }
899 };
900
901 static void vfolder_add_msg_to_folder(VFolderItem* item) {
902 GSList *msgnumlist, *cur;
903 GSList file_list;
904 MsgFileInfo fileinfo;
905 MsgInfoList msgs;
906
907 if (! item->msg_filter_func)
908 return;
909
910 msgnumlist = folder_item_get_number_list(item->source);
911 for (cur = msgnumlist; cur; cur = g_slist_next(cur)) {
912 MsgBridge* bridge = g_hash_table_lookup(item->claws_to_me, cur->data);
913 if (! bridge) {
914 msgs.data = folder_item_get_msginfo(item->source, GPOINTER_TO_UINT(cur->data));
915 msgs.next = NULL;
916 MsgInfoList* list = item->msg_filter_func(&msgs, item);
917 if (list) {
918 fileinfo.msginfo = list->data;
919 fileinfo.file = procmsg_get_message_file_path(fileinfo.msginfo);
920 fileinfo.flags = &fileinfo.msginfo->flags;
921 file_list.data = &fileinfo;
922 file_list.next = NULL;
923 vfolder_add_msgs(item->source->folder, FOLDER_ITEM(item), &file_list, NULL);
924 FOLDER_ITEM(item)->update_flags = F_ITEM_UPDATE_ADDMSG;
925 g_slist_free(list);
926 }
927 }
928 }
929 g_slist_free(msgnumlist);
930 }
931
932 static void vfolder_remove_msg_from_folder(VFolderItem* item) {
933 RemoveInfo remove_info;
934 remove_info.msgnumlist = folder_item_get_number_list(item->source);
935 remove_info.remove = 0;
936 g_hash_table_foreach(item->claws_to_me, find_msg_to_remove, &remove_info);
937 vfolder_remove_msg(FOLDER_ITEM(item)->folder, FOLDER_ITEM(item), remove_info.remove);
938 g_slist_free(remove_info.msgnumlist);
939 FOLDER_ITEM(item)->update_flags = F_ITEM_UPDATE_REMOVEMSG;
940 }
941
942 void vfolder_folder_item_update_msgs(VFolderItem* item, FolderItemUpdateFlags flag) {
943 guint c;
944
945 if (item->frozen || item->updating)
946 return;
947
948 if (item->claws_to_me) {
949 item->updating = TRUE;
950 switch (flag) {
951 case F_ITEM_UPDATE_MSGCNT:
952 break;
953 case F_ITEM_UPDATE_CONTENT:
954 c = g_hash_table_size(item->claws_to_me);
955 if (c < item->source->total_msgs) {
956 /* add messages */
957 vfolder_add_msg_to_folder(item);
958 }
959 else if (c > item->source->total_msgs) {
960 /* remove messages */
961 vfolder_remove_msg_from_folder(item);
962 }
963 break;
964 case F_ITEM_UPDATE_ADDMSG:
965 vfolder_add_msg_to_folder(item);
966 break;
967 case F_ITEM_UPDATE_REMOVEMSG:
968 vfolder_remove_msg_from_folder(item);
969 break;
970 case F_ITEM_UPDATE_NAME:
971 break;
972 }
973 item->updating = FALSE;
974 }
975 }
976
977 FolderClass* vfolder_folder_get_class() {
978 if (vfolder_class.idstr == NULL ) {
979 vfolder_class.type = F_UNKNOWN;
980 vfolder_class.idstr = "vfolder";
981 vfolder_class.uistr = "VFolder";
982
983 /* Folder functions */
984 vfolder_class.new_folder = vfolder_new_folder;
985 vfolder_class.destroy_folder = vfolder_destroy_folder;
986 vfolder_class.set_xml = folder_set_xml;
987 vfolder_class.get_xml = folder_get_xml;
988 vfolder_class.scan_tree = vfolder_scan_tree;
989 vfolder_class.create_tree = vfolder_create_tree;
990
991 /* FolderItem functions */
992 vfolder_class.item_new = vfolder_item_new;
993 vfolder_class.item_destroy = vfolder_item_destroy;
994 vfolder_class.item_get_path = vfolder_item_get_path;
995 vfolder_class.create_folder = vfolder_create_folder;
996 vfolder_class.rename_folder = NULL;
997 vfolder_class.remove_folder = vfolder_remove_folder;
998 vfolder_class.get_num_list = vfolder_get_num_list;
999 vfolder_class.scan_required = vfolder_scan_required;
1000
1001 /* Message functions */
1002 vfolder_class.get_msginfo = vfolder_get_msginfo;
1003 vfolder_class.fetch_msg = vfolder_fetch_msg;
1004 vfolder_class.copy_msgs = vfolder_copy_msgs;
1005 vfolder_class.copy_msg = vfolder_copy_msg;
1006 vfolder_class.add_msg = vfolder_add_msg;
1007 vfolder_class.add_msgs = vfolder_add_msgs;
1008 vfolder_class.remove_msg = vfolder_remove_msg;
1009 vfolder_class.remove_msgs = NULL;
1010 vfolder_class.remove_all_msg = vfolder_remove_all_msg;
1011 vfolder_class.change_flags = NULL;
1012 vfolder_class.subscribe = vfolder_subscribe_uri;
1013 debug_print("VFolder: registered folderclass\n");
1014 }
1015
1016 return &vfolder_class;
1017 }
1018
1019 /* Local functions */
1020
1021 gboolean vfolder_init(void) {
1022 gchar* error = g_new0(gchar, 1);
1023
1024 folder_register_class(vfolder_folder_get_class());
1025
1026 if (! vfolder_gtk_init(&error)) {
1027 alertpanel_error("%s", error);
1028 vfolder_done();
1029 return FALSE;
1030 }
1031
1032 folder_func_to_all_folders((FolderItemFunc)vfolder_init_read_func, NULL);
1033
1034 if (existing_tree_found == FALSE)
1035 vfolder_create_default_mailbox();
1036
1037 return TRUE;
1038 }
1039
1040 void vfolder_done(void) {
1041
1042 vfolder_gtk_done();
1043
1044 if (!claws_is_exiting())
1045 folder_unregister_class(vfolder_folder_get_class());
1046 }
This page took 0.224371 seconds and 6 git commands to generate.