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