6e82c9c44939b7c05fa1a34acbbf8c1a3bdcb789
[claws.git] / src / folderview.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2001 Hiroyuki Yamamoto
4  *
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.
9  *
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.
14  *
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.
18  */
19
20 #include "defs.h"
21
22 #include <glib.h>
23 #include <gdk/gdkkeysyms.h>
24 #include <gtk/gtkwidget.h>
25 #include <gtk/gtkscrolledwindow.h>
26 #include <gtk/gtkctree.h>
27 #include <gtk/gtkcontainer.h>
28 #include <gtk/gtkclist.h>
29 #include <gtk/gtkstyle.h>
30 #include <gtk/gtksignal.h>
31 #include <gtk/gtkmain.h>
32 #include <gtk/gtkstatusbar.h>
33 #include <gtk/gtkmenu.h>
34 #include <gtk/gtkmenuitem.h>
35 #include <gtk/gtkitemfactory.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39
40 #include "intl.h"
41 #include "main.h"
42 #include "mainwindow.h"
43 #include "folderview.h"
44 #include "summaryview.h"
45 #include "inputdialog.h"
46 #include "grouplistdialog.h"
47 #include "manage_window.h"
48 #include "alertpanel.h"
49 #include "menu.h"
50 #include "procmsg.h"
51 #include "utils.h"
52 #include "gtkutils.h"
53 #include "prefs_common.h"
54 #include "prefs_account.h"
55 #include "account.h"
56 #include "folder.h"
57
58 #include "pixmaps/inbox.xpm"
59 #include "pixmaps/outbox.xpm"
60 #include "pixmaps/dir-close.xpm"
61 #include "pixmaps/dir-open.xpm"
62 #include "pixmaps/trash.xpm"
63
64 typedef enum
65 {
66         COL_FOLDER      = 0,
67         COL_NEW         = 1,
68         COL_UNREAD      = 2,
69         COL_TOTAL       = 3
70 } FolderColumnPos;
71
72 #define N_FOLDER_COLS           4
73 #define COL_FOLDER_WIDTH        150
74 #define COL_NUM_WIDTH           32
75
76 #define STATUSBAR_PUSH(mainwin, str) \
77 { \
78         gtk_statusbar_push(GTK_STATUSBAR(mainwin->statusbar), \
79                            mainwin->folderview_cid, str); \
80         gtkut_widget_wait_for_draw(mainwin->hbox_stat); \
81 }
82
83 #define STATUSBAR_POP(mainwin) \
84 { \
85         gtk_statusbar_pop(GTK_STATUSBAR(mainwin->statusbar), \
86                           mainwin->folderview_cid); \
87 }
88
89 static GList *folderview_list = NULL;
90
91 static GdkFont *normalfont;
92 static GdkFont *boldfont;
93
94 static GtkStyle *normal_style;
95 static GtkStyle *normal_color_style;
96 static GtkStyle *bold_style;
97 static GtkStyle *bold_color_style;
98
99 static GdkPixmap *inboxxpm;
100 static GdkBitmap *inboxxpmmask;
101 static GdkPixmap *outboxxpm;
102 static GdkBitmap *outboxxpmmask;
103 static GdkPixmap *folderxpm;
104 static GdkBitmap *folderxpmmask;
105 static GdkPixmap *folderopenxpm;
106 static GdkBitmap *folderopenxpmmask;
107 static GdkPixmap *trashxpm;
108 static GdkBitmap *trashxpmmask;
109
110 static void folderview_select_node       (FolderView    *folderview,
111                                           GtkCTreeNode  *node);
112 static void folderview_set_folders       (FolderView    *folderview);
113 static void folderview_sort_folders      (FolderView    *folderview,
114                                           GtkCTreeNode  *root,
115                                           Folder        *folder);
116 static void folderview_append_folder     (FolderView    *folderview,
117                                           Folder        *folder);
118 static void folderview_update_node       (FolderView    *folderview,
119                                           GtkCTreeNode  *node);
120
121 static GtkCTreeNode *folderview_find_by_name    (GtkCTree       *ctree,
122                                                  GtkCTreeNode   *node,
123                                                  const gchar    *name);
124
125 static gint folderview_compare_name     (gconstpointer   a,
126                                          gconstpointer   b);
127
128 /* callback functions */
129 static void folderview_button_pressed   (GtkWidget      *ctree,
130                                          GdkEventButton *event,
131                                          FolderView     *folderview);
132 static void folderview_button_released  (GtkWidget      *ctree,
133                                          GdkEventButton *event,
134                                          FolderView     *folderview);
135 static void folderview_key_pressed      (GtkWidget      *widget,
136                                          GdkEventKey    *event,
137                                          FolderView     *folderview);
138 static void folderview_selected         (GtkCTree       *ctree,
139                                          GtkCTreeNode   *row,
140                                          gint            column,
141                                          FolderView     *folderview);
142 static void folderview_tree_expanded    (GtkCTree       *ctree,
143                                          GtkCTreeNode   *node,
144                                          FolderView     *folderview);
145 static void folderview_tree_collapsed   (GtkCTree       *ctree,
146                                          GtkCTreeNode   *node,
147                                          FolderView     *folderview);
148 static void folderview_popup_close      (GtkMenuShell   *menu_shell,
149                                          FolderView     *folderview);
150 static void folderview_col_resized      (GtkCList       *clist,
151                                          gint            column,
152                                          gint            width,
153                                          FolderView     *folderview);
154
155 static void folderview_update_tree_cb   (FolderView     *folderview,
156                                          guint           action,
157                                          GtkWidget      *widget);
158
159 static void folderview_new_folder_cb    (FolderView     *folderview,
160                                          guint           action,
161                                          GtkWidget      *widget);
162 static void folderview_new_mbox_folder_cb(FolderView *folderview,
163                                           guint action,
164                                           GtkWidget *widget);
165 static void folderview_rename_folder_cb (FolderView     *folderview,
166                                          guint           action,
167                                          GtkWidget      *widget);
168 static void folderview_rename_mbox_folder_cb(FolderView *folderview,
169                                              guint action,
170                                              GtkWidget *widget);
171 static void folderview_delete_folder_cb (FolderView     *folderview,
172                                          guint           action,
173                                          GtkWidget      *widget);
174 static void folderview_remove_mailbox_cb(FolderView     *folderview,
175                                          guint           action,
176                                          GtkWidget      *widget);
177
178 static void folderview_new_imap_folder_cb(FolderView    *folderview,
179                                           guint          action,
180                                           GtkWidget     *widget);
181 static void folderview_rm_imap_folder_cb (FolderView    *folderview,
182                                           guint          action,
183                                           GtkWidget     *widget);
184 static void folderview_rm_imap_server_cb (FolderView    *folderview,
185                                           guint          action,
186                                           GtkWidget     *widget);
187
188 static void folderview_new_news_group_cb(FolderView     *folderview,
189                                          guint           action,
190                                          GtkWidget      *widget);
191 static void folderview_rm_news_group_cb (FolderView     *folderview,
192                                          guint           action,
193                                          GtkWidget      *widget);
194 static void folderview_rm_news_server_cb(FolderView     *folderview,
195                                          guint           action,
196                                          GtkWidget      *widget);
197
198 static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
199                                           GdkDragContext *context,
200                                           gint            x,
201                                           gint            y,
202                                           guint           time,
203                                           FolderView     *folderview);
204 static void folderview_drag_leave_cb     (GtkWidget        *widget,
205                                           GdkDragContext   *context,
206                                           guint             time,
207                                           FolderView       *folderview);
208 static void folderview_drag_received_cb  (GtkWidget        *widget,
209                                           GdkDragContext   *drag_context,
210                                           gint              x,
211                                           gint              y,
212                                           GtkSelectionData *data,
213                                           guint             info,
214                                           guint             time,
215                                           FolderView       *folderview);
216 static void folderview_scoring_cb(FolderView *folderview, guint action,
217                                   GtkWidget *widget);
218 static void folderview_property_cb(FolderView *folderview, guint action, GtkWidget *widget);
219
220 static GtkItemFactoryEntry folderview_mbox_popup_entries[] =
221 {
222         {N_("/Create _new folder..."),  NULL, folderview_new_mbox_folder_cb,    0, NULL},
223         {N_("/_Rename folder..."),      NULL, folderview_rename_mbox_folder_cb, 0, NULL},
224         {N_("/_Delete folder"),         NULL, folderview_delete_folder_cb, 0, NULL},
225         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
226         {N_("/Remove _mailbox"),        NULL, folderview_remove_mailbox_cb, 0, NULL},
227         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
228         {N_("/_Property..."),           NULL, NULL, 0, NULL},
229         {N_("/_Scoring..."),            NULL, folderview_scoring_cb, 0, NULL}
230 };
231
232 static GtkItemFactoryEntry folderview_mail_popup_entries[] =
233 {
234         {N_("/Create _new folder..."),  NULL, folderview_new_folder_cb,    0, NULL},
235         {N_("/_Rename folder..."),      NULL, folderview_rename_folder_cb, 0, NULL},
236         {N_("/_Delete folder"),         NULL, folderview_delete_folder_cb, 0, NULL},
237         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
238         {N_("/_Update folder tree"),    NULL, folderview_update_tree_cb, 0, NULL},
239         {N_("/Remove _mailbox"),        NULL, folderview_remove_mailbox_cb, 0, NULL},
240         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
241         {N_("/_Property..."),           NULL, folderview_property_cb, 0, NULL},
242         {N_("/_Scoring..."),            NULL, folderview_scoring_cb, 0, NULL}
243 };
244
245 static GtkItemFactoryEntry folderview_imap_popup_entries[] =
246 {
247         {N_("/Create _new folder..."),  NULL, folderview_new_imap_folder_cb, 0, NULL},
248         {N_("/_Rename folder..."),      NULL, NULL, 0, NULL},
249         {N_("/_Delete folder"),         NULL, folderview_rm_imap_folder_cb, 0, NULL},
250         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
251         {N_("/_Update folder tree"),    NULL, folderview_update_tree_cb, 0, NULL},
252         {N_("/Remove _IMAP4 account"),  NULL, folderview_rm_imap_server_cb, 0, NULL},
253         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
254         {N_("/_Property..."),           NULL, NULL, 0, NULL},
255         {N_("/_Scoring..."),            NULL, folderview_scoring_cb, 0, NULL}
256 };
257
258 static GtkItemFactoryEntry folderview_news_popup_entries[] =
259 {
260         {N_("/_Subscribe to newsgroup..."),
261                                          NULL, folderview_new_news_group_cb, 0, NULL},
262         {N_("/_Remove newsgroup"),       NULL, folderview_rm_news_group_cb, 0, NULL},
263         {N_("/---"),                     NULL, NULL, 0, "<Separator>"},
264         {N_("/Remove _news account"),    NULL, folderview_rm_news_server_cb, 0, NULL},
265         {N_("/---"),                     NULL, NULL, 0, "<Separator>"},
266         {N_("/_Property..."),            NULL, NULL, 0, NULL},
267         {N_("/_Scoring..."),            NULL, folderview_scoring_cb, 0, NULL}
268 };
269
270
271 FolderView *folderview_create(void)
272 {
273         FolderView *folderview;
274         GtkWidget *scrolledwin;
275         GtkWidget *ctree;
276         gchar *titles[N_FOLDER_COLS] = {_("Folder"), _("New"),
277                                         _("Unread"), _("#")};
278         GtkWidget *mail_popup;
279         GtkWidget *news_popup;
280         GtkWidget *imap_popup;
281         GtkWidget *mbox_popup;
282         GtkItemFactory *mail_factory;
283         GtkItemFactory *news_factory;
284         GtkItemFactory *imap_factory;
285         GtkItemFactory *mbox_factory;
286         gint n_entries;
287         gint i;
288
289         debug_print(_("Creating folder view...\n"));
290         folderview = g_new0(FolderView, 1);
291
292         scrolledwin = gtk_scrolled_window_new(NULL, NULL);
293         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
294                                        GTK_POLICY_AUTOMATIC,
295                                        GTK_POLICY_ALWAYS);
296         gtk_widget_set_usize(scrolledwin,
297                              prefs_common.folderview_width,
298                              prefs_common.folderview_height);
299
300         ctree = gtk_ctree_new_with_titles(N_FOLDER_COLS, COL_FOLDER, titles);
301         gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
302         gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
303         gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_NEW,
304                                            GTK_JUSTIFY_RIGHT);
305         gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_UNREAD,
306                                            GTK_JUSTIFY_RIGHT);
307         gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_TOTAL,
308                                            GTK_JUSTIFY_RIGHT);
309         gtk_clist_set_column_width(GTK_CLIST(ctree), COL_FOLDER,
310                                    prefs_common.folder_col_folder);
311         gtk_clist_set_column_width(GTK_CLIST(ctree), COL_NEW,
312                                    prefs_common.folder_col_new);
313         gtk_clist_set_column_width(GTK_CLIST(ctree), COL_UNREAD,        
314                                    prefs_common.folder_col_unread);
315         gtk_clist_set_column_width(GTK_CLIST(ctree), COL_TOTAL,
316                                    prefs_common.folder_col_total);
317         gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
318         gtk_ctree_set_expander_style(GTK_CTREE(ctree),
319                                      GTK_CTREE_EXPANDER_SQUARE);
320         gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
321
322         /* don't let title buttons take key focus */
323         for (i = 0; i < N_FOLDER_COLS; i++)
324                 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
325                                        GTK_CAN_FOCUS);
326
327         /* popup menu */
328         n_entries = sizeof(folderview_mail_popup_entries) /
329                 sizeof(folderview_mail_popup_entries[0]);
330         mail_popup = menu_create_items(folderview_mail_popup_entries,
331                                        n_entries,
332                                        "<MailFolder>", &mail_factory,
333                                        folderview);
334         n_entries = sizeof(folderview_imap_popup_entries) /
335                 sizeof(folderview_imap_popup_entries[0]);
336         imap_popup = menu_create_items(folderview_imap_popup_entries,
337                                        n_entries,
338                                        "<IMAPFolder>", &imap_factory,
339                                        folderview);
340         n_entries = sizeof(folderview_news_popup_entries) /
341                 sizeof(folderview_news_popup_entries[0]);
342         news_popup = menu_create_items(folderview_news_popup_entries,
343                                        n_entries,
344                                        "<NewsFolder>", &news_factory,
345                                        folderview);
346         n_entries = sizeof(folderview_mbox_popup_entries) /
347                 sizeof(folderview_mbox_popup_entries[0]);
348         mbox_popup = menu_create_items(folderview_mbox_popup_entries,
349                                        n_entries,
350                                        "<MailFolder>", &mbox_factory,
351                                        folderview);
352
353         gtk_signal_connect(GTK_OBJECT(ctree), "key_press_event",
354                            GTK_SIGNAL_FUNC(folderview_key_pressed),
355                            folderview);
356         gtk_signal_connect(GTK_OBJECT(ctree), "button_press_event",
357                            GTK_SIGNAL_FUNC(folderview_button_pressed),
358                            folderview);
359         gtk_signal_connect(GTK_OBJECT(ctree), "button_release_event",
360                            GTK_SIGNAL_FUNC(folderview_button_released),
361                            folderview);
362         gtk_signal_connect(GTK_OBJECT(ctree), "tree_select_row",
363                            GTK_SIGNAL_FUNC(folderview_selected), folderview);
364
365         gtk_signal_connect_after(GTK_OBJECT(ctree), "tree_expand",
366                                  GTK_SIGNAL_FUNC(folderview_tree_expanded),
367                                  folderview);
368         gtk_signal_connect_after(GTK_OBJECT(ctree), "tree_collapse",
369                                  GTK_SIGNAL_FUNC(folderview_tree_collapsed),
370                                  folderview);
371
372         gtk_signal_connect(GTK_OBJECT(ctree), "resize_column",
373                            GTK_SIGNAL_FUNC(folderview_col_resized),
374                            folderview);
375
376         gtk_signal_connect(GTK_OBJECT(mail_popup), "selection_done",
377                            GTK_SIGNAL_FUNC(folderview_popup_close),
378                            folderview);
379         gtk_signal_connect(GTK_OBJECT(imap_popup), "selection_done",
380                            GTK_SIGNAL_FUNC(folderview_popup_close),
381                            folderview);
382         gtk_signal_connect(GTK_OBJECT(news_popup), "selection_done",
383                            GTK_SIGNAL_FUNC(folderview_popup_close),
384                            folderview);
385         gtk_signal_connect(GTK_OBJECT(mbox_popup), "selection_done",
386                            GTK_SIGNAL_FUNC(folderview_popup_close),
387                            folderview);
388
389         /* drop callback */
390         gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL &
391                           ~GTK_DEST_DEFAULT_HIGHLIGHT,
392                           summary_drag_types, 1,
393                           GDK_ACTION_MOVE);
394         gtk_signal_connect(GTK_OBJECT(ctree), "drag_motion",
395                            GTK_SIGNAL_FUNC(folderview_drag_motion_cb),
396                            folderview);
397         gtk_signal_connect(GTK_OBJECT(ctree), "drag_leave",
398                            GTK_SIGNAL_FUNC(folderview_drag_leave_cb),
399                            folderview);
400         gtk_signal_connect(GTK_OBJECT(ctree), "drag_data_received",
401                            GTK_SIGNAL_FUNC(folderview_drag_received_cb),
402                            folderview);
403
404         folderview->scrolledwin  = scrolledwin;
405         folderview->ctree        = ctree;
406         folderview->mail_popup   = mail_popup;
407         folderview->mail_factory = mail_factory;
408         folderview->imap_popup   = imap_popup;
409         folderview->imap_factory = imap_factory;
410         folderview->news_popup   = news_popup;
411         folderview->news_factory = news_factory;
412         folderview->mbox_popup   = mbox_popup;
413         folderview->mbox_factory = mbox_factory;
414
415         gtk_widget_show_all(scrolledwin);
416
417         folderview_list = g_list_append(folderview_list, folderview);
418
419         return folderview;
420 }
421
422 void folderview_init(FolderView *folderview)
423 {
424         GtkWidget *ctree = folderview->ctree;
425
426         PIXMAP_CREATE(ctree, inboxxpm, inboxxpmmask, inbox_xpm);
427         PIXMAP_CREATE(ctree, outboxxpm, outboxxpmmask, outbox_xpm);
428         PIXMAP_CREATE(ctree, folderxpm, folderxpmmask, DIRECTORY_CLOSE_XPM);
429         PIXMAP_CREATE(ctree, folderopenxpm, folderopenxpmmask,
430                       DIRECTORY_OPEN_XPM);
431         PIXMAP_CREATE(ctree, trashxpm, trashxpmmask, trash_xpm);
432
433         if (!normalfont)
434                 normalfont = gdk_fontset_load(NORMAL_FONT);
435         if (!boldfont)
436                 boldfont = gdk_fontset_load(BOLD_FONT);
437
438         if (!bold_style) {
439                 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
440                 bold_style->font = boldfont;
441                 bold_color_style = gtk_style_copy(bold_style);
442                 bold_color_style->fg[GTK_STATE_NORMAL] = folderview->color_new;
443         }
444         if (!normal_style) {
445                 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
446                 normal_style->font = normalfont;
447                 normal_color_style = gtk_style_copy(normal_style);
448                 normal_color_style->fg[GTK_STATE_NORMAL] = folderview->color_new;
449         }
450
451 }
452
453 void folderview_set(FolderView *folderview)
454 {
455         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
456         MainWindow *mainwin = folderview->mainwin;
457
458         debug_print(_("Setting folder info...\n"));
459         STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
460
461         main_window_cursor_wait(mainwin);
462
463         folderview->selected = NULL;
464         folderview->opened = NULL;
465
466         gtk_clist_freeze(GTK_CLIST(ctree));
467         gtk_clist_clear(GTK_CLIST(ctree));
468         gtk_clist_thaw(GTK_CLIST(ctree));
469         gtk_clist_freeze(GTK_CLIST(ctree));
470
471         folderview_set_folders(folderview);
472
473         gtk_clist_thaw(GTK_CLIST(ctree));
474         main_window_cursor_normal(mainwin);
475         STATUSBAR_POP(mainwin);
476 }
477
478 void folderview_set_all(void)
479 {
480         GList *list;
481
482         for (list = folderview_list; list != NULL; list = list->next)
483                 folderview_set((FolderView *)list->data);
484 }
485
486 void folderview_select(FolderView *folderview, FolderItem *item)
487 {
488         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
489         GtkCTreeNode *node;
490         GtkCTreeNode *old_selected = folderview->selected;
491
492         if (!item) return;
493
494         node = gtk_ctree_find_by_row_data(ctree, NULL, item);
495         if (node) folderview_select_node(folderview, node);
496
497         if (old_selected != node)
498                 folder_update_op_count();
499 }
500
501 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
502 {
503         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
504
505         g_return_if_fail(node != NULL);
506
507         folderview->open_folder = TRUE;
508         gtk_ctree_select(ctree, node);
509         gtkut_ctree_set_focus_row(ctree, node);
510         if (folderview->summaryview->messages > 0)
511                 gtk_widget_grab_focus(folderview->summaryview->ctree);
512         else
513                 gtk_widget_grab_focus(folderview->ctree);
514
515         gtkut_ctree_expand_parent_all(ctree, node);
516 }
517
518 void folderview_unselect(FolderView *folderview)
519 {
520         if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
521                 gtk_ctree_collapse
522                         (GTK_CTREE(folderview->ctree), folderview->opened);
523
524         folderview->selected = folderview->opened = NULL;
525 }
526
527 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
528                                                  GtkCTreeNode *node)
529 {
530         FolderItem *item;
531
532         if (node)
533                 node = gtkut_ctree_node_next(ctree, node);
534         else
535                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
536
537         for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
538                 item = gtk_ctree_node_get_row_data(ctree, node);
539                 if (item && item->unread > 0 && item->stype != F_TRASH)
540                         return node;
541         }
542
543         return NULL;
544 }
545
546 void folderview_select_next_unread(FolderView *folderview)
547 {
548         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
549         GtkCTreeNode *node = NULL;
550
551         if ((node = folderview_find_next_unread(ctree, folderview->opened))
552             != NULL) {
553                 folderview_select_node(folderview, node);
554                 return;
555         }
556
557         if (!folderview->opened ||
558             folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list))
559                 return;
560         /* search again from the first node */
561         if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
562                 folderview_select_node(folderview, node);
563 }
564
565 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row,
566                                gint new, gint unread, gint total)
567 {
568         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
569         static GtkCTreeNode *prev_row = NULL;
570         FolderItem *item;
571
572         if (!row) return;
573
574         item = gtk_ctree_node_get_row_data(ctree, row);
575         if (!item) return;
576         if (prev_row     == row    &&
577             item->new    == new    &&
578             item->unread == unread &&
579             item->total  == total)
580                 return;
581
582         prev_row = row;
583
584         item->new    = new;
585         item->unread = unread;
586         item->total  = total;
587
588         folderview_update_node(folderview, row);
589 }
590
591 static void folderview_set_folders(FolderView *folderview)
592 {
593         GList *list;
594
595         list = folder_get_list();
596
597         for (; list != NULL; list = list->next)
598                 folderview_append_folder(folderview, FOLDER(list->data));
599 }
600
601 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
602                                       gpointer data)
603 {
604         GList *list;
605         gchar *rootpath;
606
607         if (FOLDER_IS_LOCAL(folder))
608                 rootpath = LOCAL_FOLDER(folder)->rootpath;
609         else if (folder->type == F_IMAP && folder->account &&
610                  folder->account->recv_server)
611                 rootpath = folder->account->recv_server;
612         else
613                 return;
614
615         for (list = folderview_list; list != NULL; list = list->next) {
616                 FolderView *folderview = (FolderView *)list->data;
617                 MainWindow *mainwin = folderview->mainwin;
618                 gchar *str;
619
620                 if (item->path)
621                         str = g_strdup_printf(_("Scanning folder %s%c%s ..."),
622                                               rootpath, G_DIR_SEPARATOR,
623                                               item->path);
624                 else
625                         str = g_strdup_printf(_("Scanning folder %s ..."),
626                                               rootpath);
627
628                 STATUSBAR_PUSH(mainwin, str);
629                 STATUSBAR_POP(mainwin);
630                 g_free(str);
631         }
632 }
633
634 static GtkWidget *label_window_create(const gchar *str)
635 {
636         GtkWidget *window;
637         GtkWidget *label;
638
639         window = gtk_window_new(GTK_WINDOW_DIALOG);
640         gtk_widget_set_usize(window, 380, 60);
641         gtk_container_set_border_width(GTK_CONTAINER(window), 8);
642         gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
643         gtk_window_set_title(GTK_WINDOW(window), str);
644         gtk_window_set_modal(GTK_WINDOW(window), TRUE);
645         gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
646         manage_window_set_transient(GTK_WINDOW(window));
647
648         label = gtk_label_new(str);
649         gtk_container_add(GTK_CONTAINER(window), label);
650         gtk_widget_show(label);
651
652         gtk_widget_show_now(window);
653
654         return window;
655 }
656
657 void folderview_update_tree(Folder *folder)
658 {
659         GtkWidget *window;
660
661         g_return_if_fail(folder != NULL);
662
663         if (!folder->scan_tree) return;
664
665         window = label_window_create(_("Updating folder tree..."));
666
667         folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
668         folder->scan_tree(folder);
669         folder_set_ui_func(folder, NULL, NULL);
670
671         folder_write_list();
672         folderview_set_all();
673
674         gtk_widget_destroy(window);
675 }
676
677 void folderview_update_all_node(void)
678 {
679         GList *list;
680         FolderItem *item;
681         FolderView *folderview;
682         GtkCTree *ctree;
683         GtkCTreeNode *node;
684         GtkWidget *window;
685
686         window = label_window_create(_("Updating all folders..."));
687
688         for (list = folderview_list; list != NULL; list = list->next) {
689                 folderview = (FolderView *)list->data;
690                 ctree = GTK_CTREE(folderview->ctree);
691
692                 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
693                      node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
694                         item = gtk_ctree_node_get_row_data(ctree, node);
695                         if (!item || !FOLDER_IS_LOCAL(item->folder) ||
696                             !item->path)
697                                 continue;
698                         folderview_scan_tree_func(item->folder, item, NULL);
699                         folder_item_scan(item);
700                         folderview_update_node(folderview, node);
701                 }
702         }
703
704         folder_write_list();
705         gtk_widget_destroy(window);
706 }
707
708 static gboolean folderview_search_new_recursive(GtkCTree *ctree,
709                                                 GtkCTreeNode *node)
710 {
711         FolderItem *item;
712
713         if (node) {
714                 item = gtk_ctree_node_get_row_data(ctree, node);
715                 if (item) {
716                         if (item->new > 0 ||
717                             (item->stype == F_QUEUE && item->total > 0))
718                                 return TRUE;
719                 }
720                 node = GTK_CTREE_ROW(node)->children;
721         } else
722                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
723
724         while (node) {
725                 if (folderview_search_new_recursive(ctree, node) == TRUE)
726                         return TRUE;
727                 node = GTK_CTREE_ROW(node)->sibling;
728         }
729
730         return FALSE;
731 }
732
733 static gboolean folderview_have_new_children(FolderView *folderview,
734                                              GtkCTreeNode *node)
735 {
736         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
737
738         if (!node)
739                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
740         if (!node)
741                 return FALSE;
742
743         node = GTK_CTREE_ROW(node)->children;
744
745         while (node) {
746                 if (folderview_search_new_recursive(ctree, node) == TRUE)
747                         return TRUE;
748                 node = GTK_CTREE_ROW(node)->sibling;
749         }
750
751         return FALSE;
752 }
753
754 static gboolean folderview_search_unread_recursive(GtkCTree *ctree,
755                                                    GtkCTreeNode *node)
756 {
757         FolderItem *item;
758
759         if (node) {
760                 item = gtk_ctree_node_get_row_data(ctree, node);
761                 if (item) {
762                         if (item->unread > 0 ||
763                             (item->stype == F_QUEUE && item->total > 0))
764                                 return TRUE;
765                 }
766                 node = GTK_CTREE_ROW(node)->children;
767         } else
768                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
769
770         while (node) {
771                 if (folderview_search_unread_recursive(ctree, node) == TRUE)
772                         return TRUE;
773                 node = GTK_CTREE_ROW(node)->sibling;
774         }
775
776         return FALSE;
777 }
778
779 static gboolean folderview_have_unread_children(FolderView *folderview,
780                                                 GtkCTreeNode *node)
781 {
782         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
783
784         if (!node)
785                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
786         if (!node)
787                 return FALSE;
788
789         node = GTK_CTREE_ROW(node)->children;
790
791         while (node) {
792                 if (folderview_search_unread_recursive(ctree, node) == TRUE)
793                         return TRUE;
794                 node = GTK_CTREE_ROW(node)->sibling;
795         }
796
797         return FALSE;
798 }
799
800 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
801 {
802         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
803         GtkStyle *style = NULL;
804         GtkCTreeNode *parent;
805         FolderItem *item;
806         GdkPixmap *xpm, *openxpm;
807         GdkBitmap *mask, *openmask;
808         gchar *name;
809         gchar *str;
810         gboolean add_unread_mark;
811         gboolean use_bold, use_color;
812
813         item = gtk_ctree_node_get_row_data(ctree, node);
814         g_return_if_fail(item != NULL);
815
816         switch (item->stype) {
817         case F_INBOX:
818                 xpm = openxpm = inboxxpm;
819                 mask = openmask = inboxxpmmask;
820                 name = g_strdup(_("Inbox"));
821                 break;
822         case F_OUTBOX:
823                 xpm = openxpm = outboxxpm;
824                 mask = openmask = outboxxpmmask;
825                 name = g_strdup(_("Outbox"));
826                 break;
827         case F_QUEUE:
828                 xpm = openxpm = outboxxpm;
829                 mask = openmask = outboxxpmmask;
830                 name = g_strdup(_("Queue"));
831                 break;
832         case F_TRASH:
833                 xpm = openxpm = trashxpm;
834                 mask = openmask = trashxpmmask;
835                 name = g_strdup(_("Trash"));
836                 break;
837         case F_DRAFT:
838                 xpm = folderxpm;
839                 mask = folderxpmmask;
840                 openxpm = folderopenxpm;
841                 openmask = folderopenxpmmask;
842                 name = g_strdup(_("Draft"));
843                 break;
844         default:
845                 xpm = folderxpm;
846                 mask = folderxpmmask;
847                 openxpm = folderopenxpm;
848                 openmask = folderopenxpmmask;
849                 if (!item->parent) {
850                         switch (item->folder->type) {
851                         case F_MH:
852                                 name = " (MH)"; break;
853                         case F_MBOX:
854                                 name = " (mbox)"; break;
855                         case F_IMAP:
856                                 name = " (IMAP4)"; break;
857                         case F_NEWS:
858                                 name = " (News)"; break;
859                         default:
860                                 name = "";
861                         }
862                         name = g_strconcat(item->name, name, NULL);
863                 } else
864                         name = g_strdup(item->name);
865         }
866
867         if (!GTK_CTREE_ROW(node)->expanded &&
868             folderview_have_unread_children(folderview, node))
869                 add_unread_mark = TRUE;
870         else
871                 add_unread_mark = FALSE;
872
873         if (item->stype == F_QUEUE && item->total > 0 &&
874             prefs_common.display_folder_unread) {
875                 str = g_strdup_printf("%s (%d%s)", name, item->total,
876                                       add_unread_mark ? "+" : "");
877                 gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
878                                         xpm, mask, openxpm, openmask,
879                                         FALSE, GTK_CTREE_ROW(node)->expanded);
880                 g_free(str);
881         } else if ((item->unread > 0 || add_unread_mark) &&
882                  prefs_common.display_folder_unread) {
883
884                 if (item->unread > 0)
885                         str = g_strdup_printf("%s (%d%s)", name, item->unread,
886                                               add_unread_mark ? "+" : "");
887                 else
888                         str = g_strdup_printf("%s (+)", name);
889                 gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
890                                         xpm, mask, openxpm, openmask,
891                                         FALSE, GTK_CTREE_ROW(node)->expanded);
892                 g_free(str);
893         } else
894                 gtk_ctree_set_node_info(ctree, node, name, FOLDER_SPACING,
895                                         xpm, mask, openxpm, openmask,
896                                         FALSE, GTK_CTREE_ROW(node)->expanded);
897         g_free(name);
898
899         if (!item->parent) {
900                 gtk_ctree_node_set_text(ctree, node, COL_NEW,    "-");
901                 gtk_ctree_node_set_text(ctree, node, COL_UNREAD, "-");
902                 gtk_ctree_node_set_text(ctree, node, COL_TOTAL,  "-");
903         } else {
904                 gtk_ctree_node_set_text(ctree, node, COL_NEW,    itos(item->new));
905                 gtk_ctree_node_set_text(ctree, node, COL_UNREAD, itos(item->unread));
906                 gtk_ctree_node_set_text(ctree, node, COL_TOTAL,  itos(item->total));
907         }
908
909         if (item->stype == F_TRASH) return;
910
911         if (item->stype == F_QUEUE) {
912                 /* highlight queue folder if there are any messages */
913                 use_bold = use_color = (item->total > 0);
914         } else {
915                 /* if unread messages exist, print with bold font */
916                 use_bold = (item->unread > 0) || add_unread_mark;
917                 /* if new messages exist, print with colored letter */
918                 use_color =
919                         (item->new > 0) ||
920                         (add_unread_mark &&
921                          folderview_have_new_children(folderview, node));
922         }
923
924         gtk_ctree_node_set_foreground(ctree, node, NULL);
925
926         if (use_bold && use_color)
927                 style = bold_color_style;
928         else if (use_bold) {
929                 style = bold_style;
930                 if (item->op_count > 0) {
931                         gtk_ctree_node_set_foreground(ctree, node,
932                                                       &folderview->color_op);
933                 } else {
934                         style = bold_style;
935                 }
936         }
937         else if (use_color) {
938                 style = normal_color_style;
939                 gtk_ctree_node_set_foreground(ctree, node,
940                                               &folderview->color_new);
941         }
942         else if (item->op_count > 0) {
943                 style = normal_color_style;
944                 gtk_ctree_node_set_foreground(ctree, node,
945                                               &folderview->color_op);
946         } else {
947                 style = normal_style;
948         }
949
950         gtk_ctree_node_set_row_style(ctree, node, style);
951
952         parent = node;
953         while ((parent = gtkut_ctree_find_collapsed_parent(ctree, parent))
954                != NULL)
955                 folderview_update_node(folderview, parent);
956 }
957
958 void folderview_update_item(FolderItem *item, gboolean update_summary)
959 {
960         GList *list;
961         FolderView *folderview;
962         GtkCTree *ctree;
963         GtkCTreeNode *node;
964
965         g_return_if_fail(item != NULL);
966
967         for (list = folderview_list; list != NULL; list = list->next) {
968                 folderview = (FolderView *)list->data;
969                 ctree = GTK_CTREE(folderview->ctree);
970
971                 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
972                 if (node) {
973                         folderview_update_node(folderview, node);
974                         if (update_summary && folderview->opened == node)
975                                 summary_show(folderview->summaryview,
976                                              item, FALSE);
977                 }
978         }
979 }
980
981 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
982                                                 gpointer data)
983 {
984         folderview_update_item((FolderItem *)key, FALSE);
985 }
986
987 void folderview_update_item_foreach(GHashTable *table)
988 {
989         g_hash_table_foreach(table, folderview_update_item_foreach_func, NULL);
990 }
991
992 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
993                                       GNode *gnode, GtkCTreeNode *cnode,
994                                       gpointer data)
995 {
996         FolderView *folderview = (FolderView *)data;
997         FolderItem *item = FOLDER_ITEM(gnode->data);
998
999         g_return_val_if_fail(item != NULL, FALSE);
1000
1001         gtk_ctree_node_set_row_data(ctree, cnode, item);
1002         folderview_update_node(folderview, cnode);
1003
1004         return TRUE;
1005 }
1006
1007 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1008                                    gpointer data)
1009 {
1010         FolderView *folderview = (FolderView *)data;
1011         FolderItem *item;
1012
1013         if (GTK_CTREE_ROW(node)->children) {
1014                 item = gtk_ctree_node_get_row_data(ctree, node);
1015                 g_return_if_fail(item != NULL);
1016
1017                 if (!item->collapsed)
1018                         gtk_ctree_expand(ctree, node);
1019                 else
1020                         folderview_update_node(folderview, node);
1021         }
1022 }
1023
1024 #define SET_SPECIAL_FOLDER(ctree, item) \
1025 { \
1026         if (item) { \
1027                 GtkCTreeNode *node, *sibling; \
1028  \
1029                 node = gtk_ctree_find_by_row_data(ctree, root, item); \
1030                 if (!node) \
1031                         g_warning("%s not found.\n", item->path); \
1032                 else { \
1033                         if (!prev) \
1034                                 sibling = GTK_CTREE_ROW(root)->children; \
1035                         else \
1036                                 sibling = GTK_CTREE_ROW(prev)->sibling; \
1037                         if (node != sibling) \
1038                                 gtk_ctree_move(ctree, node, root, sibling); \
1039                 } \
1040  \
1041                 prev = node; \
1042         } \
1043 }
1044
1045 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1046                                     Folder *folder)
1047 {
1048         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1049         GtkCTreeNode *prev = NULL;
1050
1051         gtk_ctree_sort_recursive(ctree, root);
1052
1053         if (GTK_CTREE_ROW(root)->parent) return;
1054
1055         SET_SPECIAL_FOLDER(ctree, folder->inbox);
1056         SET_SPECIAL_FOLDER(ctree, folder->outbox);
1057         SET_SPECIAL_FOLDER(ctree, folder->draft);
1058         SET_SPECIAL_FOLDER(ctree, folder->queue);
1059         SET_SPECIAL_FOLDER(ctree, folder->trash);
1060 }
1061
1062 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1063 {
1064         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1065         GtkCTreeNode *root;
1066
1067         g_return_if_fail(folder != NULL);
1068
1069         root = gtk_ctree_insert_gnode(ctree, NULL, NULL, folder->node,
1070                                       folderview_gnode_func, folderview);
1071         gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1072                                 folderview);
1073         folderview_sort_folders(folderview, root, folder);
1074 }
1075
1076 void folderview_new_folder(FolderView *folderview)
1077 {
1078         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1079         FolderItem *item;
1080
1081         if (!folderview->selected) return;
1082
1083         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1084         g_return_if_fail(item != NULL);
1085         g_return_if_fail(item->folder != NULL);
1086
1087         switch (item->folder->type) {
1088         case F_MBOX:
1089                 folderview_new_mbox_folder_cb(folderview, 0, NULL);
1090                 break;
1091         case F_MH:
1092         case F_MAILDIR:
1093                 folderview_new_folder_cb(folderview, 0, NULL);
1094                 break;
1095         case F_IMAP:
1096                 folderview_new_imap_folder_cb(folderview, 0, NULL);
1097                 break;
1098         case F_NEWS:
1099         default:
1100                 break;
1101         }
1102 }
1103
1104 void folderview_rename_folder(FolderView *folderview)
1105 {
1106         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1107         FolderItem *item;
1108
1109         if (!folderview->selected) return;
1110
1111         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1112         g_return_if_fail(item != NULL);
1113         g_return_if_fail(item->folder != NULL);
1114         if (!item->path) return;
1115         if (item->stype != F_NORMAL) return;
1116
1117         switch (item->folder->type) {
1118         case F_MBOX:
1119                 folderview_rename_mbox_folder_cb(folderview, 0, NULL);
1120         case F_MH:
1121         case F_MAILDIR:
1122                 folderview_rename_folder_cb(folderview, 0, NULL);
1123                 break;
1124         case F_IMAP:
1125         case F_NEWS:
1126         default:
1127                 break;
1128         }
1129 }
1130
1131 void folderview_delete_folder(FolderView *folderview)
1132 {
1133         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1134         FolderItem *item;
1135
1136         if (!folderview->selected) return;
1137
1138         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1139         g_return_if_fail(item != NULL);
1140         g_return_if_fail(item->folder != NULL);
1141         if (!item->path) return;
1142         if (item->stype != F_NORMAL) return;
1143
1144         switch (item->folder->type) {
1145         case F_MH:
1146         case F_MBOX:
1147         case F_MAILDIR:
1148                 folderview_delete_folder_cb(folderview, 0, NULL);
1149                 break;
1150         case F_IMAP:
1151                 folderview_rm_imap_folder_cb(folderview, 0, NULL);
1152         case F_NEWS:
1153         default:
1154                 break;
1155         }
1156 }
1157
1158
1159 /* callback functions */
1160
1161 static void folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1162                                       FolderView *folderview)
1163 {
1164         GtkCList *clist = GTK_CLIST(ctree);
1165         gint prev_row = -1, row = -1, column = -1;
1166         FolderItem *item;
1167         Folder *folder;
1168
1169         if (!event) return;
1170
1171         if (event->button == 1) {
1172                 folderview->open_folder = TRUE;
1173                 return;
1174         }
1175
1176         if (event->button == 2 || event->button == 3) {
1177                 /* right clicked */
1178                 if (clist->selection) {
1179                         GtkCTreeNode *node;
1180
1181                         node = GTK_CTREE_NODE(clist->selection->data);
1182                         if (node)
1183                                 prev_row = gtkut_ctree_get_nth_from_node
1184                                         (GTK_CTREE(ctree), node);
1185                 }
1186
1187                 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1188                                                   &row, &column))
1189                         return;
1190                 if (prev_row != row) {
1191                         gtk_clist_unselect_all(clist);
1192                         if (event->button == 2)
1193                                 folderview_select_node
1194                                         (folderview,
1195                                          gtk_ctree_node_nth(GTK_CTREE(ctree),
1196                                                             row));
1197                         else
1198                                 gtk_clist_select_row(clist, row, column);
1199                 }
1200         }
1201
1202         if (event->button != 3) return;
1203
1204         item = gtk_clist_get_row_data(clist, row);
1205         g_return_if_fail(item != NULL);
1206         g_return_if_fail(item->folder != NULL);
1207         folder = item->folder;
1208
1209         menu_set_insensitive_all(GTK_MENU_SHELL(folderview->mail_popup));
1210         menu_set_insensitive_all(GTK_MENU_SHELL(folderview->imap_popup));
1211         menu_set_insensitive_all(GTK_MENU_SHELL(folderview->news_popup));
1212         menu_set_insensitive_all(GTK_MENU_SHELL(folderview->mbox_popup));
1213
1214         if (FOLDER_IS_LOCAL(folder) && item->parent == NULL) {
1215                 menu_set_sensitive(folderview->mail_factory,
1216                                    "/Create new folder...", TRUE);
1217                 menu_set_sensitive(folderview->mail_factory,
1218                                    "/Update folder tree", TRUE);
1219                 menu_set_sensitive(folderview->mail_factory,
1220                                    "/Remove mailbox", TRUE);
1221         } else if (FOLDER_IS_LOCAL(folder) && item->stype != F_NORMAL) {
1222                 menu_set_sensitive(folderview->mail_factory,
1223                                    "/Create new folder...", TRUE);
1224                 menu_set_sensitive(folderview->mail_factory,
1225                                    "/Scoring...", TRUE);
1226         } else if (FOLDER_IS_LOCAL(folder)) {
1227                 menu_set_sensitive(folderview->mail_factory,
1228                                    "/Create new folder...", TRUE);
1229                 menu_set_sensitive(folderview->mail_factory,
1230                                    "/Rename folder...", TRUE);
1231                 menu_set_sensitive(folderview->mail_factory,
1232                                    "/Delete folder", TRUE);
1233                 menu_set_sensitive(folderview->mail_factory,
1234                                    "/Scoring...", TRUE);
1235                 menu_set_sensitive(folderview->mail_factory,
1236                                    "/Property...", TRUE);
1237         } else if (folder->type == F_IMAP && item->parent == NULL) {
1238                 menu_set_sensitive(folderview->imap_factory,
1239                                    "/Create new folder...", TRUE);
1240                 menu_set_sensitive(folderview->imap_factory,
1241                                    "/Update folder tree", TRUE);
1242                 menu_set_sensitive(folderview->imap_factory,
1243                                    "/Remove IMAP4 account", TRUE);
1244         } else if (folder->type == F_IMAP && item->stype != F_NORMAL) {
1245                 menu_set_sensitive(folderview->imap_factory,
1246                                    "/Create new folder...", TRUE);
1247         } else if (folder->type == F_IMAP) {
1248                 menu_set_sensitive(folderview->imap_factory,
1249                                    "/Create new folder...", TRUE);
1250                 menu_set_sensitive(folderview->imap_factory,
1251                                    "/Delete folder", TRUE);
1252                 menu_set_sensitive(folderview->imap_factory,
1253                                    "/Scoring...", TRUE);
1254         } else if (folder->type == F_NEWS && item->parent == NULL) {
1255                 menu_set_sensitive(folderview->news_factory,
1256                                    "/Subscribe to newsgroup...", TRUE);
1257                 menu_set_sensitive(folderview->news_factory,
1258                                    "/Remove news account", TRUE);
1259         } else if (folder->type == F_NEWS) {
1260                 menu_set_sensitive(folderview->news_factory,
1261                                    "/Subscribe to newsgroup...", TRUE);
1262                 menu_set_sensitive(folderview->news_factory,
1263                                    "/Remove newsgroup", TRUE);
1264                 menu_set_sensitive(folderview->news_factory,
1265                                    "/Scoring...", TRUE);
1266         }
1267         if (folder->type == F_MBOX && item->parent == NULL) {
1268                 menu_set_sensitive(folderview->mbox_factory,
1269                                    "/Create new folder...", TRUE);
1270                 menu_set_sensitive(folderview->mbox_factory,
1271                                    "/Remove mailbox", TRUE);
1272         } else if (folder->type == F_MBOX && item->stype != F_NORMAL) {
1273                 menu_set_sensitive(folderview->mbox_factory,
1274                                    "/Create new folder...", TRUE);
1275                 menu_set_sensitive(folderview->mbox_factory,
1276                                    "/Scoring...", TRUE);
1277         } else if (folder->type == F_MBOX) {
1278                 menu_set_sensitive(folderview->mbox_factory,
1279                                    "/Create new folder...", TRUE);
1280                 menu_set_sensitive(folderview->mbox_factory,
1281                                    "/Rename folder...", TRUE);
1282                 menu_set_sensitive(folderview->mbox_factory,
1283                                    "/Delete folder", TRUE);
1284                 menu_set_sensitive(folderview->mbox_factory,
1285                                    "/Scoring...", TRUE);
1286         }
1287
1288         if (FOLDER_IS_LOCAL(folder))
1289                 gtk_menu_popup(GTK_MENU(folderview->mail_popup), NULL, NULL,
1290                                NULL, NULL, event->button, event->time);
1291         else if (folder->type == F_IMAP)
1292                 gtk_menu_popup(GTK_MENU(folderview->imap_popup), NULL, NULL,
1293                                NULL, NULL, event->button, event->time);
1294         else if (folder->type == F_NEWS)
1295                 gtk_menu_popup(GTK_MENU(folderview->news_popup), NULL, NULL,
1296                                NULL, NULL, event->button, event->time);
1297         else if (folder->type == F_MBOX)
1298                 gtk_menu_popup(GTK_MENU(folderview->mbox_popup), NULL, NULL,
1299                                NULL, NULL, event->button, event->time);
1300 }
1301
1302 static void folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1303                                        FolderView *folderview)
1304 {
1305         if (!event) return;
1306
1307         if (event->button == 1 && folderview->open_folder == FALSE &&
1308             folderview->opened != NULL) {
1309                 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1310                 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1311                                           folderview->opened);
1312         }
1313 }
1314
1315 #define BREAK_ON_MODIFIER_KEY() \
1316         if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
1317
1318 static void folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1319                                    FolderView *folderview)
1320 {
1321         if (!event) return;
1322
1323         switch (event->keyval) {
1324         case GDK_Return:
1325         case GDK_space:
1326                 if (folderview->selected) {
1327                         folderview_select_node(folderview,
1328                                                folderview->selected);
1329                 }
1330                 break;
1331         case GDK_v:
1332         case GDK_V:
1333         case GDK_g:
1334         case GDK_G:
1335         case GDK_x:
1336         case GDK_X:
1337         case GDK_w:
1338         case GDK_D:
1339         case GDK_Q:
1340                 BREAK_ON_MODIFIER_KEY();
1341                 summary_pass_key_press_event(folderview->summaryview, event);
1342         default:
1343         }
1344 }
1345
1346 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
1347                                 gint column, FolderView *folderview)
1348 {
1349         static gboolean can_select = TRUE;      /* exclusive lock */
1350         gboolean opened;
1351         FolderItem *item;
1352
1353         folderview->selected = row;
1354
1355         if (folderview->opened == row) {
1356                 folderview->open_folder = FALSE;
1357                 return;
1358         }
1359
1360         if (!can_select) {
1361                 gtk_ctree_select(ctree, folderview->opened);
1362                 gtkut_ctree_set_focus_row(ctree, folderview->opened);
1363                 return;
1364         }
1365
1366         if (!folderview->open_folder) return;
1367
1368         item = gtk_ctree_node_get_row_data(ctree, row);
1369         if (!item) return;
1370
1371         can_select = FALSE;
1372
1373         if (item->path)
1374                 debug_print(_("Folder %s is selected\n"), item->path);
1375
1376         if (!GTK_CTREE_ROW(row)->children)
1377                 gtk_ctree_expand(ctree, row);
1378         if (folderview->opened &&
1379             !GTK_CTREE_ROW(folderview->opened)->children)
1380                 gtk_ctree_collapse(ctree, folderview->opened);
1381
1382         /* ungrab the mouse event */
1383         if (GTK_WIDGET_HAS_GRAB(ctree)) {
1384                 gtk_grab_remove(GTK_WIDGET(ctree));
1385                 if (gdk_pointer_is_grabbed())
1386                         gdk_pointer_ungrab(GDK_CURRENT_TIME);
1387         }
1388
1389         opened = summary_show(folderview->summaryview, item, FALSE);
1390
1391         if (!opened) {
1392                 gtk_ctree_select(ctree, folderview->opened);
1393                 gtkut_ctree_set_focus_row(ctree, folderview->opened);
1394         } else
1395                 folderview->opened = row;
1396
1397         folderview->open_folder = FALSE;
1398         can_select = TRUE;
1399 }
1400
1401 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
1402                                      FolderView *folderview)
1403 {
1404         FolderItem *item;
1405
1406         item = gtk_ctree_node_get_row_data(ctree, node);
1407         g_return_if_fail(item != NULL);
1408         item->collapsed = FALSE;
1409         folderview_update_node(folderview, node);
1410 }
1411
1412 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
1413                                       FolderView *folderview)
1414 {
1415         FolderItem *item;
1416
1417         item = gtk_ctree_node_get_row_data(ctree, node);
1418         g_return_if_fail(item != NULL);
1419         item->collapsed= TRUE;
1420         folderview_update_node(folderview, node);
1421 }
1422
1423 static void folderview_popup_close(GtkMenuShell *menu_shell,
1424                                    FolderView *folderview)
1425 {
1426         if (!folderview->opened) return;
1427
1428         gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
1429         gtkut_ctree_set_focus_row(GTK_CTREE(folderview->ctree),
1430                                   folderview->opened);
1431 }
1432
1433 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
1434                                    FolderView *folderview)
1435 {
1436         switch (column) {
1437         case COL_FOLDER:
1438                 prefs_common.folder_col_folder = width;
1439                 break;
1440         case COL_NEW:
1441                 prefs_common.folder_col_new = width;
1442                 break;
1443         case COL_UNREAD:
1444                 prefs_common.folder_col_unread = width;
1445                 break;
1446         case COL_TOTAL:
1447                 prefs_common.folder_col_total = width;
1448                 break;
1449         default:
1450         }
1451 }
1452
1453 static GtkCTreeNode *folderview_find_by_name(GtkCTree *ctree,
1454                                              GtkCTreeNode *node,
1455                                              const gchar *name)
1456 {
1457         FolderItem *item;
1458
1459         if (!node)
1460                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1461         if (!node)
1462                 return NULL;
1463
1464         node = GTK_CTREE_ROW(node)->children;
1465
1466         while (node) {
1467                 item = gtk_ctree_node_get_row_data(ctree, node);
1468                 if (!folderview_compare_name(item, name))
1469                         return node;
1470                 node = GTK_CTREE_ROW(node)->sibling;
1471         }
1472
1473         return NULL;
1474 }
1475
1476 static void folderview_update_tree_cb(FolderView *folderview, guint action,
1477                                       GtkWidget *widget)
1478 {
1479         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1480         FolderItem *item;
1481
1482         if (!folderview->selected) return;
1483
1484         summary_show(folderview->summaryview, NULL, FALSE);
1485
1486         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1487         g_return_if_fail(item != NULL);
1488         g_return_if_fail(item->folder != NULL);
1489
1490         folderview_update_tree(item->folder);
1491 }
1492
1493 static void folderview_new_folder_cb(FolderView *folderview, guint action,
1494                                      GtkWidget *widget)
1495 {
1496         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1497         gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
1498         FolderItem *item;
1499         FolderItem *new_item;
1500         gchar *new_folder;
1501         GtkCTreeNode *node;
1502
1503         if (!folderview->selected) return;
1504
1505         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1506         g_return_if_fail(item != NULL);
1507         g_return_if_fail(item->folder != NULL);
1508
1509         new_folder = input_dialog(_("New folder"),
1510                                   _("Input the name of new folder:"),
1511                                   _("NewFolder"));
1512         if (!new_folder) return;
1513
1514         if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
1515                 alertpanel_error(_("`%c' can't be included in folder name."),
1516                                  G_DIR_SEPARATOR);
1517                 g_free(new_folder);
1518                 return;
1519         }
1520
1521         /* find whether the directory already exists */
1522         if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
1523                 alertpanel_error(_("The folder `%s' already exists."),
1524                                  new_folder);
1525                 g_free(new_folder);
1526                 return;
1527         }
1528
1529         new_item = item->folder->create_folder(item->folder, item, new_folder);
1530         g_free(new_folder);
1531         if (!new_item) return;
1532
1533         gtk_clist_freeze(GTK_CLIST(ctree));
1534
1535         text[COL_FOLDER] = new_item->name;
1536         node = gtk_ctree_insert_node(ctree, folderview->selected, NULL, text,
1537                                      FOLDER_SPACING,
1538                                      folderxpm, folderxpmmask,
1539                                      folderopenxpm, folderopenxpmmask,
1540                                      FALSE, FALSE);
1541         gtk_ctree_expand(ctree, folderview->selected);
1542         gtk_ctree_node_set_row_data(ctree, node, new_item);
1543         folderview_sort_folders(folderview, folderview->selected, item->folder);
1544
1545         gtk_clist_thaw(GTK_CLIST(ctree));
1546
1547         folder_write_list();
1548 }
1549
1550 static void folderview_new_mbox_folder_cb(FolderView *folderview, guint action,
1551                                           GtkWidget *widget)
1552 {
1553         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1554         gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
1555         FolderItem *item;
1556         FolderItem *new_item;
1557         gchar *new_folder;
1558         GtkCTreeNode *node;
1559
1560         if (!folderview->selected) return;
1561
1562         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1563         g_return_if_fail(item != NULL);
1564         g_return_if_fail(item->folder != NULL);
1565
1566         new_folder = input_dialog(_("New folder"),
1567                                   _("Input the name of new folder:"),
1568                                   _("NewFolder"));
1569         if (!new_folder) return;
1570
1571         /* find whether the directory already exists */
1572         if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
1573                 alertpanel_error(_("The folder `%s' already exists."),
1574                                  new_folder);
1575                 g_free(new_folder);
1576                 return;
1577         }
1578
1579         new_item = item->folder->create_folder(item->folder, item, new_folder);
1580         g_free(new_folder);
1581         if (!new_item) return;
1582
1583         gtk_clist_freeze(GTK_CLIST(ctree));
1584
1585         text[COL_FOLDER] = new_item->name;
1586         node = gtk_ctree_insert_node(ctree, folderview->selected, NULL, text,
1587                                      FOLDER_SPACING,
1588                                      folderxpm, folderxpmmask,
1589                                      folderopenxpm, folderopenxpmmask,
1590                                      FALSE, FALSE);
1591         gtk_ctree_expand(ctree, folderview->selected);
1592         gtk_ctree_node_set_row_data(ctree, node, new_item);
1593         folderview_sort_folders(folderview, folderview->selected, item->folder);
1594
1595         gtk_clist_thaw(GTK_CLIST(ctree));
1596
1597         folder_write_list();
1598 }
1599
1600 static void folderview_rename_folder_cb(FolderView *folderview, guint action,
1601                                         GtkWidget *widget)
1602 {
1603         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1604         FolderItem *item;
1605         gchar *new_folder;
1606         gchar *message;
1607
1608         if (!folderview->selected) return;
1609
1610         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1611         g_return_if_fail(item != NULL);
1612         g_return_if_fail(item->path != NULL);
1613         g_return_if_fail(item->folder != NULL);
1614
1615         message = g_strdup_printf(_("Input new name for `%s':"),
1616                                   g_basename(item->path));
1617         new_folder = input_dialog(_("Rename folder"), message,
1618                                   g_basename(item->path));
1619         g_free(message);
1620         if (!new_folder) return;
1621
1622         if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
1623                 alertpanel_error(_("`%c' can't be included in folder name."),
1624                                  G_DIR_SEPARATOR);
1625                 g_free(new_folder);
1626                 return;
1627         }
1628
1629         if (folderview_find_by_name
1630                 (ctree, GTK_CTREE_ROW(folderview->selected)->parent,
1631                  new_folder)) {
1632                 alertpanel_error(_("The folder `%s' already exists."),
1633                                  new_folder);
1634                 g_free(new_folder);
1635                 return;
1636         }
1637
1638         if (item->folder->rename_folder(item->folder, item, new_folder) < 0) {
1639                 g_free(new_folder);
1640                 return;
1641         }
1642         g_free(new_folder);
1643
1644         gtk_clist_freeze(GTK_CLIST(ctree));
1645
1646         folderview_update_node(folderview, folderview->selected);
1647         folderview_sort_folders(folderview,
1648                                 GTK_CTREE_ROW(folderview->selected)->parent,
1649                                 item->folder);
1650         if (folderview->opened == folderview->selected) {
1651                 if (!GTK_CTREE_ROW(folderview->opened)->children)
1652                         gtk_ctree_expand(ctree, folderview->opened);
1653                 summary_show(folderview->summaryview, item, FALSE);
1654         }
1655
1656         gtk_clist_thaw(GTK_CLIST(ctree));
1657
1658         folder_write_list();
1659 }
1660
1661 static void folderview_rename_mbox_folder_cb(FolderView *folderview,
1662                                              guint action,
1663                                              GtkWidget *widget)
1664 {
1665         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1666         FolderItem *item;
1667         gchar *new_folder;
1668         gchar *message;
1669
1670         if (!folderview->selected) return;
1671
1672         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1673         g_return_if_fail(item != NULL);
1674         g_return_if_fail(item->path != NULL);
1675         g_return_if_fail(item->folder != NULL);
1676
1677         message = g_strdup_printf(_("Input new name for `%s':"),
1678                                   g_basename(item->path));
1679         new_folder = input_dialog(_("Rename folder"), message,
1680                                   g_basename(item->path));
1681         g_free(message);
1682         if (!new_folder) return;
1683
1684         if (folderview_find_by_name
1685                 (ctree, GTK_CTREE_ROW(folderview->selected)->parent,
1686                  new_folder)) {
1687                 alertpanel_error(_("The folder `%s' already exists."),
1688                                  new_folder);
1689                 g_free(new_folder);
1690                 return;
1691         }
1692
1693         if (item->folder->rename_folder(item->folder, item, new_folder) < 0) {
1694                 g_free(new_folder);
1695                 return;
1696         }
1697         g_free(new_folder);
1698
1699         gtk_clist_freeze(GTK_CLIST(ctree));
1700
1701         folderview_update_node(folderview, folderview->selected);
1702         folderview_sort_folders(folderview,
1703                                 GTK_CTREE_ROW(folderview->selected)->parent,
1704                                 item->folder);
1705         if (folderview->opened == folderview->selected) {
1706                 if (!GTK_CTREE_ROW(folderview->opened)->children)
1707                         gtk_ctree_expand(ctree, folderview->opened);
1708                 summary_show(folderview->summaryview, item, FALSE);
1709         }
1710
1711         gtk_clist_thaw(GTK_CLIST(ctree));
1712
1713         folder_write_list();
1714 }
1715
1716 static void folderview_delete_folder_cb(FolderView *folderview, guint action,
1717                                         GtkWidget *widget)
1718 {
1719         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1720         FolderItem *item;
1721         gchar *message;
1722         AlertValue avalue;
1723
1724         if (!folderview->selected) return;
1725
1726         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1727         g_return_if_fail(item != NULL);
1728         g_return_if_fail(item->path != NULL);
1729         g_return_if_fail(item->folder != NULL);
1730
1731         message = g_strdup_printf
1732                 (_("All folder(s) and message(s) under `%s' will be deleted.\n"
1733                    "Do you really want to delete?"),
1734                  g_basename(item->path));
1735         avalue = alertpanel(_("Delete folder"), message,
1736                             _("Yes"), _("+No"), NULL);
1737         g_free(message);
1738         if (avalue != G_ALERTDEFAULT) return;
1739
1740         if (item->folder->remove_folder(item->folder, item) < 0) {
1741                 alertpanel_error(_("Can't remove the folder `%s'."),
1742                                  item->path);
1743                 return;
1744         }
1745
1746         if (folderview->opened == folderview->selected ||
1747             gtk_ctree_is_ancestor(ctree,
1748                                   folderview->selected,
1749                                   folderview->opened)) {
1750                 summary_clear_all(folderview->summaryview);
1751                 folderview->opened = NULL;
1752         }
1753
1754         gtk_ctree_remove_node(ctree, folderview->selected);
1755         folder_write_list();
1756 }
1757
1758 static void folderview_remove_mailbox_cb(FolderView *folderview, guint action,
1759                                          GtkWidget *widget)
1760 {
1761         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1762         GtkCTreeNode *node;
1763         FolderItem *item;
1764         gchar *message;
1765         AlertValue avalue;
1766
1767         if (!folderview->selected) return;
1768         node = folderview->selected;
1769         item = gtk_ctree_node_get_row_data(ctree, node);
1770         g_return_if_fail(item != NULL);
1771         g_return_if_fail(item->folder != NULL);
1772         if (item->parent) return;
1773
1774         message = g_strdup_printf
1775                 (_("Really remove the mailbox `%s' ?\n"
1776                    "(The messages are NOT deleted from disk)"),
1777                  item->folder->name);
1778         avalue = alertpanel(_("Remove folder"), message,
1779                             _("Yes"), _("+No"), NULL);
1780         g_free(message);
1781         if (avalue != G_ALERTDEFAULT) return;
1782
1783         folder_destroy(item->folder);
1784         summary_clear_all(folderview->summaryview);
1785         folderview_unselect(folderview);
1786         gtk_ctree_remove_node(ctree, node);
1787         folder_write_list();
1788 }
1789
1790 static void folderview_new_imap_folder_cb(FolderView *folderview, guint action,
1791                                           GtkWidget *widget)
1792 {
1793         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1794         gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
1795         GtkCTreeNode *node;
1796         FolderItem *item;
1797         FolderItem *new_item;
1798         gchar *new_folder;
1799         gchar *p;
1800
1801         if (!folderview->selected) return;
1802
1803         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1804         g_return_if_fail(item != NULL);
1805         g_return_if_fail(item->folder != NULL);
1806         g_return_if_fail(item->folder->type == F_IMAP);
1807         g_return_if_fail(item->folder->account != NULL);
1808
1809         new_folder = input_dialog
1810                 (_("New folder"),
1811                  _("Input the name of new folder:\n"
1812                    "(if you want to create a folder to store subfolders,\n"
1813                    " append `/' at the end of the name)"),
1814                  _("NewFolder"));
1815         if (!new_folder) return;
1816
1817         if ((p = strchr(new_folder, G_DIR_SEPARATOR)) != NULL &&
1818             *(p + 1) != '\0') {
1819                 alertpanel_error(_("`%c' can't be included in folder name."),
1820                                  G_DIR_SEPARATOR);
1821                 g_free(new_folder);
1822                 return;
1823         }
1824
1825         /* find whether the directory already exists */
1826         if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
1827                 alertpanel_error(_("The folder `%s' already exists."),
1828                                  new_folder);
1829                 g_free(new_folder);
1830                 return;
1831         }
1832
1833         new_item = item->folder->create_folder(item->folder, item, new_folder);
1834         if (!new_item) {
1835                 alertpanel_error(_("Can't create the folder `%s'."),
1836                                  new_folder);
1837                 g_free(new_folder);
1838                 return;
1839         }
1840         g_free(new_folder);
1841
1842         gtk_clist_freeze(GTK_CLIST(ctree));
1843
1844         text[COL_FOLDER] = new_item->name;
1845         node = gtk_ctree_insert_node(ctree, folderview->selected, NULL, text,
1846                                      FOLDER_SPACING,
1847                                      folderxpm, folderxpmmask,
1848                                      folderopenxpm, folderopenxpmmask,
1849                                      FALSE, FALSE);
1850         gtk_ctree_expand(ctree, folderview->selected);
1851         gtk_ctree_node_set_row_data(ctree, node, new_item);
1852         folderview_sort_folders(folderview, folderview->selected, item->folder);
1853
1854         gtk_clist_thaw(GTK_CLIST(ctree));
1855
1856         folder_write_list();
1857 }
1858
1859 static void folderview_rm_imap_folder_cb(FolderView *folderview, guint action,
1860                                          GtkWidget *widget)
1861 {
1862         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1863         FolderItem *item;
1864         gchar *message;
1865         AlertValue avalue;
1866
1867         if (!folderview->selected) return;
1868
1869         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1870         g_return_if_fail(item != NULL);
1871         g_return_if_fail(item->folder != NULL);
1872         g_return_if_fail(item->folder->type == F_IMAP);
1873         g_return_if_fail(item->folder->account != NULL);
1874
1875         message = g_strdup_printf(_("Really delete folder `%s'?"),
1876                                   g_basename(item->path));
1877         avalue = alertpanel(_("Delete folder"), message,
1878                             _("Yes"), _("+No"), NULL);
1879         g_free(message);
1880         if (avalue != G_ALERTDEFAULT) return;
1881
1882         if (item->folder->remove_folder(item->folder, item) < 0) {
1883                 alertpanel_error(_("Can't remove the folder `%s'."),
1884                                  item->path);
1885                 if (folderview->opened == folderview->selected)
1886                         summary_show(folderview->summaryview,
1887                                      folderview->summaryview->folder_item,
1888                                      FALSE);
1889                 return;
1890         }
1891
1892         if (folderview->opened == folderview->selected ||
1893             gtk_ctree_is_ancestor(ctree,
1894                                   folderview->selected,
1895                                   folderview->opened)) {
1896                 summary_clear_all(folderview->summaryview);
1897                 folderview->opened = NULL;
1898         }
1899
1900         gtk_ctree_remove_node(ctree, folderview->selected);
1901         folder_write_list();
1902 }
1903
1904 static void folderview_rm_imap_server_cb(FolderView *folderview, guint action,
1905                                          GtkWidget *widget)
1906 {
1907         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1908         FolderItem *item;
1909         gchar *message;
1910         AlertValue avalue;
1911
1912         if (!folderview->selected) return;
1913
1914         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1915         g_return_if_fail(item != NULL);
1916         g_return_if_fail(item->folder != NULL);
1917         g_return_if_fail(item->folder->type == F_IMAP);
1918         g_return_if_fail(item->folder->account != NULL);
1919
1920         message = g_strdup_printf(_("Really delete IMAP4 account `%s'?"),
1921                                   item->folder->name);
1922         avalue = alertpanel(_("Delete IMAP4 account"), message,
1923                             _("Yes"), _("+No"), NULL);
1924         g_free(message);
1925
1926         if (avalue != G_ALERTDEFAULT) return;
1927
1928         if (folderview->opened == folderview->selected ||
1929             gtk_ctree_is_ancestor(ctree,
1930                                   folderview->selected,
1931                                   folderview->opened)) {
1932                 summary_clear_all(folderview->summaryview);
1933                 folderview->opened = NULL;
1934         }
1935
1936         account_destroy(item->folder->account);
1937         folder_destroy(item->folder);
1938         gtk_ctree_remove_node(ctree, folderview->selected);
1939         account_set_menu();
1940         main_window_reflect_prefs_all();
1941         folder_write_list();
1942 }
1943
1944 static void folderview_new_news_group_cb(FolderView *folderview, guint action,
1945                                          GtkWidget *widget)
1946 {
1947         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1948         gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
1949         GtkCTreeNode *servernode, *node;
1950         FolderItem *item;
1951         FolderItem *newitem;
1952         gchar *new_group;
1953         const gchar *server;
1954
1955         if (!folderview->selected) return;
1956
1957         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1958         g_return_if_fail(item != NULL);
1959         g_return_if_fail(item->folder != NULL);
1960         g_return_if_fail(item->folder->type == F_NEWS);
1961         g_return_if_fail(item->folder->account != NULL);
1962
1963         new_group = grouplist_dialog(item->folder);
1964         if (!new_group) return;
1965
1966         if (GTK_CTREE_ROW(folderview->selected)->parent != NULL)
1967                 servernode = GTK_CTREE_ROW(folderview->selected)->parent;
1968         else
1969                 servernode = folderview->selected;
1970
1971         if (folderview_find_by_name(ctree, servernode, new_group)) {
1972                 alertpanel_error(_("The newsgroup `%s' already exists."),
1973                                  new_group);
1974                 g_free(new_group);
1975                 return;
1976         }
1977
1978         gtk_clist_freeze(GTK_CLIST(ctree));
1979
1980         text[COL_FOLDER] = new_group;
1981         node = gtk_ctree_insert_node(ctree, servernode, NULL, text,
1982                                      FOLDER_SPACING,
1983                                      folderxpm, folderxpmmask,
1984                                      folderopenxpm, folderopenxpmmask,
1985                                      FALSE, FALSE);
1986         gtk_ctree_expand(ctree, servernode);
1987
1988         item = gtk_ctree_node_get_row_data(ctree, servernode);
1989         server = item->folder->account->nntp_server;
1990
1991         newitem = folder_item_new(new_group, new_group);
1992         g_free(new_group);
1993         folder_item_append(item, newitem);
1994         gtk_ctree_node_set_row_data(ctree, node, newitem);
1995         gtk_ctree_sort_node(ctree, servernode);
1996
1997         gtk_clist_thaw(GTK_CLIST(ctree));
1998
1999         folder_write_list();
2000 }
2001
2002 static void folderview_rm_news_group_cb(FolderView *folderview, guint action,
2003                                         GtkWidget *widget)
2004 {
2005         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2006         FolderItem *item;
2007         gchar *message;
2008         AlertValue avalue;
2009
2010         if (!folderview->selected) return;
2011
2012         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2013         g_return_if_fail(item != NULL);
2014         g_return_if_fail(item->folder != NULL);
2015         g_return_if_fail(item->folder->type == F_NEWS);
2016         g_return_if_fail(item->folder->account != NULL);
2017
2018         message = g_strdup_printf(_("Really delete newsgroup `%s'?"),
2019                                   g_basename(item->path));
2020         avalue = alertpanel(_("Delete newsgroup"), message,
2021                             _("Yes"), _("+No"), NULL);
2022         g_free(message);
2023         if (avalue != G_ALERTDEFAULT) return;
2024
2025         if (folderview->opened == folderview->selected) {
2026                 summary_clear_all(folderview->summaryview);
2027                 folderview->opened = NULL;
2028         }
2029
2030         folder_item_remove(item);
2031         gtk_ctree_remove_node(ctree, folderview->selected);
2032         folder_write_list();
2033 }
2034
2035 static void folderview_rm_news_server_cb(FolderView *folderview, guint action,
2036                                          GtkWidget *widget)
2037 {
2038         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2039         FolderItem *item;
2040         gchar *message;
2041         AlertValue avalue;
2042
2043         if (!folderview->selected) return;
2044
2045         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2046         g_return_if_fail(item != NULL);
2047         g_return_if_fail(item->folder != NULL);
2048         g_return_if_fail(item->folder->type == F_NEWS);
2049         g_return_if_fail(item->folder->account != NULL);
2050
2051         message = g_strdup_printf(_("Really delete news account `%s'?"),
2052                                   item->folder->name);
2053         avalue = alertpanel(_("Delete news account"), message,
2054                             _("Yes"), _("+No"), NULL);
2055         g_free(message);
2056
2057         if (avalue != G_ALERTDEFAULT) return;
2058
2059         if (folderview->opened == folderview->selected ||
2060             gtk_ctree_is_ancestor(ctree,
2061                                   folderview->selected,
2062                                   folderview->opened)) {
2063                 summary_clear_all(folderview->summaryview);
2064                 folderview->opened = NULL;
2065         }
2066
2067         account_destroy(item->folder->account);
2068         folder_destroy(item->folder);
2069         gtk_ctree_remove_node(ctree, folderview->selected);
2070         account_set_menu();
2071         main_window_reflect_prefs_all();
2072         folder_write_list();
2073 }
2074
2075 static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
2076                                           GdkDragContext *context,
2077                                           gint            x,
2078                                           gint            y,
2079                                           guint           time,
2080                                           FolderView     *folderview)
2081 {
2082         gint row, column;
2083         FolderItem *item, *current_item;
2084         GtkCTreeNode *node = NULL;
2085         gboolean acceptable = FALSE;
2086
2087         if (gtk_clist_get_selection_info(GTK_CLIST(widget),
2088                                          x - 24, y - 24, &row, &column)) {
2089                 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2090                 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2091                 current_item = folderview->summaryview->folder_item;
2092                 if (item != NULL &&
2093                     item->path != NULL &&
2094                     current_item != NULL &&
2095                     current_item != item) {
2096                         switch (item->folder->type){
2097                         case F_MH:
2098                                 if (current_item->folder->type == F_MH)
2099                                     acceptable = TRUE;
2100                                 break;
2101                         case F_IMAP:
2102                                 if (current_item->folder->account == item->folder->account)
2103                                     acceptable = TRUE;
2104                                 break;
2105                         default:
2106                         }
2107                 }
2108         }
2109
2110         if (acceptable) {
2111                 gtk_ctree_select(GTK_CTREE(widget), node);
2112                 gdk_drag_status(context, context->suggested_action, time);
2113         } else {
2114                 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2115                 gdk_drag_status(context, 0, time);
2116         }
2117
2118         return acceptable;
2119 }
2120
2121 static void folderview_drag_leave_cb(GtkWidget      *widget,
2122                                      GdkDragContext *context,
2123                                      guint           time,
2124                                      FolderView     *folderview)
2125 {
2126         gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2127 }
2128
2129 static void folderview_drag_received_cb(GtkWidget        *widget,
2130                                         GdkDragContext   *drag_context,
2131                                         gint              x,
2132                                         gint              y,
2133                                         GtkSelectionData *data,
2134                                         guint             info,
2135                                         guint             time,
2136                                         FolderView       *folderview)
2137 {
2138         gint row, column;
2139         FolderItem *item;
2140         GtkCTreeNode *node;
2141
2142         if (gtk_clist_get_selection_info(GTK_CLIST(widget),
2143                                          x - 24, y - 24, &row, &column) == 0)
2144                 return;
2145
2146         node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2147         item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2148         if (item != NULL) {
2149                 summary_move_selected_to(folderview->summaryview, item);
2150                 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2151         } else
2152                 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2153 }
2154
2155 static gint folderview_compare_name(gconstpointer a, gconstpointer b)
2156 {
2157         const FolderItem *item = a;
2158         const gchar *name = b;
2159
2160         if (!item->path) return -1;
2161         return strcmp2(g_basename(item->path), name);
2162 }
2163
2164 static void folderview_scoring_cb(FolderView *folderview, guint action,
2165                                    GtkWidget *widget)
2166 {
2167         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2168         FolderItem *item;
2169
2170         if (!folderview->selected) return;
2171
2172         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2173         g_return_if_fail(item != NULL);
2174         g_return_if_fail(item->folder != NULL);
2175
2176         prefs_scoring_open(item);
2177 }
2178
2179 static void folderview_property_cb(FolderView *folderview, guint action, GtkWidget *widget) {
2180         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2181         FolderItem *item;
2182
2183         if (!folderview->selected) return;
2184
2185         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2186         g_return_if_fail(item != NULL);
2187         g_return_if_fail(item->folder != NULL);
2188
2189         prefs_folder_item_create(item);
2190 }
2191
2192 void folderview_set_target_folder_color(gint color_op) {
2193         GList *list;
2194         FolderView *folderview;
2195
2196         for (list = folderview_list; list != NULL; list = list->next) {
2197                 folderview = (FolderView *)list->data;
2198                 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2199         }
2200 }