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