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