2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2001 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.
32 #include "folderview.h"
37 #include "mbox_folder.h"
43 #include "prefs_account.h"
44 #include "mbox_folder.h"
46 static GList
*folder_list
= NULL
;
48 static void folder_init (Folder
*folder
,
52 static void local_folder_destroy (LocalFolder
*lfolder
);
53 static void remote_folder_destroy (RemoteFolder
*rfolder
);
54 static void mh_folder_destroy (MHFolder
*folder
);
55 static void mbox_folder_destroy (MboxFolder
*folder
);
56 static void imap_folder_destroy (IMAPFolder
*folder
);
57 static void news_folder_destroy (NewsFolder
*folder
);
59 static gboolean
folder_read_folder_func (GNode
*node
,
61 static gchar
*folder_get_list_path (void);
62 static void folder_write_list_recursive (GNode
*node
,
64 static void folder_update_op_count_rec (GNode
*node
);
67 Folder
*folder_new(FolderType type
, const gchar
*name
, const gchar
*path
)
69 Folder
*folder
= NULL
;
71 name
= name
? name
: path
;
74 folder
= mbox_folder_new(name
, path
);
77 folder
= mh_folder_new(name
, path
);
80 folder
= imap_folder_new(name
, path
);
83 folder
= news_folder_new(name
, path
);
92 Folder
*mh_folder_new(const gchar
*name
, const gchar
*path
)
96 folder
= (Folder
*)g_new0(MHFolder
, 1);
97 folder_init(folder
, F_MH
, name
);
98 LOCAL_FOLDER(folder
)->rootpath
= g_strdup(path
);
103 Folder
*mbox_folder_new(const gchar
*name
, const gchar
*path
)
108 folder
= (Folder
*)g_new0(MboxFolder
, 1);
109 folder_init(folder
, F_MBOX
, name
);
110 LOCAL_FOLDER(folder
)->rootpath
= g_strdup(path
);
115 Folder
*maildir_folder_new(const gchar
*name
, const gchar
*path
)
117 /* not yet implemented */
121 Folder
*imap_folder_new(const gchar
*name
, const gchar
*path
)
125 folder
= (Folder
*)g_new0(IMAPFolder
, 1);
126 folder_init(folder
, F_IMAP
, name
);
131 Folder
*news_folder_new(const gchar
*name
, const gchar
*path
)
135 folder
= (Folder
*)g_new0(NewsFolder
, 1);
136 folder_init(folder
, F_NEWS
, name
);
141 FolderItem
*folder_item_new(const gchar
*name
, const gchar
*path
)
145 item
= g_new0(FolderItem
, 1);
147 item
->stype
= F_NORMAL
;
148 item
->name
= g_strdup(name
);
149 item
->path
= g_strdup(path
);
150 item
->account
= NULL
;
156 item
->no_sub
= FALSE
;
157 item
->no_select
= FALSE
;
158 item
->collapsed
= FALSE
;
163 item
->prefs
= prefs_folder_item_new();
168 void folder_item_append(FolderItem
*parent
, FolderItem
*item
)
172 g_return_if_fail(parent
!= NULL
);
173 g_return_if_fail(parent
->folder
!= NULL
);
174 g_return_if_fail(item
!= NULL
);
176 node
= parent
->folder
->node
;
177 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, parent
);
178 g_return_if_fail(node
!= NULL
);
180 item
->parent
= parent
;
181 item
->folder
= parent
->folder
;
182 g_node_append_data(node
, item
);
185 void folder_item_remove(FolderItem
*item
)
189 g_return_if_fail(item
!= NULL
);
190 g_return_if_fail(item
->folder
!= NULL
);
192 node
= item
->folder
->node
;
193 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
194 g_return_if_fail(node
!= NULL
);
196 /* TODO: free all FolderItem's first */
197 if (item
->folder
->node
== node
)
198 item
->folder
->node
= NULL
;
199 g_node_destroy(node
);
202 void folder_item_destroy(FolderItem
*item
)
204 g_return_if_fail(item
!= NULL
);
211 void folder_set_ui_func(Folder
*folder
, FolderUIFunc func
, gpointer data
)
213 g_return_if_fail(folder
!= NULL
);
215 folder
->ui_func
= func
;
216 folder
->ui_func_data
= data
;
219 void folder_set_name(Folder
*folder
, const gchar
*name
)
221 g_return_if_fail(folder
!= NULL
);
223 g_free(folder
->name
);
224 folder
->name
= name
? g_strdup(name
) : NULL
;
225 if (folder
->node
&& folder
->node
->data
) {
226 FolderItem
*item
= (FolderItem
*)folder
->node
->data
;
229 item
->name
= name
? g_strdup(name
) : NULL
;
233 void folder_destroy(Folder
*folder
)
235 g_return_if_fail(folder
!= NULL
);
237 folder_list
= g_list_remove(folder_list
, folder
);
239 switch (folder
->type
) {
241 mh_folder_destroy(MH_FOLDER(folder
));
244 mbox_folder_destroy(MBOX_FOLDER(folder
));
247 imap_folder_destroy(IMAP_FOLDER(folder
));
250 news_folder_destroy(NEWS_FOLDER(folder
));
256 folder_tree_destroy(folder
);
257 g_free(folder
->name
);
261 void folder_tree_destroy(Folder
*folder
)
263 /* TODO: destroy all FolderItem before */
264 g_node_destroy(folder
->node
);
266 folder
->inbox
= NULL
;
267 folder
->outbox
= NULL
;
268 folder
->draft
= NULL
;
269 folder
->queue
= NULL
;
270 folder
->trash
= NULL
;
274 void folder_add(Folder
*folder
)
280 g_return_if_fail(folder
!= NULL
);
282 for (i
= 0, cur
= folder_list
; cur
!= NULL
; cur
= cur
->next
, i
++) {
283 cur_folder
= FOLDER(cur
->data
);
284 if (folder
->type
== F_MH
) {
285 if (cur_folder
->type
!= F_MH
) break;
286 } else if (folder
->type
== F_MBOX
) {
287 if (cur_folder
->type
!= F_MH
&&
288 cur_folder
->type
!= F_MBOX
) break;
289 } else if (folder
->type
== F_IMAP
) {
290 if (cur_folder
->type
!= F_MH
&&
291 cur_folder
->type
!= F_MBOX
&&
292 cur_folder
->type
!= F_IMAP
) break;
293 } else if (folder
->type
== F_NEWS
) {
294 if (cur_folder
->type
!= F_MH
&&
295 cur_folder
->type
!= F_MBOX
&&
296 cur_folder
->type
!= F_IMAP
&&
297 cur_folder
->type
!= F_NEWS
) break;
301 folder_list
= g_list_insert(folder_list
, folder
, i
);
304 GList
*folder_get_list(void)
309 gint
folder_read_list(void)
315 path
= folder_get_list_path();
316 if (!is_file_exist(path
)) return -1;
317 node
= xml_parse_file(path
);
318 if (!node
) return -1;
320 xmlnode
= node
->data
;
321 if (strcmp2(xmlnode
->tag
->tag
, "folderlist") != 0) {
322 g_warning("wrong folder list\n");
327 g_node_traverse(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, 2,
328 folder_read_folder_func
, NULL
);
337 void folder_write_list(void)
344 path
= folder_get_list_path();
345 if ((pfile
= prefs_write_open(path
)) == NULL
) return;
347 fprintf(pfile
->fp
, "<?xml version=\"1.0\" encoding=\"%s\"?>\n",
348 conv_get_current_charset_str());
349 fputs("\n<folderlist>\n", pfile
->fp
);
351 for (list
= folder_list
; list
!= NULL
; list
= list
->next
) {
353 folder_write_list_recursive(folder
->node
, pfile
->fp
);
356 fputs("</folderlist>\n", pfile
->fp
);
358 if (prefs_write_close(pfile
) < 0)
359 g_warning("failed to write folder list.\n");
362 Folder
*folder_find_from_path(const gchar
*path
)
367 for (list
= folder_list
; list
!= NULL
; list
= list
->next
) {
369 if ((folder
->type
== F_MH
|| folder
->type
== F_MBOX
) &&
370 !path_cmp(LOCAL_FOLDER(folder
)->rootpath
, path
))
377 static gboolean
folder_item_find_func(GNode
*node
, gpointer data
)
379 FolderItem
*item
= node
->data
;
381 const gchar
*path
= d
[0];
383 if (path_cmp(path
, item
->path
) != 0)
391 FolderItem
*folder_find_item_from_path(const gchar
*path
)
396 folder
= folder_get_default_folder();
397 g_return_val_if_fail(folder
!= NULL
, NULL
);
399 d
[0] = (gpointer
)path
;
401 g_node_traverse(folder
->node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, -1,
402 folder_item_find_func
, d
);
406 Folder
*folder_get_default_folder(void)
408 return folder_list
? FOLDER(folder_list
->data
) : NULL
;
411 FolderItem
*folder_get_default_inbox(void)
415 if (!folder_list
) return NULL
;
416 folder
= FOLDER(folder_list
->data
);
417 g_return_val_if_fail(folder
!= NULL
, NULL
);
418 return folder
->inbox
;
421 FolderItem
*folder_get_default_outbox(void)
425 if (!folder_list
) return NULL
;
426 folder
= FOLDER(folder_list
->data
);
427 g_return_val_if_fail(folder
!= NULL
, NULL
);
428 return folder
->outbox
;
431 FolderItem
*folder_get_default_draft(void)
435 if (!folder_list
) return NULL
;
436 folder
= FOLDER(folder_list
->data
);
437 g_return_val_if_fail(folder
!= NULL
, NULL
);
438 return folder
->draft
;
441 FolderItem
*folder_get_default_queue(void)
445 if (!folder_list
) return NULL
;
446 folder
= FOLDER(folder_list
->data
);
447 g_return_val_if_fail(folder
!= NULL
, NULL
);
448 return folder
->queue
;
451 FolderItem
*folder_get_default_trash(void)
455 if (!folder_list
) return NULL
;
456 folder
= FOLDER(folder_list
->data
);
457 g_return_val_if_fail(folder
!= NULL
, NULL
);
458 return folder
->trash
;
461 gchar
*folder_item_get_path(FolderItem
*item
)
466 g_return_val_if_fail(item
!= NULL
, NULL
);
468 if (FOLDER_TYPE(item
->folder
) == F_MH
)
469 folder_path
= g_strdup(LOCAL_FOLDER(item
->folder
)->rootpath
);
470 else if (FOLDER_TYPE(item
->folder
) == F_MBOX
) {
471 path
= mbox_get_virtual_path(item
);
474 folder_path
= g_strconcat(get_mbox_cache_dir(),
475 G_DIR_SEPARATOR_S
, path
, NULL
);
480 else if (FOLDER_TYPE(item
->folder
) == F_IMAP
) {
481 g_return_val_if_fail(item
->folder
->account
!= NULL
, NULL
);
482 folder_path
= g_strconcat(get_imap_cache_dir(),
484 item
->folder
->account
->recv_server
,
486 item
->folder
->account
->userid
,
488 } else if (FOLDER_TYPE(item
->folder
) == F_NEWS
) {
489 g_return_val_if_fail(item
->folder
->account
!= NULL
, NULL
);
490 folder_path
= g_strconcat(get_news_cache_dir(),
492 item
->folder
->account
->nntp_server
,
497 g_return_val_if_fail(folder_path
!= NULL
, NULL
);
499 if (folder_path
[0] == G_DIR_SEPARATOR
) {
501 path
= g_strconcat(folder_path
, G_DIR_SEPARATOR_S
,
504 path
= g_strdup(folder_path
);
507 path
= g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S
,
508 folder_path
, G_DIR_SEPARATOR_S
,
511 path
= g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S
,
519 void folder_item_scan(FolderItem
*item
)
523 g_return_if_fail(item
!= NULL
);
525 folder
= item
->folder
;
527 g_return_if_fail(folder
->scan
!= NULL
);
529 folder
->scan(folder
, item
);
532 static void folder_item_scan_foreach_func(gpointer key
, gpointer val
,
535 folder_item_scan(FOLDER_ITEM(key
));
538 void folder_item_scan_foreach(GHashTable
*table
)
540 g_hash_table_foreach(table
, folder_item_scan_foreach_func
, NULL
);
543 gchar
*folder_item_fetch_msg(FolderItem
*item
, gint num
)
547 g_return_val_if_fail(item
!= NULL
, NULL
);
549 folder
= item
->folder
;
551 g_return_val_if_fail(folder
->scan
!= NULL
, NULL
);
552 g_return_val_if_fail(folder
->fetch_msg
!= NULL
, NULL
);
554 if (item
->last_num
< 0) folder
->scan(folder
, item
);
556 return folder
->fetch_msg(folder
, item
, num
);
559 gint
folder_item_add_msg(FolderItem
*dest
, const gchar
*file
,
560 gboolean remove_source
)
565 g_return_val_if_fail(dest
!= NULL
, -1);
566 g_return_val_if_fail(file
!= NULL
, -1);
568 folder
= dest
->folder
;
570 g_return_val_if_fail(folder
->scan
!= NULL
, -1);
571 g_return_val_if_fail(folder
->add_msg
!= NULL
, -1);
573 if (dest
->last_num
< 0) folder
->scan(folder
, dest
);
575 num
= folder
->add_msg(folder
, dest
, file
, remove_source
);
576 if (num
> 0) dest
->last_num
= num
;
582 gint folder_item_move_msg(FolderItem *dest, MsgInfo *msginfo)
587 g_return_val_if_fail(dest != NULL, -1);
588 g_return_val_if_fail(msginfo != NULL, -1);
590 folder = dest->folder;
591 if (dest->last_num < 0) folder->scan(folder, dest);
593 num = folder->move_msg(folder, dest, msginfo);
594 if (num > 0) dest->last_num = num;
600 gint
folder_item_move_msg(FolderItem
*dest
, MsgInfo
*msginfo
)
607 g_return_val_if_fail(dest
!= NULL
, -1);
608 g_return_val_if_fail(msginfo
!= NULL
, -1);
610 folder
= dest
->folder
;
612 g_return_val_if_fail(folder
->scan
!= NULL
, -1);
613 g_return_val_if_fail(folder
->remove_msg
!= NULL
, -1);
614 g_return_val_if_fail(folder
->copy_msg
!= NULL
, -1);
616 if (dest
->last_num
< 0) folder
->scan(folder
, dest
);
618 src_folder
= msginfo
->folder
->folder
;
620 num
= folder
->copy_msg(folder
, dest
, msginfo
);
623 src_folder
->remove_msg(src_folder
,
628 if (folder
->finished_copy
)
629 folder
->finished_copy(folder
, dest
);
631 src_folder
= msginfo
->folder
->folder
;
633 if (msginfo
->folder
&& src_folder
->scan
)
634 src_folder
->scan(src_folder
, msginfo
->folder
);
635 folder
->scan(folder
, dest
);
641 gint folder_item_move_msgs_with_dest(FolderItem *dest, GSList *msglist)
646 g_return_val_if_fail(dest != NULL, -1);
647 g_return_val_if_fail(msglist != NULL, -1);
649 folder = dest->folder;
650 if (dest->last_num < 0) folder->scan(folder, dest);
652 num = folder->move_msgs_with_dest(folder, dest, msglist);
653 if (num > 0) dest->last_num = num;
654 else dest->op_count = 0;
660 gint
folder_item_move_msgs_with_dest(FolderItem
*dest
, GSList
*msglist
)
667 g_return_val_if_fail(dest
!= NULL
, -1);
668 g_return_val_if_fail(msglist
!= NULL
, -1);
670 folder
= dest
->folder
;
672 g_return_val_if_fail(folder
->scan
!= NULL
, -1);
673 g_return_val_if_fail(folder
->copy_msg
!= NULL
, -1);
674 g_return_val_if_fail(folder
->remove_msg
!= NULL
, -1);
676 if (dest
->last_num
< 0) folder
->scan(folder
, dest
);
679 for(l
= msglist
; l
!= NULL
; l
= g_slist_next(l
)) {
680 MsgInfo
* msginfo
= (MsgInfo
*) l
->data
;
682 if (!item
&& msginfo
->folder
!= NULL
)
683 item
= msginfo
->folder
;
685 if (folder
->copy_msg(folder
, dest
, msginfo
) != -1)
686 item
->folder
->remove_msg(item
->folder
,
691 if (folder
->finished_copy
)
692 folder
->finished_copy(folder
, dest
);
694 if (item
&& item
->folder
->scan
)
695 item
->folder
->scan(item
->folder
, item
);
696 folder
->scan(folder
, dest
);
698 return dest
->last_num
;
702 gint folder_item_copy_msg(FolderItem *dest, MsgInfo *msginfo)
707 g_return_val_if_fail(dest != NULL, -1);
708 g_return_val_if_fail(msginfo != NULL, -1);
710 folder = dest->folder;
711 if (dest->last_num < 0) folder->scan(folder, dest);
713 num = folder->copy_msg(folder, dest, msginfo);
714 if (num > 0) dest->last_num = num;
720 gint
folder_item_copy_msg(FolderItem
*dest
, MsgInfo
*msginfo
)
727 g_return_val_if_fail(dest
!= NULL
, -1);
728 g_return_val_if_fail(msginfo
!= NULL
, -1);
730 folder
= dest
->folder
;
732 g_return_val_if_fail(folder
->scan
!= NULL
, -1);
733 g_return_val_if_fail(folder
->copy_msg
!= NULL
, -1);
735 if (dest
->last_num
< 0) folder
->scan(folder
, dest
);
737 num
= folder
->copy_msg(folder
, dest
, msginfo
);
739 if (folder
->finished_copy
)
740 folder
->finished_copy(folder
, dest
);
742 folder
->scan(folder
, dest
);
748 gint folder_item_copy_msgs_with_dest(FolderItem *dest, GSList *msglist)
753 g_return_val_if_fail(dest != NULL, -1);
754 g_return_val_if_fail(msglist != NULL, -1);
756 folder = dest->folder;
757 if (dest->last_num < 0) folder->scan(folder, dest);
759 num = folder->copy_msgs_with_dest(folder, dest, msglist);
760 if (num > 0) dest->last_num = num;
761 else dest->op_count = 0;
767 gint
folder_item_copy_msgs_with_dest(FolderItem
*dest
, GSList
*msglist
)
774 g_return_val_if_fail(dest
!= NULL
, -1);
775 g_return_val_if_fail(msglist
!= NULL
, -1);
777 folder
= dest
->folder
;
779 g_return_val_if_fail(folder
->scan
!= NULL
, -1);
780 g_return_val_if_fail(folder
->copy_msg
!= NULL
, -1);
782 if (dest
->last_num
< 0) folder
->scan(folder
, dest
);
784 for(l
= msglist
; l
!= NULL
; l
= g_slist_next(l
)) {
785 MsgInfo
* msginfo
= (MsgInfo
*) l
->data
;
787 folder
->copy_msg(folder
, dest
, msginfo
);
790 if (folder
->finished_copy
)
791 folder
->finished_copy(folder
, dest
);
793 folder
->scan(folder
, dest
);
795 return dest
->last_num
;
798 gint
folder_item_remove_msg(FolderItem
*item
, gint num
)
803 g_return_val_if_fail(item
!= NULL
, -1);
805 folder
= item
->folder
;
807 g_return_val_if_fail(folder
->scan
!= NULL
, -1);
808 g_return_val_if_fail(folder
->remove_msg
!= NULL
, -1);
810 if (folder
->finished_remove
)
811 folder
->finished_remove(folder
, item
);
813 result
= folder
->remove_msg(folder
, item
, num
);
815 if (item
->last_num
< 0) folder
->scan(folder
, item
);
818 if (folder
->finished_remove
)
819 folder
->finished_remove(folder
, item
);
825 gint
folder_item_remove_all_msg(FolderItem
*item
)
830 g_return_val_if_fail(item
!= NULL
, -1);
832 folder
= item
->folder
;
834 g_return_val_if_fail(folder
->scan
!= NULL
, -1);
835 g_return_val_if_fail(folder
->remove_all_msg
!= NULL
, -1);
837 if (item
->last_num
< 0) folder
->scan(folder
, item
);
839 result
= folder
->remove_all_msg(folder
, item
);
842 if (folder
->finished_remove
)
843 folder
->finished_remove(folder
, item
);
849 gboolean
folder_item_is_msg_changed(FolderItem
*item
, MsgInfo
*msginfo
)
853 g_return_val_if_fail(item
!= NULL
, FALSE
);
855 folder
= item
->folder
;
857 g_return_val_if_fail(folder
->is_msg_changed
!= NULL
, -1);
859 return folder
->is_msg_changed(folder
, item
, msginfo
);
862 gchar
*folder_item_get_cache_file(FolderItem
*item
)
867 g_return_val_if_fail(item
!= NULL
, NULL
);
868 g_return_val_if_fail(item
->path
!= NULL
, NULL
);
870 path
= folder_item_get_path(item
);
871 g_return_val_if_fail(path
!= NULL
, NULL
);
872 if (!is_dir_exist(path
))
874 file
= g_strconcat(path
, G_DIR_SEPARATOR_S
, CACHE_FILE
, NULL
);
880 gchar
*folder_item_get_mark_file(FolderItem
*item
)
885 g_return_val_if_fail(item
!= NULL
, NULL
);
886 g_return_val_if_fail(item
->path
!= NULL
, NULL
);
888 path
= folder_item_get_path(item
);
889 g_return_val_if_fail(path
!= NULL
, NULL
);
890 if (!is_dir_exist(path
))
892 file
= g_strconcat(path
, G_DIR_SEPARATOR_S
, MARK_FILE
, NULL
);
899 static void folder_init(Folder
*folder
, FolderType type
, const gchar
*name
)
903 g_return_if_fail(folder
!= NULL
);
906 folder_set_name(folder
, name
);
907 folder
->account
= NULL
;
908 folder
->inbox
= NULL
;
909 folder
->outbox
= NULL
;
910 folder
->draft
= NULL
;
911 folder
->queue
= NULL
;
912 folder
->trash
= NULL
;
913 folder
->ui_func
= NULL
;
914 folder
->ui_func_data
= NULL
;
915 item
= folder_item_new(name
, NULL
);
916 item
->folder
= folder
;
917 folder
->node
= g_node_new(item
);
922 folder
->get_msg_list
= mh_get_msg_list
;
923 folder
->fetch_msg
= mh_fetch_msg
;
924 folder
->add_msg
= mh_add_msg
;
926 folder->move_msg = mh_move_msg;
927 folder->move_msgs_with_dest = mh_move_msgs_with_dest;
928 folder->copy_msg = mh_copy_msg;
929 folder->copy_msgs_with_dest = mh_copy_msgs_with_dest;
931 folder
->copy_msg
= mh_copy_msg
;
932 folder
->remove_msg
= mh_remove_msg
;
933 folder
->remove_all_msg
= mh_remove_all_msg
;
934 folder
->is_msg_changed
= mh_is_msg_changed
;
935 folder
->scan
= mh_scan_folder
;
936 folder
->scan_tree
= mh_scan_tree
;
937 folder
->create_tree
= mh_create_tree
;
938 folder
->create_folder
= mh_create_folder
;
939 folder
->rename_folder
= mh_rename_folder
;
940 folder
->remove_folder
= mh_remove_folder
;
943 folder
->get_msg_list
= imap_get_msg_list
;
944 folder
->fetch_msg
= imap_fetch_msg
;
945 folder
->add_msg
= imap_add_msg
;
946 folder
->move_msg
= imap_move_msg
;
947 folder
->move_msgs_with_dest
= imap_move_msgs_with_dest
;
948 folder
->copy_msg
= imap_copy_msg
;
949 folder
->copy_msgs_with_dest
= imap_copy_msgs_with_dest
;
950 folder
->remove_msg
= imap_remove_msg
;
951 folder
->remove_all_msg
= imap_remove_all_msg
;
952 folder
->scan
= imap_scan_folder
;
953 folder
->scan_tree
= imap_scan_tree
;
954 folder
->create_tree
= imap_create_tree
;
955 folder
->create_folder
= imap_create_folder
;
956 folder
->remove_folder
= imap_remove_folder
;
959 folder
->get_msg_list
= news_get_article_list
;
960 folder
->fetch_msg
= news_fetch_msg
;
961 folder
->scan
= news_scan_group
;
964 folder
->get_msg_list
= mbox_get_msg_list
;
965 folder
->fetch_msg
= mbox_fetch_msg
;
966 folder
->scan
= mbox_scan_folder
;
967 folder
->add_msg
= mbox_add_msg
;
968 folder
->remove_all_msg
= mbox_remove_all_msg
;
969 folder
->remove_msg
= mbox_remove_msg
;
971 folder->move_msg = mbox_move_msg;
972 folder->move_msgs_with_dest = mbox_move_msgs_with_dest;
973 folder->copy_msg = mbox_copy_msg;
974 folder->copy_msgs_with_dest = mbox_copy_msgs_with_dest;
976 folder
->copy_msg
= mbox_copy_msg
;
978 folder
->create_tree
= mbox_create_tree
;
979 folder
->create_folder
= mbox_create_folder
;
980 folder
->rename_folder
= mbox_rename_folder
;
981 folder
->remove_folder
= mbox_remove_folder
;
983 folder
->update_mark
= mbox_update_mark
;
984 folder
->change_flags
= mbox_change_flags
;
985 folder
->finished_copy
= mbox_finished_copy
;
996 LOCAL_FOLDER(folder
)->rootpath
= NULL
;
1000 REMOTE_FOLDER(folder
)->session
= NULL
;
1007 static void local_folder_destroy(LocalFolder
*lfolder
)
1009 g_return_if_fail(lfolder
!= NULL
);
1011 g_free(lfolder
->rootpath
);
1014 static void remote_folder_destroy(RemoteFolder
*rfolder
)
1016 g_return_if_fail(rfolder
!= NULL
);
1018 if (rfolder
->session
)
1019 session_destroy(rfolder
->session
);
1022 static void mh_folder_destroy(MHFolder
*folder
)
1024 local_folder_destroy(LOCAL_FOLDER(folder
));
1027 static void mbox_folder_destroy(MboxFolder
*folder
)
1029 local_folder_destroy(LOCAL_FOLDER(folder
));
1032 static void imap_folder_destroy(IMAPFolder
*folder
)
1034 remote_folder_destroy(REMOTE_FOLDER(folder
));
1037 static void news_folder_destroy(NewsFolder
*folder
)
1039 remote_folder_destroy(REMOTE_FOLDER(folder
));
1042 static gboolean
folder_build_tree(GNode
*node
, gpointer data
)
1044 Folder
*folder
= FOLDER(data
);
1048 SpecialFolderItemType stype
= F_NORMAL
;
1049 const gchar
*name
= NULL
;
1050 const gchar
*path
= NULL
;
1051 PrefsAccount
*account
= NULL
;
1052 gboolean no_sub
= FALSE
, no_select
= FALSE
, collapsed
= FALSE
;
1053 gint mtime
= 0, new = 0, unread
= 0, total
= 0;
1055 g_return_val_if_fail(node
->data
!= NULL
, FALSE
);
1056 if (!node
->parent
) return FALSE
;
1058 xmlnode
= node
->data
;
1059 if (strcmp2(xmlnode
->tag
->tag
, "folderitem") != 0) {
1060 g_warning("tag name != \"folderitem\"\n");
1064 list
= xmlnode
->tag
->attr
;
1065 for (; list
!= NULL
; list
= list
->next
) {
1066 XMLAttr
*attr
= list
->data
;
1068 if (!attr
|| !attr
->name
|| !attr
->value
) continue;
1069 if (!strcmp(attr
->name
, "type")) {
1070 if (!strcasecmp(attr
->value
, "normal"))
1072 else if (!strcasecmp(attr
->value
, "inbox"))
1074 else if (!strcasecmp(attr
->value
, "outbox"))
1076 else if (!strcasecmp(attr
->value
, "draft"))
1078 else if (!strcasecmp(attr
->value
, "queue"))
1080 else if (!strcasecmp(attr
->value
, "trash"))
1082 } else if (!strcmp(attr
->name
, "name"))
1084 else if (!strcmp(attr
->name
, "path"))
1086 else if (!strcmp(attr
->name
, "account_id")) {
1087 account
= account_find_from_id(atoi(attr
->value
));
1088 if (!account
) g_warning("account_id: %s not found\n",
1090 } else if (!strcmp(attr
->name
, "mtime"))
1091 mtime
= atoi(attr
->value
);
1092 else if (!strcmp(attr
->name
, "new"))
1093 new = atoi(attr
->value
);
1094 else if (!strcmp(attr
->name
, "unread"))
1095 unread
= atoi(attr
->value
);
1096 else if (!strcmp(attr
->name
, "total"))
1097 total
= atoi(attr
->value
);
1098 else if (!strcmp(attr
->name
, "no_sub"))
1099 no_sub
= *attr
->value
== '1' ? TRUE
: FALSE
;
1100 else if (!strcmp(attr
->name
, "no_select"))
1101 no_select
= *attr
->value
== '1' ? TRUE
: FALSE
;
1102 else if (!strcmp(attr
->name
, "collapsed"))
1103 collapsed
= *attr
->value
== '1' ? TRUE
: FALSE
;
1106 item
= folder_item_new(name
, path
);
1107 item
->stype
= stype
;
1108 item
->account
= account
;
1109 item
->mtime
= mtime
;
1111 item
->unread
= unread
;
1112 item
->total
= total
;
1113 item
->no_sub
= no_sub
;
1114 item
->no_select
= no_select
;
1115 item
->collapsed
= collapsed
;
1116 item
->parent
= FOLDER_ITEM(node
->parent
->data
);
1117 item
->folder
= folder
;
1119 case F_INBOX
: folder
->inbox
= item
; break;
1120 case F_OUTBOX
: folder
->outbox
= item
; break;
1121 case F_DRAFT
: folder
->draft
= item
; break;
1122 case F_QUEUE
: folder
->queue
= item
; break;
1123 case F_TRASH
: folder
->trash
= item
; break;
1128 prefs_folder_item_read_config(item
);
1131 xml_free_node(xmlnode
);
1136 static gboolean
folder_read_folder_func(GNode
*node
, gpointer data
)
1141 FolderType type
= F_UNKNOWN
;
1142 const gchar
*name
= NULL
;
1143 const gchar
*path
= NULL
;
1144 PrefsAccount
*account
= NULL
;
1145 gboolean collapsed
= FALSE
;
1147 if (g_node_depth(node
) != 2) return FALSE
;
1148 g_return_val_if_fail(node
->data
!= NULL
, FALSE
);
1150 xmlnode
= node
->data
;
1151 if (strcmp2(xmlnode
->tag
->tag
, "folder") != 0) {
1152 g_warning("tag name != \"folder\"\n");
1155 g_node_unlink(node
);
1156 list
= xmlnode
->tag
->attr
;
1157 for (; list
!= NULL
; list
= list
->next
) {
1158 XMLAttr
*attr
= list
->data
;
1160 if (!attr
|| !attr
->name
|| !attr
->value
) continue;
1161 if (!strcmp(attr
->name
, "type")) {
1162 if (!strcasecmp(attr
->value
, "mh"))
1164 else if (!strcasecmp(attr
->value
, "mbox"))
1166 else if (!strcasecmp(attr
->value
, "maildir"))
1168 else if (!strcasecmp(attr
->value
, "imap"))
1170 else if (!strcasecmp(attr
->value
, "news"))
1172 } else if (!strcmp(attr
->name
, "name"))
1174 else if (!strcmp(attr
->name
, "path"))
1176 else if (!strcmp(attr
->name
, "account_id")) {
1177 account
= account_find_from_id(atoi(attr
->value
));
1178 if (!account
) g_warning("account_id: %s not found\n",
1180 } else if (!strcmp(attr
->name
, "collapsed"))
1181 collapsed
= *attr
->value
== '1' ? TRUE
: FALSE
;
1184 folder
= folder_new(type
, name
, path
);
1185 g_return_val_if_fail(folder
!= NULL
, FALSE
);
1186 folder
->account
= account
;
1187 if (account
&& (type
== F_IMAP
|| type
== F_NEWS
))
1188 account
->folder
= REMOTE_FOLDER(folder
);
1189 node
->data
= folder
->node
->data
;
1190 g_node_destroy(folder
->node
);
1191 folder
->node
= node
;
1193 FOLDER_ITEM(node
->data
)->collapsed
= collapsed
;
1195 g_node_traverse(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, -1,
1196 folder_build_tree
, folder
);
1201 static gchar
*folder_get_list_path(void)
1203 static gchar
*filename
= NULL
;
1206 filename
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
1212 static void folder_write_list_recursive(GNode
*node
, gpointer data
)
1214 FILE *fp
= (FILE *)data
;
1215 FolderItem
*item
= FOLDER_ITEM(node
->data
);
1217 static gchar
*folder_type_str
[] = {"mh", "mbox", "maildir", "imap",
1219 static gchar
*folder_item_stype_str
[] = {"normal", "inbox", "outbox",
1220 "draft", "queue", "trash"};
1222 g_return_if_fail(item
!= NULL
);
1224 depth
= g_node_depth(node
);
1225 for (i
= 0; i
< depth
; i
++)
1228 Folder
*folder
= item
->folder
;
1230 fprintf(fp
, "<folder type=\"%s\"", folder_type_str
[folder
->type
]);
1232 fputs(" name=\"", fp
);
1233 xml_file_put_escape_str(fp
, folder
->name
);
1236 if ((folder
->type
== F_MH
) || (folder
->type
== F_MBOX
)) {
1237 fputs(" path=\"", fp
);
1238 xml_file_put_escape_str
1239 (fp
, LOCAL_FOLDER(folder
)->rootpath
);
1242 if (folder
->account
)
1243 fprintf(fp
, " account_id=\"%d\"",
1244 folder
->account
->account_id
);
1245 if (item
->collapsed
&& node
->children
)
1246 fputs(" collapsed=\"1\"", fp
);
1248 fprintf(fp
, "<folderitem type=\"%s\"",
1249 folder_item_stype_str
[item
->stype
]);
1251 fputs(" name=\"", fp
);
1252 xml_file_put_escape_str(fp
, item
->name
);
1256 fputs(" path=\"", fp
);
1257 xml_file_put_escape_str(fp
, item
->path
);
1261 fprintf(fp
, " account_id=\"%d\"",
1262 item
->account
->account_id
);
1264 fputs(" no_sub=\"1\"", fp
);
1265 if (item
->no_select
)
1266 fputs(" no_select=\"1\"", fp
);
1267 if (item
->collapsed
&& node
->children
)
1268 fputs(" collapsed=\"1\"", fp
);
1270 " mtime=\"%ld\" new=\"%d\" unread=\"%d\" total=\"%d\"",
1271 item
->mtime
, item
->new, item
->unread
, item
->total
);
1274 if (node
->children
) {
1278 child
= node
->children
;
1284 folder_write_list_recursive(cur
, data
);
1287 for (i
= 0; i
< depth
; i
++)
1289 fprintf(fp
, "</%s>\n", depth
== 1 ? "folder" : "folderitem");
1294 static void folder_update_op_count_rec(GNode
*node
) {
1295 FolderItem
*fitem
= FOLDER_ITEM(node
->data
);
1297 if (g_node_depth(node
) > 0) {
1298 if (fitem
->op_count
> 0) {
1299 fitem
->op_count
= 0;
1300 folderview_update_item(fitem
, 0);
1302 if (node
->children
) {
1305 child
= node
->children
;
1311 folder_update_op_count_rec(cur
);
1317 void folder_update_op_count() {
1321 for (cur
= folder_list
; cur
!= NULL
; cur
= cur
->next
) {
1323 folder_update_op_count_rec(folder
->node
);
1327 typedef struct _type_str
{
1333 static type_str type_str_table
[] =
1337 {"#maildir", F_MAILDIR
},
1343 static gchar
* folder_get_type_string(gint type
)
1347 for(i
= 0 ; i
< sizeof(type_str_table
) / sizeof(type_str
) ; i
++) {
1348 if (type_str_table
[i
].type
== type
)
1349 return type_str_table
[i
].str
;
1354 static gint
folder_get_type_from_string(gchar
* str
)
1358 for(i
= 0 ; i
< sizeof(type_str_table
) / sizeof(type_str
) ; i
++) {
1359 if (g_strcasecmp(type_str_table
[i
].str
, str
))
1360 return type_str_table
[i
].type
;
1365 gchar
* folder_get_identifier(Folder
* folder
)
1368 type_str
= folder_get_type_string(folder
->type
);
1370 return g_strconcat(type_str
, "/", folder
->name
, NULL
);
1374 static gchar * folder_item_get_tree_identifier(FolderItem * item)
1376 if (item->parent != NULL) {
1380 path = folder_item_get_tree_identifier(item->parent);
1384 id = g_strconcat(path, "/", item->name, NULL);
1390 return g_strconcat("/", item->name, NULL);
1395 gchar
* folder_item_get_identifier(FolderItem
* item
)
1401 folder_str
= folder_get_identifier(item
->folder
);
1403 if (item
->path
== NULL
) {
1408 id
= g_strconcat(folder_str
, "/", item
->path
, NULL
);
1413 Folder
* folder_find_from_name(const gchar
* name
)
1418 for (list
= g_list_first(folder_list
); list
!= NULL
;
1419 list
= list
->next
) {
1420 folder
= list
->data
;
1421 if (strcmp(name
, folder
->name
) == 0)
1427 FolderItem
* folder_find_item_from_identifier(const gchar
*identifier
)
1437 Xalloca(str
, strlen(identifier
) + 1, return NULL
);
1438 strcpy(str
, identifier
);
1440 /* extract box type */
1442 p
= strchr(str
, '/');
1449 type
= folder_get_type_from_string(str
);
1453 /* extract box name */
1455 p
= strchr(str
, '/');
1464 folder
= folder_find_from_name(name
);
1470 d
[0] = (gpointer
)path
;
1472 g_node_traverse(folder
->node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, -1,
1473 folder_item_find_func
, d
);