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