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