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