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