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