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