inital gtk2 patch
[claws.git] / src / folderview.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2003 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 "prefs_filtering.h"
58 #include "prefs_scoring.h"
59 #include "prefs_folder_item.h"
60 #include "account.h"
61 #include "folder.h"
62 #include "foldersel.h"
63 #include "inc.h"
64 #include "statusbar.h"
65 #include "hooks.h"
66
67 typedef enum
68 {
69         COL_FOLDER      = 0,
70         COL_NEW         = 1,
71         COL_UNREAD      = 2,
72         COL_TOTAL       = 3
73 } FolderColumnPos;
74
75 #define N_FOLDER_COLS           4
76 #define COL_FOLDER_WIDTH        150
77 #define COL_NUM_WIDTH           32
78
79 static GList *folderview_list = NULL;
80
81 static GtkStyle *normal_style;
82 static GtkStyle *normal_color_style;
83 static GtkStyle *bold_style;
84 static GtkStyle *bold_color_style;
85 static GtkStyle *bold_tgtfold_style;
86
87 static GdkBitmap *inboxxpm;
88 static GdkBitmap *inboxxpmmask;
89 static GdkPixmap *inboxhrmxpm;
90 static GdkBitmap *inboxhrmxpmmask;
91 static GdkPixmap *inboxopenxpm;
92 static GdkBitmap *inboxopenxpmmask;
93 static GdkPixmap *inboxopenhrmxpm;
94 static GdkBitmap *inboxopenhrmxpmmask;
95 static GdkPixmap *outboxxpm;
96 static GdkBitmap *outboxxpmmask;
97 static GdkPixmap *outboxhrmxpm;
98 static GdkBitmap *outboxhrmxpmmask;
99 static GdkPixmap *outboxopenxpm;
100 static GdkBitmap *outboxopenxpmmask;
101 static GdkPixmap *outboxopenhrmxpm;
102 static GdkBitmap *outboxopenhrmxpmmask;
103 static GdkPixmap *folderxpm;
104 static GdkBitmap *folderxpmmask;
105 static GdkPixmap *folderhrmxpm;
106 static GdkBitmap *folderhrmxpmmask;
107 static GdkPixmap *folderopenxpm;
108 static GdkBitmap *folderopenxpmmask;
109 static GdkPixmap *folderopenhrmxpm;
110 static GdkBitmap *folderopenhrmxpmmask;
111 static GdkPixmap *trashopenxpm;
112 static GdkBitmap *trashopenxpmmask;
113 static GdkPixmap *trashopenhrmxpm;
114 static GdkBitmap *trashopenhrmxpmmask;
115 static GdkPixmap *trashxpm;
116 static GdkBitmap *trashxpmmask;
117 static GdkPixmap *trashhrmxpm;
118 static GdkBitmap *trashhrmxpmmask;
119 static GdkPixmap *queuexpm;
120 static GdkBitmap *queuexpmmask;
121 static GdkPixmap *queuehrmxpm;
122 static GdkBitmap *queuehrmxpmmask;
123 static GdkPixmap *queueopenxpm;
124 static GdkBitmap *queueopenxpmmask;
125 static GdkPixmap *queueopenhrmxpm;
126 static GdkBitmap *queueopenhrmxpmmask;
127 static GdkPixmap *newxpm;
128 static GdkBitmap *newxpmmask;
129 static GdkPixmap *unreadxpm;
130 static GdkBitmap *unreadxpmmask;
131 static GdkPixmap *draftsxpm;
132 static GdkBitmap *draftsxpmmask;
133 static GdkPixmap *draftsopenxpm;
134 static GdkBitmap *draftsopenxpmmask;
135
136 static void folderview_select_node       (FolderView    *folderview,
137                                           GtkCTreeNode  *node);
138 static void folderview_set_folders       (FolderView    *folderview);
139 static void folderview_sort_folders      (FolderView    *folderview,
140                                           GtkCTreeNode  *root,
141                                           Folder        *folder);
142 static void folderview_append_folder     (FolderView    *folderview,
143                                           Folder        *folder);
144 static void folderview_update_node       (FolderView    *folderview,
145                                           GtkCTreeNode  *node);
146
147 static GtkCTreeNode *folderview_find_by_name    (GtkCTree       *ctree,
148                                                  GtkCTreeNode   *node,
149                                                  const gchar    *name);
150
151 static gint folderview_clist_compare    (GtkCList       *clist,
152                                          gconstpointer   ptr1,
153                                          gconstpointer   ptr2);
154 static gint folderview_compare_name     (gconstpointer   a,
155                                          gconstpointer   b);
156
157 /* callback functions */
158 static gboolean folderview_button_pressed       (GtkWidget      *ctree,
159                                                  GdkEventButton *event,
160                                                  FolderView     *folderview);
161 static gboolean folderview_button_released      (GtkWidget      *ctree,
162                                                  GdkEventButton *event,
163                                                  FolderView     *folderview);
164 static gboolean folderview_key_pressed  (GtkWidget      *widget,
165                                          GdkEventKey    *event,
166                                          FolderView     *folderview);
167 static void folderview_selected         (GtkCTree       *ctree,
168                                          GtkCTreeNode   *row,
169                                          gint            column,
170                                          FolderView     *folderview);
171 static void folderview_tree_expanded    (GtkCTree       *ctree,
172                                          GtkCTreeNode   *node,
173                                          FolderView     *folderview);
174 static void folderview_tree_collapsed   (GtkCTree       *ctree,
175                                          GtkCTreeNode   *node,
176                                          FolderView     *folderview);
177 static void folderview_popup_close      (GtkMenuShell   *menu_shell,
178                                          FolderView     *folderview);
179 static void folderview_col_resized      (GtkCList       *clist,
180                                          gint            column,
181                                          gint            width,
182                                          FolderView     *folderview);
183
184 static void folderview_update_tree_cb   (FolderView     *folderview,
185                                          guint           action,
186                                          GtkWidget      *widget);
187
188 static void mark_all_read_cb            (FolderView    *folderview,
189                                          guint           action,
190                                          GtkWidget      *widget);
191 static void folderview_new_folder_cb    (FolderView     *folderview,
192                                          guint           action,
193                                          GtkWidget      *widget);
194 static void folderview_new_mbox_folder_cb(FolderView *folderview,
195                                           guint action,
196                                           GtkWidget *widget);
197 static void folderview_rename_folder_cb (FolderView     *folderview,
198                                          guint           action,
199                                          GtkWidget      *widget);
200 static void folderview_rename_mbox_folder_cb(FolderView *folderview,
201                                              guint action,
202                                              GtkWidget *widget);
203 static void folderview_delete_folder_cb (FolderView     *folderview,
204                                          guint           action,
205                                          GtkWidget      *widget);
206 static void folderview_remove_mailbox_cb(FolderView     *folderview,
207                                          guint           action,
208                                          GtkWidget      *widget);
209
210 static void folderview_new_imap_folder_cb(FolderView    *folderview,
211                                           guint          action,
212                                           GtkWidget     *widget);
213 static void folderview_rm_imap_server_cb (FolderView    *folderview,
214                                           guint          action,
215                                           GtkWidget     *widget);
216
217 static void folderview_new_news_group_cb(FolderView     *folderview,
218                                          guint           action,
219                                          GtkWidget      *widget);
220 static void folderview_rm_news_group_cb (FolderView     *folderview,
221                                          guint           action,
222                                          GtkWidget      *widget);
223 static void folderview_rm_news_server_cb(FolderView     *folderview,
224                                          guint           action,
225                                          GtkWidget      *widget);
226
227 static void folderview_search_cb        (FolderView     *folderview,
228                                          guint           action,
229                                          GtkWidget      *widget);
230
231 static void folderview_property_cb      (FolderView     *folderview,
232                                          guint           action,
233                                          GtkWidget      *widget);
234
235 static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
236                                           GdkDragContext *context,
237                                           gint            x,
238                                           gint            y,
239                                           guint           time,
240                                           FolderView     *folderview);
241 static void folderview_drag_leave_cb     (GtkWidget        *widget,
242                                           GdkDragContext   *context,
243                                           guint             time,
244                                           FolderView       *folderview);
245 static void folderview_drag_received_cb  (GtkWidget        *widget,
246                                           GdkDragContext   *drag_context,
247                                           gint              x,
248                                           gint              y,
249                                           GtkSelectionData *data,
250                                           guint             info,
251                                           guint             time,
252                                           FolderView       *folderview);
253 static void folderview_start_drag        (GtkWidget *widget, gint button, GdkEvent *event,
254                                           FolderView       *folderview);
255 static void folderview_drag_data_get     (GtkWidget        *widget,
256                                           GdkDragContext   *drag_context,
257                                           GtkSelectionData *selection_data,
258                                           guint             info,
259                                           guint             time,
260                                           FolderView       *folderview);
261 static void folderview_drag_end_cb       (GtkWidget        *widget,
262                                           GdkDragContext   *drag_context,
263                                           FolderView       *folderview);
264
265 void folderview_create_folder_node       (FolderView       *folderview, 
266                                           FolderItem       *item);
267 gboolean folderview_update_folder        (gpointer          source,
268                                           gpointer          userdata);
269 gboolean folderview_update_item          (gpointer          source,
270                                           gpointer          data);
271
272 static void folderview_scoring_cb(FolderView *folderview, guint action,
273                                   GtkWidget *widget);
274 static void folderview_processing_cb(FolderView *folderview, guint action,
275                                      GtkWidget *widget);
276 static void folderview_move_to(FolderView *folderview, FolderItem *from_folder,
277                                FolderItem *to_folder);
278 static void folderview_move_to_cb(FolderView *folderview);
279
280 static GtkItemFactoryEntry folderview_mbox_popup_entries[] =
281 {
282         {N_("/Create _new folder..."),  NULL, folderview_new_mbox_folder_cb,    0, NULL},
283         {N_("/_Rename folder..."),      NULL, folderview_rename_mbox_folder_cb, 0, NULL},
284         {N_("/M_ove folder..."),        NULL, folderview_move_to_cb, 0, NULL},
285         {N_("/_Delete folder"),         NULL, folderview_delete_folder_cb, 0, NULL},
286         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
287         {N_("/Remove _mailbox"),        NULL, folderview_remove_mailbox_cb, 0, NULL},
288         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
289         {N_("/_Properties..."),         NULL, NULL, 0, NULL},
290         {N_("/_Processing..."),         NULL, folderview_processing_cb, 0, NULL},
291         {N_("/_Scoring..."),            NULL, folderview_scoring_cb, 0, NULL}
292 };
293
294 static GtkItemFactoryEntry folderview_mail_popup_entries[] =
295 {
296         {N_("/Mark all _read"),         NULL, mark_all_read_cb, 0, NULL},
297         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
298         {N_("/Create _new folder..."),  NULL, folderview_new_folder_cb,    0, NULL},
299         {N_("/_Rename folder..."),      NULL, folderview_rename_folder_cb, 0, NULL},
300         {N_("/M_ove folder..."),        NULL, folderview_move_to_cb, 0, NULL},
301         {N_("/_Delete folder"),         NULL, folderview_delete_folder_cb, 0, NULL},
302         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
303         {N_("/_Check for new messages"),
304                                         NULL, folderview_update_tree_cb, 0, NULL},
305         {N_("/R_ebuild folder tree"),   NULL, folderview_update_tree_cb, 1, NULL},
306         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
307         {N_("/Remove _mailbox"),        NULL, folderview_remove_mailbox_cb, 0, NULL},
308         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
309         {N_("/_Search folder..."),      NULL, folderview_search_cb, 0, NULL},
310         {N_("/_Properties..."),         NULL, folderview_property_cb, 0, NULL},
311         {N_("/_Processing..."),         NULL, folderview_processing_cb, 0, NULL},
312         {N_("/S_coring..."),            NULL, folderview_scoring_cb, 0, NULL}
313 };
314
315 static GtkItemFactoryEntry folderview_imap_popup_entries[] =
316 {
317         {N_("/Mark all _read"),         NULL, mark_all_read_cb, 0, NULL},
318         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
319         {N_("/Create _new folder..."),  NULL, folderview_new_imap_folder_cb, 0, NULL},
320         {N_("/_Rename folder..."),      NULL, folderview_rename_folder_cb,   0, NULL},
321         {N_("/M_ove folder..."),        NULL, folderview_move_to_cb, 0, NULL},
322         {N_("/_Delete folder"),         NULL, folderview_delete_folder_cb,   0, NULL},
323         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
324         {N_("/_Check for new messages"),
325                                         NULL, folderview_update_tree_cb, 0, NULL},
326         {N_("/R_ebuild folder tree"),   NULL, folderview_update_tree_cb, 1, NULL},
327         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
328         {N_("/Remove _IMAP4 account"),  NULL, folderview_rm_imap_server_cb, 0, NULL},
329         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
330         {N_("/_Search folder..."),      NULL, folderview_search_cb, 0, NULL},
331         {N_("/_Properties..."),         NULL, folderview_property_cb, 0, NULL},
332         {N_("/_Processing..."),         NULL, folderview_processing_cb, 0, NULL},
333         {N_("/S_coring..."),            NULL, folderview_scoring_cb, 0, NULL}
334 };
335
336 static GtkItemFactoryEntry folderview_news_popup_entries[] =
337 {
338         {N_("/Mark all _read"),         NULL, mark_all_read_cb, 0, NULL},
339         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
340         {N_("/_Subscribe to newsgroup..."),
341                                         NULL, folderview_new_news_group_cb, 0, NULL},
342         {N_("/_Remove newsgroup"),      NULL, folderview_rm_news_group_cb, 0, NULL},
343         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
344         {N_("/_Check for new messages"),
345                                         NULL, folderview_update_tree_cb, 0, NULL},
346         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
347         {N_("/Remove _news account"),   NULL, folderview_rm_news_server_cb, 0, NULL},
348         {N_("/---"),                    NULL, NULL, 0, "<Separator>"},
349         {N_("/_Search folder..."),      NULL, folderview_search_cb, 0, NULL},
350         {N_("/_Properties..."),         NULL, folderview_property_cb, 0, NULL},
351         {N_("/_Processing..."),         NULL, folderview_processing_cb, 0, NULL},
352         {N_("/S_coring..."),            NULL, folderview_scoring_cb, 0, NULL}
353 };
354
355 GtkTargetEntry folderview_drag_types[] =
356 {
357         {"text/plain", GTK_TARGET_SAME_APP, TARGET_DUMMY}
358 };
359
360 FolderView *folderview_create(void)
361 {
362         FolderView *folderview;
363         GtkWidget *scrolledwin;
364         GtkWidget *ctree;
365         gchar *titles[N_FOLDER_COLS];
366         GtkWidget *mail_popup;
367         GtkWidget *news_popup;
368         GtkWidget *imap_popup;
369         GtkWidget *mbox_popup;
370         GtkItemFactory *mail_factory;
371         GtkItemFactory *news_factory;
372         GtkItemFactory *imap_factory;
373         GtkItemFactory *mbox_factory;
374         gint n_entries;
375         gint i;
376
377         debug_print("Creating folder view...\n");
378         folderview = g_new0(FolderView, 1);
379
380         titles[COL_FOLDER] = _("Folder");
381         titles[COL_NEW]    = _("New");
382         titles[COL_UNREAD] = _("Unread");
383         titles[COL_TOTAL]  = _("#");
384
385         scrolledwin = gtk_scrolled_window_new(NULL, NULL);
386         gtk_scrolled_window_set_policy
387                 (GTK_SCROLLED_WINDOW(scrolledwin),
388                  GTK_POLICY_AUTOMATIC,
389                  prefs_common.folderview_vscrollbar_policy);
390         gtk_widget_set_size_request(scrolledwin,
391                              prefs_common.folderview_width,
392                              prefs_common.folderview_height);
393
394         ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, COL_FOLDER, titles);
395         
396         gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
397         gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
398 #ifndef CLAWS /* text instead of pixmaps */
399         gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_NEW,
400                                            GTK_JUSTIFY_RIGHT);
401         gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_UNREAD,
402                                            GTK_JUSTIFY_RIGHT);
403 #endif                                     
404         gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_TOTAL,
405                                            GTK_JUSTIFY_RIGHT);
406         gtk_clist_set_column_width(GTK_CLIST(ctree), COL_FOLDER,
407                                    prefs_common.folder_col_folder);
408         gtk_clist_set_column_width(GTK_CLIST(ctree), COL_NEW,
409                                    prefs_common.folder_col_new);
410         gtk_clist_set_column_width(GTK_CLIST(ctree), COL_UNREAD,        
411                                    prefs_common.folder_col_unread);
412         gtk_clist_set_column_width(GTK_CLIST(ctree), COL_TOTAL,
413                                    prefs_common.folder_col_total);
414         gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
415         gtk_ctree_set_expander_style(GTK_CTREE(ctree),
416                                      GTK_CTREE_EXPANDER_SQUARE);
417         gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
418         gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
419
420         /* don't let title buttons take key focus */
421         for (i = 0; i < N_FOLDER_COLS; i++)
422                 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
423                                        GTK_CAN_FOCUS);
424
425         /* popup menu */
426         n_entries = sizeof(folderview_mail_popup_entries) /
427                 sizeof(folderview_mail_popup_entries[0]);
428         mail_popup = menu_create_items(folderview_mail_popup_entries,
429                                        n_entries,
430                                        "<MailFolder>", &mail_factory,
431                                        folderview);
432         n_entries = sizeof(folderview_imap_popup_entries) /
433                 sizeof(folderview_imap_popup_entries[0]);
434         imap_popup = menu_create_items(folderview_imap_popup_entries,
435                                        n_entries,
436                                        "<IMAPFolder>", &imap_factory,
437                                        folderview);
438         n_entries = sizeof(folderview_news_popup_entries) /
439                 sizeof(folderview_news_popup_entries[0]);
440         news_popup = menu_create_items(folderview_news_popup_entries,
441                                        n_entries,
442                                        "<NewsFolder>", &news_factory,
443                                        folderview);
444         n_entries = sizeof(folderview_mbox_popup_entries) /
445                 sizeof(folderview_mbox_popup_entries[0]);
446         mbox_popup = menu_create_items(folderview_mbox_popup_entries,
447                                        n_entries,
448                                        "<MboxFolder>", &mbox_factory,
449                                        folderview);
450
451         g_signal_connect(G_OBJECT(ctree), "key_press_event",
452                          G_CALLBACK(folderview_key_pressed),
453                          folderview);
454         g_signal_connect(G_OBJECT(ctree), "button_press_event",
455                          G_CALLBACK(folderview_button_pressed),
456                          folderview);
457         g_signal_connect(G_OBJECT(ctree), "button_release_event",
458                          G_CALLBACK(folderview_button_released),
459                          folderview);
460         g_signal_connect(G_OBJECT(ctree), "tree_select_row",
461                          G_CALLBACK(folderview_selected), folderview);
462         g_signal_connect(G_OBJECT(ctree), "start_drag",
463                          G_CALLBACK(folderview_start_drag), folderview);
464         g_signal_connect(G_OBJECT(ctree), "drag_data_get",
465                          G_CALLBACK(folderview_drag_data_get),
466                          folderview);
467
468         g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
469                                G_CALLBACK(folderview_tree_expanded),
470                                folderview);
471         g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
472                                G_CALLBACK(folderview_tree_collapsed),
473                                folderview);
474
475         g_signal_connect(G_OBJECT(ctree), "resize_column",
476                          G_CALLBACK(folderview_col_resized),
477                          folderview);
478
479         g_signal_connect(G_OBJECT(mail_popup), "selection_done",
480                          G_CALLBACK(folderview_popup_close),
481                          folderview);
482         g_signal_connect(G_OBJECT(imap_popup), "selection_done",
483                          G_CALLBACK(folderview_popup_close),
484                          folderview);
485         g_signal_connect(G_OBJECT(news_popup), "selection_done",
486                          G_CALLBACK(folderview_popup_close),
487                          folderview);
488         g_signal_connect(G_OBJECT(mbox_popup), "selection_done",
489                          G_CALLBACK(folderview_popup_close),
490                          folderview);
491
492         /* drop callback */
493         gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
494                           summary_drag_types, 1,
495                           GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
496         g_signal_connect(G_OBJECT(ctree), "drag_motion",
497                          G_CALLBACK(folderview_drag_motion_cb),
498                          folderview);
499         g_signal_connect(G_OBJECT(ctree), "drag_leave",
500                          G_CALLBACK(folderview_drag_leave_cb),
501                          folderview);
502         g_signal_connect(G_OBJECT(ctree), "drag_data_received",
503                          G_CALLBACK(folderview_drag_received_cb),
504                          folderview);
505         g_signal_connect(G_OBJECT(ctree), "drag_end",
506                          G_CALLBACK(folderview_drag_end_cb),
507                          folderview);
508
509         folderview->scrolledwin  = scrolledwin;
510         folderview->ctree        = ctree;
511         folderview->mail_popup   = mail_popup;
512         folderview->mail_factory = mail_factory;
513         folderview->imap_popup   = imap_popup;
514         folderview->imap_factory = imap_factory;
515         folderview->news_popup   = news_popup;
516         folderview->news_factory = news_factory;
517         folderview->mbox_popup   = mbox_popup;
518         folderview->mbox_factory = mbox_factory;
519
520         folderview->folder_update_callback_id =
521                 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
522         folderview->folder_item_update_callback_id =
523                 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item, (gpointer) folderview);
524
525         gtk_widget_show_all(scrolledwin);
526
527         folderview->target_list = gtk_target_list_new(folderview_drag_types, 1);
528         folderview_list = g_list_append(folderview_list, folderview);
529
530         return folderview;
531 }
532
533 void folderview_init(FolderView *folderview)
534 {
535         GtkWidget *ctree = folderview->ctree;
536         GtkWidget *label_new;
537         GtkWidget *label_unread;
538         GtkWidget *hbox_new;
539         GtkWidget *hbox_unread;
540         
541         gtk_widget_realize(ctree);
542         stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
543         stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
544         stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
545         stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
546         stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
547         stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
548         stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
549         stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
550         stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
551         stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
552         stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
553         stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
554         stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
555         stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
556         stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
557         stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
558         stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
559         stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
560         stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
561         stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
562         stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
563         stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
564
565         /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
566          * instead text (text overflows making them unreadable and ugly) */
567         stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
568                          &newxpm, &newxpmmask);
569         stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
570                          &unreadxpm, &unreadxpmmask);
571                 
572         label_new = gtk_pixmap_new(newxpm, newxpmmask);
573         label_unread = gtk_pixmap_new(unreadxpm, unreadxpmmask);
574
575         hbox_new = gtk_hbox_new(FALSE, 4);
576         hbox_unread = gtk_hbox_new(FALSE, 4);
577
578         /* left justified */
579         gtk_box_pack_start(GTK_BOX(hbox_new),label_new,FALSE,FALSE,0);
580         gtk_box_pack_start(GTK_BOX(hbox_unread),label_unread,FALSE,FALSE,0);
581
582         gtk_widget_show_all(hbox_new);
583         gtk_widget_show_all(hbox_unread);
584
585         gtk_clist_set_column_widget(GTK_CLIST(ctree),COL_NEW,hbox_new);
586         gtk_clist_set_column_widget(GTK_CLIST(ctree),COL_UNREAD,hbox_unread);
587                         
588 #if 0
589         if (!normalfont) {
590                 if (gtkut_font_load(NORMAL_FONT) == NULL) {
591                         GtkStyle *style = gtk_style_new();
592                         normalfont = style->font;
593                         gdk_font_ref(normalfont);
594                         gtk_style_unref(style);
595                 } 
596                 else 
597                         normalfont = gtkut_font_load(NORMAL_FONT);
598         }
599         
600         if (!boldfont) {
601                 if (gtkut_font_load(BOLD_FONT) == NULL) {
602                         GtkStyle *style = gtk_style_new();
603                         boldfont = style->font;
604                         gdk_font_ref(boldfont);
605                         gtk_style_unref(style);
606                 }
607                 else
608                         boldfont = gtkut_font_load(BOLD_FONT);
609         }
610 #endif
611         
612         if (!bold_style) {
613                 PangoFontDescription *font_desc;
614                 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
615                 font_desc = pango_font_description_from_string(BOLD_FONT);
616                 if (font_desc) {
617                         if (bold_style->font_desc)
618                                 pango_font_description_free
619                                         (bold_style->font_desc);
620                         bold_style->font_desc = font_desc;
621                 }
622                 bold_color_style = gtk_style_copy(bold_style);
623                 bold_color_style->fg[GTK_STATE_NORMAL] = folderview->color_new;
624
625                 bold_tgtfold_style = gtk_style_copy(bold_style);
626                 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
627         }
628         if (!normal_style) {
629                 PangoFontDescription *font_desc;
630                 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
631                 font_desc = pango_font_description_from_string(NORMAL_FONT);
632                 if (font_desc) {
633                         if (normal_style->font_desc)
634                                 pango_font_description_free
635                                         (normal_style->font_desc);
636                         normal_style->font_desc = font_desc;
637                 }
638                 normal_color_style = gtk_style_copy(normal_style);
639                 normal_color_style->fg[GTK_STATE_NORMAL] = folderview->color_new;
640         }
641 }
642
643 void folderview_set(FolderView *folderview)
644 {
645         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
646         MainWindow *mainwin = folderview->mainwin;
647
648         debug_print("Setting folder info...\n");
649         STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
650
651         main_window_cursor_wait(mainwin);
652
653         folderview->selected = NULL;
654         folderview->opened = NULL;
655
656         gtk_clist_freeze(GTK_CLIST(ctree));
657         gtk_clist_clear(GTK_CLIST(ctree));
658         gtk_clist_thaw(GTK_CLIST(ctree));
659         gtk_clist_freeze(GTK_CLIST(ctree));
660
661         folderview_set_folders(folderview);
662
663         gtk_clist_thaw(GTK_CLIST(ctree));
664         main_window_cursor_normal(mainwin);
665         STATUSBAR_POP(mainwin);
666 }
667
668 void folderview_set_all(void)
669 {
670         GList *list;
671
672         for (list = folderview_list; list != NULL; list = list->next)
673                 folderview_set((FolderView *)list->data);
674 }
675
676 void folderview_select(FolderView *folderview, FolderItem *item)
677 {
678         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
679         GtkCTreeNode *node;
680         GtkCTreeNode *old_selected = folderview->selected;
681
682         if (!item) return;
683
684         node = gtk_ctree_find_by_row_data(ctree, NULL, item);
685         if (node) folderview_select_node(folderview, node);
686
687         if (old_selected != node)
688                 folder_update_op_count();
689 }
690
691 static void mark_all_read_cb(FolderView *folderview, guint action,
692                              GtkWidget *widget)
693 {
694         if (folderview->selected)
695                 summary_mark_all_read(folderview->summaryview);
696 }
697
698 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
699 {
700         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
701
702         g_return_if_fail(node != NULL);
703
704         folderview->open_folder = TRUE;
705         gtkut_ctree_set_focus_row(ctree, node);
706         gtk_ctree_select(ctree, node);
707         if (folderview->summaryview->folder_item &&
708             folderview->summaryview->folder_item->total_msgs > 0)
709                 gtk_widget_grab_focus(folderview->summaryview->ctree);
710         else
711                 gtk_widget_grab_focus(folderview->ctree);
712
713         gtkut_ctree_expand_parent_all(ctree, node);
714 }
715
716 void folderview_unselect(FolderView *folderview)
717 {
718         if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
719                 gtk_ctree_collapse
720                         (GTK_CTREE(folderview->ctree), folderview->opened);
721
722         folderview->selected = folderview->opened = NULL;
723 }
724
725 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
726                                                  GtkCTreeNode *node)
727 {
728         FolderItem *item;
729
730         if (node)
731                 node = gtkut_ctree_node_next(ctree, node);
732         else
733                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
734
735         for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
736                 item = gtk_ctree_node_get_row_data(ctree, node);
737                 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
738                         return node;
739         }
740
741         return NULL;
742 }
743
744 void folderview_select_next_unread(FolderView *folderview)
745 {
746         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
747         GtkCTreeNode *node = NULL;
748
749         if ((node = folderview_find_next_unread(ctree, folderview->opened))
750             != NULL) {
751                 folderview_select_node(folderview, node);
752                 return;
753         }
754
755         if (!folderview->opened ||
756             folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list))
757                 return;
758         /* search again from the first node */
759         if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
760                 folderview_select_node(folderview, node);
761 }
762
763 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
764 {
765         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
766         static GtkCTreeNode *prev_row = NULL;
767         FolderItem *item;
768         gint new, unread, total;
769         gchar *new_str, *unread_str, *total_str;
770
771         if (!row) return;
772
773         item = gtk_ctree_node_get_row_data(ctree, row);
774         if (!item) return;
775
776         gtk_ctree_node_get_text(ctree, row, COL_NEW, &new_str);
777         gtk_ctree_node_get_text(ctree, row, COL_UNREAD, &unread_str);
778         gtk_ctree_node_get_text(ctree, row, COL_TOTAL, &total_str);
779         new = atoi(new_str);
780         unread = atoi(unread_str);
781         total = atoi(total_str);
782
783         prev_row = row;
784
785         folderview_update_node(folderview, row);
786 }
787
788 static void folderview_set_folders(FolderView *folderview)
789 {
790         GList *list;
791
792         list = folder_get_list();
793
794         for (; list != NULL; list = list->next)
795                 folderview_append_folder(folderview, FOLDER(list->data));
796 }
797
798 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
799                                       gpointer data)
800 {
801         GList *list;
802
803         for (list = folderview_list; list != NULL; list = list->next) {
804                 FolderView *folderview = (FolderView *)list->data;
805                 MainWindow *mainwin = folderview->mainwin;
806                 gchar *str;
807
808                 if (item->path)
809                         str = g_strdup_printf(_("Scanning folder %s%c%s ..."),
810                                               item->folder->name, G_DIR_SEPARATOR,
811                                               item->path);
812                 else
813                         str = g_strdup_printf(_("Scanning folder %s ..."),
814                                               item->folder->name);
815
816                 STATUSBAR_PUSH(mainwin, str);
817                 STATUSBAR_POP(mainwin);
818                 g_free(str);
819         }
820 }
821
822 static GtkWidget *label_window_create(const gchar *str)
823 {
824         GtkWidget *window;
825         GtkWidget *label;
826
827         window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
828         gtk_widget_set_size_request(window, 380, 60);
829         gtk_container_set_border_width(GTK_CONTAINER(window), 8);
830         gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
831         gtk_window_set_title(GTK_WINDOW(window), str);
832         gtk_window_set_modal(GTK_WINDOW(window), TRUE);
833         gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
834         manage_window_set_transient(GTK_WINDOW(window));
835
836         label = gtk_label_new(str);
837         gtk_container_add(GTK_CONTAINER(window), label);
838         gtk_widget_show(label);
839
840         gtk_widget_show_now(window);
841
842         return window;
843 }
844
845 void folderview_rescan_tree(Folder *folder)
846 {
847         GtkWidget *window;
848
849         g_return_if_fail(folder != NULL);
850
851         if (!folder->klass->scan_tree) return;
852
853         inc_lock();
854         window = label_window_create(_("Rebuilding folder tree..."));
855
856         folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
857         folder_scan_tree(folder);
858         folder_set_ui_func(folder, NULL, NULL);
859
860         folderview_set_all();
861
862         gtk_widget_destroy(window);
863         inc_unlock();
864 }
865
866 /** folderview_check_new()
867  *  Scan and update the folder and return the 
868  *  count the number of new messages since last check. 
869  *  \param folder the folder to check for new messages
870  *  \return the number of new messages since last check
871  */
872 gint folderview_check_new(Folder *folder)
873 {
874         GList *list;
875         FolderItem *item;
876         FolderView *folderview;
877         GtkCTree *ctree;
878         GtkCTreeNode *node;
879         gint new_msgs = 0;
880         gint former_new_msgs = 0;
881         gint former_new = 0;
882
883         for (list = folderview_list; list != NULL; list = list->next) {
884                 folderview = (FolderView *)list->data;
885                 ctree = GTK_CTREE(folderview->ctree);
886
887                 inc_lock();
888                 main_window_lock(folderview->mainwin);
889                 gtk_widget_set_sensitive(folderview->ctree, FALSE);
890
891                 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
892                      node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
893                         item = gtk_ctree_node_get_row_data(ctree, node);
894                         if (!item || !item->path || !item->folder) continue;
895                         if (item->no_select) continue;
896                         if (folder && folder != item->folder) continue;
897                         if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
898
899                         folderview_scan_tree_func(item->folder, item, NULL);
900                         former_new = item->new_msgs;
901                         if (folder_item_scan(item) < 0) {
902                                 if (folder && !FOLDER_IS_LOCAL(folder))
903                                         break;
904                         }
905                         folderview_update_node(folderview, node);
906                         new_msgs += item->new_msgs;
907                         former_new_msgs += former_new;
908                 }
909
910                 gtk_widget_set_sensitive(folderview->ctree, TRUE);
911                 main_window_unlock(folderview->mainwin);
912                 inc_unlock();
913         }
914
915         folder_write_list();
916         /* Number of new messages since last check is the just the difference 
917          * between former_new_msgs and new_msgs. If new_msgs is less than
918          * former_new_msgs, that would mean another session accessed the folder
919          * and the result is not well defined.
920          */
921         new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
922         return new_msgs;
923 }
924
925 void folderview_check_new_all(void)
926 {
927         GList *list;
928         GtkWidget *window;
929         FolderView *folderview;
930
931         folderview = (FolderView *)folderview_list->data;
932
933         inc_lock();
934         main_window_lock(folderview->mainwin);
935         window = label_window_create
936                 (_("Checking for new messages in all folders..."));
937
938         list = folder_get_list();
939         for (; list != NULL; list = list->next) {
940                 Folder *folder = list->data;
941
942                 folderview_check_new(folder);
943         }
944
945         folder_write_list();
946         folderview_set_all();
947
948         gtk_widget_destroy(window);
949         main_window_unlock(folderview->mainwin);
950         inc_unlock();
951 }
952
953 static gboolean folderview_search_new_recursive(GtkCTree *ctree,
954                                                 GtkCTreeNode *node)
955 {
956         FolderItem *item;
957
958         if (node) {
959                 item = gtk_ctree_node_get_row_data(ctree, node);
960                 if (item) {
961                         if (item->new_msgs > 0 ||
962                             (item->stype == F_QUEUE && item->total_msgs > 0))
963                                 return TRUE;
964                 }
965                 node = GTK_CTREE_ROW(node)->children;
966         } else
967                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
968
969         while (node) {
970                 if (folderview_search_new_recursive(ctree, node) == TRUE)
971                         return TRUE;
972                 node = GTK_CTREE_ROW(node)->sibling;
973         }
974
975         return FALSE;
976 }
977
978 static gboolean folderview_have_new_children(FolderView *folderview,
979                                              GtkCTreeNode *node)
980 {
981         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
982
983         if (!node)
984                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
985         if (!node)
986                 return FALSE;
987
988         node = GTK_CTREE_ROW(node)->children;
989
990         while (node) {
991                 if (folderview_search_new_recursive(ctree, node) == TRUE)
992                         return TRUE;
993                 node = GTK_CTREE_ROW(node)->sibling;
994         }
995
996         return FALSE;
997 }
998
999 static gboolean folderview_search_unread_recursive(GtkCTree *ctree,
1000                                                    GtkCTreeNode *node)
1001 {
1002         FolderItem *item;
1003
1004         if (node) {
1005                 item = gtk_ctree_node_get_row_data(ctree, node);
1006                 if (item) {
1007                         if (item->unread_msgs > 0 ||
1008                             (item->stype == F_QUEUE && item->total_msgs > 0))
1009                                 return TRUE;
1010                 }
1011                 node = GTK_CTREE_ROW(node)->children;
1012         } else
1013                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1014
1015         while (node) {
1016                 if (folderview_search_unread_recursive(ctree, node) == TRUE)
1017                         return TRUE;
1018                 node = GTK_CTREE_ROW(node)->sibling;
1019         }
1020
1021         return FALSE;
1022 }
1023
1024 static gboolean folderview_have_unread_children(FolderView *folderview,
1025                                                 GtkCTreeNode *node)
1026 {
1027         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1028
1029         if (!node)
1030                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1031         if (!node)
1032                 return FALSE;
1033
1034         node = GTK_CTREE_ROW(node)->children;
1035
1036         while (node) {
1037                 if (folderview_search_unread_recursive(ctree, node) == TRUE)
1038                         return TRUE;
1039                 node = GTK_CTREE_ROW(node)->sibling;
1040         }
1041
1042         return FALSE;
1043 }
1044
1045 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1046 {
1047         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1048         GtkStyle *style = NULL;
1049         GtkStyle *color_style = NULL;
1050         FolderItem *item;
1051         GdkPixmap *xpm, *openxpm;
1052         GdkBitmap *mask, *openmask;
1053         gchar *name;
1054         gchar *str;
1055         gboolean add_unread_mark;
1056         gboolean use_bold, use_color;
1057
1058         item = gtk_ctree_node_get_row_data(ctree, node);
1059         g_return_if_fail(item != NULL);
1060
1061         switch (item->stype) {
1062         case F_INBOX:
1063                 if (item->hide_read_msgs) {
1064                         xpm = inboxhrmxpm;
1065                         mask = inboxhrmxpmmask;
1066                         openxpm = inboxopenhrmxpm;
1067                         openmask = inboxopenhrmxpmmask;
1068                 } else {
1069                         xpm = inboxxpm;
1070                         mask = inboxxpmmask;
1071                         openxpm = inboxopenxpm;
1072                         openmask = inboxopenxpmmask;
1073                 }
1074                 break;
1075         case F_OUTBOX:
1076                 if (item->hide_read_msgs) {
1077                         xpm = outboxhrmxpm;
1078                         mask = outboxhrmxpmmask;
1079                         openxpm = outboxopenhrmxpm;
1080                         openmask = outboxopenhrmxpmmask;
1081                 } else {
1082                         xpm = outboxxpm;
1083                         mask = outboxxpmmask;
1084                         openxpm = outboxopenxpm;
1085                         openmask = outboxopenxpmmask;
1086                 }
1087                 break;
1088         case F_QUEUE:
1089                 if (item->hide_read_msgs) {
1090                         xpm = queuehrmxpm;
1091                         mask = queuehrmxpmmask;
1092                         openxpm = queueopenhrmxpm;
1093                         openmask = queueopenhrmxpmmask;
1094                 } else {
1095                         xpm = queuexpm;
1096                         mask = queuexpmmask;
1097                         openxpm = queueopenxpm;
1098                         openmask = queueopenxpmmask;
1099                 }
1100                 break;
1101         case F_TRASH:
1102                 if (item->hide_read_msgs) {
1103                         xpm = trashhrmxpm;
1104                         mask = trashhrmxpmmask;
1105                         openxpm = trashopenhrmxpm;
1106                         openmask = trashopenhrmxpmmask;
1107                 } else {
1108                         xpm = trashxpm;
1109                         mask = trashxpmmask;
1110                         openxpm = trashopenxpm;
1111                         openmask = trashopenxpmmask;
1112                 }
1113                 break;
1114         case F_DRAFT:
1115                 xpm = draftsxpm;
1116                 mask = draftsxpmmask;
1117                 openxpm = draftsopenxpm;
1118                 openmask = draftsopenxpmmask;
1119                 break;
1120         default:
1121                 if (item->hide_read_msgs) {
1122                         xpm = folderhrmxpm;
1123                         mask = folderhrmxpmmask;
1124                         openxpm = folderopenhrmxpm;
1125                         openmask = folderopenhrmxpmmask;
1126                 } else {
1127                         xpm = folderxpm;
1128                         mask = folderxpmmask;
1129                         openxpm = folderopenxpm;
1130                         openmask = folderopenxpmmask;
1131                 }
1132         }
1133         name = folder_item_get_name(item);
1134
1135         if (!GTK_CTREE_ROW(node)->expanded &&
1136             folderview_have_unread_children(folderview, node))
1137                 add_unread_mark = TRUE;
1138         else
1139                 add_unread_mark = FALSE;
1140
1141         if (item->stype == F_QUEUE && item->total_msgs > 0 &&
1142             prefs_common.display_folder_unread) {
1143                 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1144                                       add_unread_mark ? "+" : "");
1145                 gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1146                                         xpm, mask, openxpm, openmask,
1147                                         FALSE, GTK_CTREE_ROW(node)->expanded);
1148                 g_free(str);
1149         } else if ((item->unread_msgs > 0 || add_unread_mark) &&
1150                  prefs_common.display_folder_unread) {
1151
1152                 if (item->unread_msgs > 0)
1153                         str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1154                                               add_unread_mark ? "+" : "", 
1155                                               item->unreadmarked_msgs > 0 ? "!":"");
1156                 else
1157                         str = g_strdup_printf("%s (+)", name);
1158                 gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1159                                         xpm, mask, openxpm, openmask,
1160                                         FALSE, GTK_CTREE_ROW(node)->expanded);
1161                 g_free(str);
1162         } else {
1163                 str = g_strdup_printf("%s%s", name, 
1164                                       item->unreadmarked_msgs > 0 ? " (!)":"");
1165         
1166                 gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1167                                         xpm, mask, openxpm, openmask,
1168                                         FALSE, GTK_CTREE_ROW(node)->expanded);
1169                 g_free(str);
1170         }
1171         g_free(name);
1172
1173         if (!item->parent) {
1174                 gtk_ctree_node_set_text(ctree, node, COL_NEW,    "-");
1175                 gtk_ctree_node_set_text(ctree, node, COL_UNREAD, "-");
1176                 gtk_ctree_node_set_text(ctree, node, COL_TOTAL,  "-");
1177         } else {
1178                 gtk_ctree_node_set_text(ctree, node, COL_NEW,    itos(item->new_msgs));
1179                 gtk_ctree_node_set_text(ctree, node, COL_UNREAD, itos(item->unread_msgs));
1180                 gtk_ctree_node_set_text(ctree, node, COL_TOTAL,  itos(item->total_msgs));
1181         }
1182
1183         if (item->stype == F_OUTBOX || item->stype == F_DRAFT ||
1184             item->stype == F_TRASH) {
1185                 use_bold = use_color = FALSE;
1186         } else if (item->stype == F_QUEUE) {
1187                 /* highlight queue folder if there are any messages */
1188                 use_bold = use_color = (item->total_msgs > 0);
1189         } else {
1190                 /* if unread messages exist, print with bold font */
1191                 use_bold = (item->unread_msgs > 0) || add_unread_mark;
1192                 /* if new messages exist, print with colored letter */
1193                 use_color =
1194                         (item->new_msgs > 0) ||
1195                         (add_unread_mark &&
1196                          folderview_have_new_children(folderview, node));       
1197         }
1198
1199         gtk_ctree_node_set_foreground(ctree, node, NULL);
1200
1201         if (use_bold) {
1202                 if (item->prefs->color > 0 && !use_color) {
1203                         GdkColor gdk_color;
1204
1205                         gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1206                         color_style = gtk_style_copy(bold_style);
1207                         color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1208                         style = color_style;
1209                 } else if (use_color)
1210                         style = bold_color_style;
1211                 else
1212                         style = bold_style;
1213                 if (item->op_count > 0) {
1214                         style = bold_tgtfold_style;
1215                 }
1216         } else if (use_color) {
1217                 style = normal_color_style;
1218                 gtk_ctree_node_set_foreground(ctree, node,
1219                                               &folderview->color_new);
1220         } else if (item->op_count > 0) {
1221                 style = bold_tgtfold_style;
1222         } else if (item->prefs->color > 0) {
1223                 GdkColor gdk_color;
1224
1225                 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1226                 color_style = gtk_style_copy(normal_style);
1227                 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1228                 style = color_style;
1229         } else {
1230                 style = normal_style;
1231         }
1232
1233         gtk_ctree_node_set_row_style(ctree, node, style);
1234
1235         if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1236                 folderview_update_node(folderview, node);
1237 }
1238
1239 gboolean folderview_update_item(gpointer source, gpointer data)
1240 {
1241         FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1242         FolderView *folderview = (FolderView *)data;
1243         GtkCTree *ctree;
1244         GtkCTreeNode *node;
1245
1246         g_return_val_if_fail(update_info != NULL, TRUE);
1247         g_return_val_if_fail(update_info->item != NULL, TRUE);
1248         g_return_val_if_fail(folderview != NULL, FALSE);
1249
1250         ctree = GTK_CTREE(folderview->ctree);
1251
1252         node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1253         if (node) {
1254                 if (update_info->update_flags & F_ITEM_UPDATE_MSGCNT)
1255                         folderview_update_node(folderview, node);
1256                 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1257                         summary_show(folderview->summaryview, update_info->item);
1258         }
1259         
1260         return FALSE;
1261 }
1262
1263 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1264                                       GNode *gnode, GtkCTreeNode *cnode,
1265                                       gpointer data)
1266 {
1267         FolderView *folderview = (FolderView *)data;
1268         FolderItem *item = FOLDER_ITEM(gnode->data);
1269
1270         g_return_val_if_fail(item != NULL, FALSE);
1271
1272         gtk_ctree_node_set_row_data(ctree, cnode, item);
1273         folderview_update_node(folderview, cnode);
1274
1275         return TRUE;
1276 }
1277
1278 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1279                                    gpointer data)
1280 {
1281         FolderView *folderview = (FolderView *)data;
1282         FolderItem *item;
1283
1284         if (GTK_CTREE_ROW(node)->children) {
1285                 item = gtk_ctree_node_get_row_data(ctree, node);
1286                 g_return_if_fail(item != NULL);
1287
1288                 if (!item->collapsed)
1289                         gtk_ctree_expand(ctree, node);
1290                 else
1291                         folderview_update_node(folderview, node);
1292         }
1293 }
1294
1295 #define SET_SPECIAL_FOLDER(ctree, item) \
1296 { \
1297         if (item) { \
1298                 GtkCTreeNode *node, *parent, *sibling; \
1299  \
1300                 node = gtk_ctree_find_by_row_data(ctree, root, item); \
1301                 if (!node) \
1302                         g_warning("%s not found.\n", item->path); \
1303                 else { \
1304                         parent = GTK_CTREE_ROW(node)->parent; \
1305                         if (prev && parent == GTK_CTREE_ROW(prev)->parent) \
1306                                 sibling = GTK_CTREE_ROW(prev)->sibling; \
1307                         else \
1308                                 sibling = GTK_CTREE_ROW(parent)->children; \
1309                         while (sibling) { \
1310                                 FolderItem *tmp; \
1311  \
1312                                 tmp = gtk_ctree_node_get_row_data \
1313                                         (ctree, sibling); \
1314                                 if (tmp->stype != F_NORMAL) \
1315                                         sibling = GTK_CTREE_ROW(sibling)->sibling; \
1316                                 else \
1317                                         break; \
1318                         } \
1319                         if (node != sibling) \
1320                                 gtk_ctree_move(ctree, node, parent, sibling); \
1321                 } \
1322  \
1323                 prev = node; \
1324         } \
1325 }
1326
1327 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1328                                     Folder *folder)
1329 {
1330         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1331         GtkCTreeNode *prev = NULL;
1332
1333         gtk_sctree_sort_recursive(ctree, root);
1334
1335         if (root && GTK_CTREE_ROW(root)->parent) return;
1336
1337         SET_SPECIAL_FOLDER(ctree, folder->inbox);
1338         SET_SPECIAL_FOLDER(ctree, folder->outbox);
1339         SET_SPECIAL_FOLDER(ctree, folder->draft);
1340         SET_SPECIAL_FOLDER(ctree, folder->queue);
1341         SET_SPECIAL_FOLDER(ctree, folder->trash);
1342 }
1343
1344 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1345 {
1346         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1347         GtkCTreeNode *root;
1348
1349         g_return_if_fail(folder != NULL);
1350
1351         root = gtk_ctree_insert_gnode(ctree, NULL, NULL, folder->node,
1352                                       folderview_gnode_func, folderview);
1353         gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1354                                 folderview);
1355         folderview_sort_folders(folderview, root, folder);
1356 }
1357
1358 void folderview_new_folder(FolderView *folderview)
1359 {
1360         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1361         FolderItem *item;
1362
1363         if (!folderview->selected) return;
1364
1365         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1366         g_return_if_fail(item != NULL);
1367         g_return_if_fail(item->folder != NULL);
1368
1369         switch (FOLDER_TYPE(item->folder)) {
1370         case F_MBOX:
1371                 folderview_new_mbox_folder_cb(folderview, 0, NULL);
1372                 break;
1373         case F_MH:
1374         case F_MAILDIR:
1375                 folderview_new_folder_cb(folderview, 0, NULL);
1376                 break;
1377         case F_IMAP:
1378                 folderview_new_imap_folder_cb(folderview, 0, NULL);
1379                 break;
1380         case F_NEWS:
1381         default:
1382                 break;
1383         }
1384 }
1385
1386 void folderview_rename_folder(FolderView *folderview)
1387 {
1388         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1389         FolderItem *item;
1390
1391         if (!folderview->selected) return;
1392
1393         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1394         g_return_if_fail(item != NULL);
1395         g_return_if_fail(item->folder != NULL);
1396         if (!item->path) return;
1397         if (item->stype != F_NORMAL) return;
1398
1399         switch (FOLDER_TYPE(item->folder)) {
1400         case F_MBOX:
1401                 folderview_rename_mbox_folder_cb(folderview, 0, NULL);
1402                 break;
1403         case F_MH:
1404         case F_MAILDIR:
1405         case F_IMAP:
1406                 folderview_rename_folder_cb(folderview, 0, NULL);
1407                 break;
1408         case F_NEWS:
1409         default:
1410                 break;
1411         }
1412 }
1413
1414 void folderview_delete_folder(FolderView *folderview)
1415 {
1416         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1417         FolderItem *item;
1418
1419         if (!folderview->selected) return;
1420
1421         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1422         g_return_if_fail(item != NULL);
1423         g_return_if_fail(item->folder != NULL);
1424         if (!item->path) return;
1425         if (item->stype != F_NORMAL) return;
1426
1427         switch (FOLDER_TYPE(item->folder)) {
1428         case F_MH:
1429         case F_MBOX:
1430         case F_MAILDIR:
1431         case F_IMAP:
1432                 folderview_delete_folder_cb(folderview, 0, NULL);
1433                 break;
1434         case F_NEWS:
1435         default:
1436                 break;
1437         }
1438 }
1439
1440
1441 /* callback functions */
1442
1443 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1444                                           FolderView *folderview)
1445 {
1446         GtkCList *clist = GTK_CLIST(ctree);
1447         gint prev_row = -1, row = -1, column = -1;
1448         FolderItem *item;
1449         Folder *folder;
1450         GtkWidget *popup;
1451         gboolean mark_all_read   = FALSE;
1452         gboolean new_folder      = FALSE;
1453         gboolean rename_folder   = FALSE;
1454         gboolean move_folder     = FALSE;
1455         gboolean delete_folder   = FALSE;
1456         gboolean update_tree     = FALSE;
1457         gboolean rescan_tree     = FALSE;
1458         gboolean remove_tree     = FALSE;
1459         gboolean search_folder   = FALSE;
1460         gboolean folder_property = FALSE;
1461         gboolean folder_processing  = FALSE;
1462         gboolean folder_scoring  = FALSE;
1463
1464         if (!event) return FALSE;
1465
1466         if (event->button == 1) {
1467                 folderview->open_folder = TRUE;
1468                 return FALSE;
1469         }
1470
1471         if (event->button == 2 || event->button == 3) {
1472                 /* right clicked */
1473                 if (clist->selection) {
1474                         GtkCTreeNode *node;
1475
1476                         node = GTK_CTREE_NODE(clist->selection->data);
1477                         if (node)
1478                                 prev_row = gtkut_ctree_get_nth_from_node
1479                                         (GTK_CTREE(ctree), node);
1480                 }
1481
1482                 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1483                                                   &row, &column))
1484                         return FALSE;
1485                 if (prev_row != row) {
1486                         gtk_clist_unselect_all(clist);
1487                         if (event->button == 2)
1488                                 folderview_select_node
1489                                         (folderview,
1490                                          gtk_ctree_node_nth(GTK_CTREE(ctree),
1491                                                             row));
1492                         else
1493                                 gtk_clist_select_row(clist, row, column);
1494                 }
1495         }
1496
1497         if (event->button != 3) return FALSE;
1498
1499         item = gtk_clist_get_row_data(clist, row);
1500         g_return_val_if_fail(item != NULL, FALSE);
1501         g_return_val_if_fail(item->folder != NULL, FALSE);
1502         folder = item->folder;
1503
1504         if (folderview->mainwin->lock_count == 0) {
1505                 new_folder = TRUE;
1506                 if (item->parent == NULL) {
1507                         update_tree = remove_tree = TRUE;
1508                         if (folder->account)
1509                                 folder_property = TRUE;
1510                 } else
1511                         mark_all_read = search_folder = folder_property = TRUE;
1512                         
1513                 if (FOLDER_IS_LOCAL(folder) || FOLDER_TYPE(folder) == F_IMAP || FOLDER_TYPE(folder) == F_MBOX) {
1514                         if (item->parent == NULL)
1515                                 update_tree = rescan_tree = TRUE;
1516                         else if (item->stype == F_NORMAL)
1517                                 move_folder = rename_folder = delete_folder = folder_scoring = folder_processing = TRUE;
1518                         else if (item->stype == F_INBOX)
1519                                 folder_scoring = folder_processing = TRUE;
1520                         else if (item->stype == F_TRASH)
1521                                 folder_processing = TRUE;
1522                         else if (item->stype == F_OUTBOX)
1523                                 folder_processing = TRUE;
1524                 } else if (FOLDER_TYPE(folder) == F_NEWS) {
1525                         if (item->parent != NULL)
1526                                 delete_folder = folder_scoring = folder_processing = TRUE;
1527                 }
1528                 if (item->unread_msgs < 1) 
1529                         mark_all_read = FALSE;
1530         }
1531
1532 #define SET_SENS(factory, name, sens) \
1533         menu_set_sensitive(folderview->factory, name, sens)
1534         
1535         mark_all_read = mark_all_read && 
1536                         (item == folderview->summaryview->folder_item);
1537
1538         if (FOLDER_IS_LOCAL(folder)) {
1539                 popup = folderview->mail_popup;
1540                 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1541                 SET_SENS(mail_factory, "/Mark all read", mark_all_read);
1542                 SET_SENS(mail_factory, "/Create new folder...", new_folder);
1543                 SET_SENS(mail_factory, "/Rename folder...", rename_folder);
1544                 SET_SENS(mail_factory, "/Move folder...", move_folder);
1545                 SET_SENS(mail_factory, "/Delete folder", delete_folder);
1546                 SET_SENS(mail_factory, "/Check for new messages", update_tree);
1547                 SET_SENS(mail_factory, "/Rebuild folder tree", rescan_tree);
1548                 SET_SENS(mail_factory, "/Remove mailbox", remove_tree);
1549                 SET_SENS(mail_factory, "/Search folder...", search_folder);
1550                 SET_SENS(mail_factory, "/Properties...", folder_property);
1551                 SET_SENS(mail_factory, "/Processing...", folder_processing);
1552                 SET_SENS(mail_factory, "/Scoring...", folder_scoring);
1553         } else if (FOLDER_TYPE(folder) == F_IMAP) {
1554                 popup = folderview->imap_popup;
1555                 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1556                 SET_SENS(imap_factory, "/Mark all read", mark_all_read);
1557                 SET_SENS(imap_factory, "/Create new folder...", new_folder);
1558                 SET_SENS(imap_factory, "/Rename folder...", rename_folder);
1559                 SET_SENS(imap_factory, "/Move folder...", move_folder);
1560                 SET_SENS(imap_factory, "/Delete folder", delete_folder);
1561                 SET_SENS(imap_factory, "/Check for new messages", update_tree);
1562                 SET_SENS(imap_factory, "/Rebuild folder tree", rescan_tree);
1563                 SET_SENS(imap_factory, "/Remove IMAP4 account", remove_tree);
1564                 SET_SENS(imap_factory, "/Search folder...", search_folder);
1565                 SET_SENS(imap_factory, "/Properties...", folder_property);
1566                 SET_SENS(imap_factory, "/Processing...", folder_processing);
1567                 SET_SENS(imap_factory, "/Scoring...", folder_scoring);
1568         } else if (FOLDER_TYPE(folder) == F_NEWS) {
1569                 popup = folderview->news_popup;
1570                 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1571                 SET_SENS(news_factory, "/Mark all read", mark_all_read);
1572                 SET_SENS(news_factory, "/Subscribe to newsgroup...", new_folder);
1573                 SET_SENS(news_factory, "/Remove newsgroup", delete_folder);
1574                 SET_SENS(news_factory, "/Check for new messages", update_tree);
1575                 SET_SENS(news_factory, "/Remove news account", remove_tree);
1576                 SET_SENS(news_factory, "/Search folder...", search_folder);
1577                 SET_SENS(news_factory, "/Properties...", folder_property);
1578                 SET_SENS(news_factory, "/Processing...", folder_processing);
1579                 SET_SENS(news_factory, "/Scoring...", folder_scoring);
1580         } else if (FOLDER_TYPE(folder) == F_MBOX) {
1581                 popup = folderview->mbox_popup;
1582                 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1583                 SET_SENS(mbox_factory, "/Create new folder...", new_folder);
1584                 SET_SENS(mbox_factory, "/Rename folder...", rename_folder);
1585                 SET_SENS(mbox_factory, "/Move folder...", move_folder);
1586                 SET_SENS(mbox_factory, "/Delete folder", delete_folder);
1587                 SET_SENS(news_factory, "/Properties...", folder_property);
1588                 SET_SENS(mbox_factory, "/Processing...", folder_processing);
1589                 SET_SENS(mbox_factory, "/Scoring...", folder_scoring);
1590         } else
1591                 return FALSE;
1592
1593 #undef SET_SENS
1594
1595         gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1596                        event->button, event->time);
1597
1598         return FALSE;
1599 }
1600
1601 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1602                                            FolderView *folderview)
1603 {
1604         if (!event) return FALSE;
1605
1606         if (event->button == 1 && folderview->open_folder == FALSE &&
1607             folderview->opened != NULL) {
1608                 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1609                                           folderview->opened);
1610                 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1611         }
1612
1613         return FALSE;
1614 }
1615
1616 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1617                                        FolderView *folderview)
1618 {
1619         if (!event) return FALSE;
1620
1621         switch (event->keyval) {
1622         case GDK_Return:
1623                 if (folderview->selected) {
1624                         folderview_select_node(folderview,
1625                                                folderview->selected);
1626                 }
1627                 break;
1628         case GDK_space:
1629                 if (folderview->selected) {
1630                         if (folderview->opened == folderview->selected &&
1631                             (!folderview->summaryview->folder_item ||
1632                              folderview->summaryview->folder_item->total_msgs == 0))
1633                                 folderview_select_next_unread(folderview);
1634                         else
1635                                 folderview_select_node(folderview,
1636                                                        folderview->selected);
1637                 }
1638                 break;
1639         default:
1640                 break;
1641         }
1642
1643         return FALSE;
1644 }
1645
1646 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
1647                                 gint column, FolderView *folderview)
1648 {
1649         static gboolean can_select = TRUE;      /* exclusive lock */
1650         gboolean opened;
1651         FolderItem *item;
1652         gchar *buf;
1653
1654         folderview->selected = row;
1655
1656         if (folderview->opened == row) {
1657                 folderview->open_folder = FALSE;
1658                 return;
1659         }
1660
1661         if (!can_select || summary_is_locked(folderview->summaryview)) {
1662                 gtkut_ctree_set_focus_row(ctree, folderview->opened);
1663                 gtk_ctree_select(ctree, folderview->opened);
1664                 return;
1665         }
1666
1667         if (!folderview->open_folder) return;
1668
1669         item = gtk_ctree_node_get_row_data(ctree, row);
1670         if (!item) return;
1671
1672         can_select = FALSE;
1673
1674         /* Save cache for old folder */
1675         /* We don't want to lose all caches if sylpheed crashed */
1676         if (folderview->opened) {
1677                 FolderItem *olditem;
1678                 
1679                 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
1680                 if (olditem) {
1681                         /* will be null if we just moved the previously opened folder */
1682                         summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
1683                         folder_item_close(olditem);
1684                 }
1685         }
1686
1687         /* CLAWS: set compose button type: news folder items 
1688          * always have a news folder as parent */
1689         if (item->folder) 
1690                 toolbar_set_compose_button
1691                         (folderview->mainwin->toolbar,
1692                          FOLDER_TYPE(item->folder) == F_NEWS ? 
1693                          COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
1694
1695         if (item->path)
1696                 debug_print("Folder %s is selected\n", item->path);
1697
1698         if (!GTK_CTREE_ROW(row)->children)
1699                 gtk_ctree_expand(ctree, row);
1700         if (folderview->opened &&
1701             !GTK_CTREE_ROW(folderview->opened)->children)
1702                 gtk_ctree_collapse(ctree, folderview->opened);
1703
1704         /* ungrab the mouse event */
1705         if (GTK_WIDGET_HAS_GRAB(ctree)) {
1706                 gtk_grab_remove(GTK_WIDGET(ctree));
1707                 if (gdk_pointer_is_grabbed())
1708                         gdk_pointer_ungrab(GDK_CURRENT_TIME);
1709         }
1710
1711         /* Open Folder */
1712         buf = g_strdup_printf(_("Opening Folder %s..."), item->path ? 
1713                                         item->path : "(null)");
1714         debug_print("%s\n", buf);
1715         STATUSBAR_PUSH(folderview->mainwin, buf);
1716         g_free(buf);
1717
1718         main_window_cursor_wait(folderview->mainwin);
1719
1720         if (folder_item_open(item) != 0) {
1721                 main_window_cursor_normal(folderview->mainwin);
1722                 STATUSBAR_POP(folderview->mainwin);
1723
1724                 alertpanel_error(_("Folder could not be opened."));
1725
1726                 return;
1727         }
1728
1729         main_window_cursor_normal(folderview->mainwin);
1730
1731         /* Show messages */
1732         summary_set_prefs_from_folderitem(folderview->summaryview, item);
1733         opened = summary_show(folderview->summaryview, item);
1734         
1735         folder_clean_cache_memory();
1736
1737         if (!opened) {
1738                 gtkut_ctree_set_focus_row(ctree, folderview->opened);
1739                 gtk_ctree_select(ctree, folderview->opened);
1740         } else {
1741                 folderview->opened = row;
1742                 if (gtk_ctree_node_is_visible(ctree, row)
1743                     != GTK_VISIBILITY_FULL)
1744                         gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
1745         }
1746
1747         STATUSBAR_POP(folderview->mainwin);
1748
1749         folderview->open_folder = FALSE;
1750         can_select = TRUE;
1751 }
1752
1753 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
1754                                      FolderView *folderview)
1755 {
1756         FolderItem *item;
1757
1758         item = gtk_ctree_node_get_row_data(ctree, node);
1759         g_return_if_fail(item != NULL);
1760         item->collapsed = FALSE;
1761         folderview_update_node(folderview, node);
1762 }
1763
1764 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
1765                                       FolderView *folderview)
1766 {
1767         FolderItem *item;
1768
1769         item = gtk_ctree_node_get_row_data(ctree, node);
1770         g_return_if_fail(item != NULL);
1771         item->collapsed= TRUE;
1772         folderview_update_node(folderview, node);
1773 }
1774
1775 static void folderview_popup_close(GtkMenuShell *menu_shell,
1776                                    FolderView *folderview)
1777 {
1778         if (!folderview->opened) return;
1779
1780         gtkut_ctree_set_focus_row(GTK_CTREE(folderview->ctree),
1781                                   folderview->opened);
1782         gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
1783 }
1784
1785 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
1786                                    FolderView *folderview)
1787 {
1788         switch (column) {
1789         case COL_FOLDER:
1790                 prefs_common.folder_col_folder = width;
1791                 break;
1792         case COL_NEW:
1793                 prefs_common.folder_col_new = width;
1794                 break;
1795         case COL_UNREAD:
1796                 prefs_common.folder_col_unread = width;
1797                 break;
1798         case COL_TOTAL:
1799                 prefs_common.folder_col_total = width;
1800                 break;
1801         default:
1802                 break;
1803         }
1804 }
1805
1806 static GtkCTreeNode *folderview_find_by_name(GtkCTree *ctree,
1807                                              GtkCTreeNode *node,
1808                                              const gchar *name)
1809 {
1810         FolderItem *item;
1811
1812         if (!node)
1813                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1814         if (!node)
1815                 return NULL;
1816
1817         node = GTK_CTREE_ROW(node)->children;
1818
1819         while (node) {
1820                 item = gtk_ctree_node_get_row_data(ctree, node);
1821                 if (!folderview_compare_name(item, name))
1822                         return node;
1823                 node = GTK_CTREE_ROW(node)->sibling;
1824         }
1825
1826         return NULL;
1827 }
1828
1829 static void folderview_update_tree_cb(FolderView *folderview, guint action,
1830                                       GtkWidget *widget)
1831 {
1832         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1833         FolderItem *item;
1834
1835         if (!folderview->selected) return;
1836
1837         summary_show(folderview->summaryview, NULL);
1838
1839         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1840         g_return_if_fail(item != NULL);
1841         g_return_if_fail(item->folder != NULL);
1842
1843         if (action == 0)
1844                 folderview_check_new(item->folder);
1845         else
1846                 folderview_rescan_tree(item->folder);
1847 }
1848
1849 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
1850 {
1851         GNode *srcnode;
1852
1853         folderview_create_folder_node(folderview, item);
1854         
1855         srcnode = item->folder->node;   
1856         srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1857         srcnode = srcnode->children;
1858         while (srcnode != NULL) {
1859                 if (srcnode && srcnode->data) {
1860                         FolderItem *next_item = (FolderItem*) srcnode->data;
1861                         folderview_create_folder_node_recursive(folderview, next_item);
1862                 }
1863                 srcnode = srcnode->next;
1864         }
1865 }
1866
1867 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
1868 {
1869         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1870         gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
1871         GtkCTreeNode *node, *parent_node;
1872         
1873         parent_node = gtk_ctree_find_by_row_data(ctree, NULL, item->parent);
1874         if (parent_node == NULL)
1875                 return;
1876
1877         gtk_clist_freeze(GTK_CLIST(ctree));
1878
1879         text[COL_FOLDER] = item->name;
1880         node = gtk_ctree_insert_node(ctree, parent_node, NULL, text,
1881                                      FOLDER_SPACING,
1882                                      folderxpm, folderxpmmask,
1883                                      folderopenxpm, folderopenxpmmask,
1884                                      FALSE, FALSE);
1885         gtk_ctree_expand(ctree, parent_node);
1886         gtk_ctree_node_set_row_data(ctree, node, item);
1887         if (normal_style)
1888                 gtk_ctree_node_set_row_style(ctree, node, normal_style);
1889         folderview_sort_folders(folderview, folderview->selected, item->folder);
1890
1891         gtk_clist_thaw(GTK_CLIST(ctree));
1892 }
1893
1894 static void folderview_new_folder_cb(FolderView *folderview, guint action,
1895                                      GtkWidget *widget)
1896 {
1897         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1898         FolderItem *item;
1899         FolderItem *new_item;
1900         gchar *new_folder;
1901         gchar *name, *name_;
1902
1903         if (!folderview->selected) return;
1904
1905         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1906         g_return_if_fail(item != NULL);
1907         g_return_if_fail(item->folder != NULL);
1908
1909         new_folder = input_dialog(_("New folder"),
1910                                   _("Input the name of new folder:"),
1911                                   _("NewFolder"));
1912         if (!new_folder) return;
1913
1914         if (FOLDER_TYPE(item->folder) != F_MBOX) {
1915                 if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
1916                         alertpanel_error(_("`%c' can't be included in folder name."),
1917                                          G_DIR_SEPARATOR);
1918                         g_free(new_folder);
1919                         return;
1920                 }
1921         }
1922
1923         name_ = trim_string(new_folder, 32);
1924         Xstrdup_a(name, name_, {g_free(new_folder); return;});
1925         g_free(name_);
1926
1927         /* find whether the directory already exists */
1928         if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
1929                 alertpanel_error(_("The folder `%s' already exists."), name);
1930                 g_free(new_folder);
1931                 return;
1932         }
1933
1934         new_item = folder_create_folder(item, new_folder);
1935         if (!new_item) {
1936                 alertpanel_error(_("Can't create the folder `%s'."), name);
1937                 g_free(new_folder);
1938                 return;
1939         } 
1940         g_free(new_folder);
1941
1942         folder_write_list();
1943 }
1944
1945 static void folderview_new_mbox_folder_cb(FolderView *folderview, guint action,
1946                                           GtkWidget *widget)
1947 {
1948         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1949         FolderItem *item;
1950         FolderItem *new_item;
1951         gchar *new_folder;
1952
1953         if (!folderview->selected) return;
1954
1955         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1956         g_return_if_fail(item != NULL);
1957         g_return_if_fail(item->folder != NULL);
1958
1959         new_folder = input_dialog(_("New folder"),
1960                                   _("Input the name of new folder:"),
1961                                   _("NewFolder"));
1962         if (!new_folder) return;
1963
1964         /* find whether the directory already exists */
1965         if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
1966                 alertpanel_error(_("The folder `%s' already exists."),
1967                                  new_folder);
1968                 g_free(new_folder);
1969                 return;
1970         }
1971
1972         new_item = folder_create_folder(item, new_folder);
1973         g_free(new_folder);
1974         if (!new_item) return;
1975
1976         folder_write_list();
1977 }
1978
1979 static void folderview_rename_folder_cb(FolderView *folderview, guint action,
1980                                         GtkWidget *widget)
1981 {
1982         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1983         FolderItem *item;
1984         gchar *new_folder;
1985         gchar *name, *name_;
1986         gchar *message;
1987         gchar *old_path;
1988         gchar *old_id;
1989         gchar *new_id;
1990
1991         if (!folderview->selected) return;
1992
1993         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1994         g_return_if_fail(item != NULL);
1995         g_return_if_fail(item->path != NULL);
1996         g_return_if_fail(item->folder != NULL);
1997
1998         name_ = trim_string(item->name, 32);
1999         Xstrdup_a(name, name_, return);
2000         g_free(name_);
2001         message = g_strdup_printf(_("Input new name for `%s':"), name);
2002         new_folder = input_dialog(_("Rename folder"), message,
2003                                   g_basename(item->path));
2004         g_free(message);
2005         if (!new_folder) return;
2006
2007         if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
2008                 alertpanel_error(_("`%c' can't be included in folder name."),
2009                                  G_DIR_SEPARATOR);
2010                 g_free(new_folder);
2011                 return;
2012         }
2013
2014         if (folderview_find_by_name
2015                 (ctree, GTK_CTREE_ROW(folderview->selected)->parent,
2016                  new_folder)) {
2017                 name = trim_string(new_folder, 32);
2018                 alertpanel_error(_("The folder `%s' already exists."), name);
2019                 g_free(name);
2020                 g_free(new_folder);
2021                 return;
2022         }
2023
2024         Xstrdup_a(old_path, item->path, {g_free(new_folder); return;});
2025         old_id = folder_item_get_identifier(item);
2026
2027         if (item->folder->klass->rename_folder(item->folder, item, new_folder) < 0) {
2028                 g_free(old_id);
2029                 g_free(new_folder);
2030                 return;
2031         }
2032         g_free(new_folder);
2033
2034         /* if (FOLDER_TYPE(item->folder) == F_MH)
2035                 prefs_filtering_rename_path(old_path, item->path); */
2036         new_id = folder_item_get_identifier(item);
2037         prefs_filtering_rename_path(old_id, new_id);
2038
2039         g_free(old_id);
2040         g_free(new_id);
2041
2042         gtk_clist_freeze(GTK_CLIST(ctree));
2043
2044         folderview_update_node(folderview, folderview->selected);
2045         folderview_sort_folders(folderview,
2046                                 GTK_CTREE_ROW(folderview->selected)->parent,
2047                                 item->folder);
2048         if (folderview->opened == folderview->selected ||
2049             gtk_ctree_is_ancestor(ctree,
2050                                   folderview->selected,
2051                                   folderview->opened)) {
2052                 GtkCTreeNode *node = folderview->opened;
2053                 folderview_unselect(folderview);
2054                 folderview_select_node(folderview, node);
2055         }
2056
2057         gtk_clist_thaw(GTK_CLIST(ctree));
2058
2059         folder_write_list();
2060 }
2061
2062 static void folderview_rename_mbox_folder_cb(FolderView *folderview,
2063                                              guint action,
2064                                              GtkWidget *widget)
2065 {
2066         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2067         FolderItem *item;
2068         gchar *new_folder;
2069         gchar *message;
2070
2071         if (!folderview->selected) return;
2072
2073         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2074         g_return_if_fail(item != NULL);
2075         g_return_if_fail(item->path != NULL);
2076         g_return_if_fail(item->folder != NULL);
2077
2078         message = g_strdup_printf(_("Input new name for `%s':"),
2079                                   g_basename(item->path));
2080         new_folder = input_dialog(_("Rename folder"), message,
2081                                   g_basename(item->path));
2082         g_free(message);
2083         if (!new_folder) return;
2084
2085         if (folderview_find_by_name
2086                 (ctree, GTK_CTREE_ROW(folderview->selected)->parent,
2087                  new_folder)) {
2088                 alertpanel_error(_("The folder `%s' already exists."),
2089                                  new_folder);
2090                 g_free(new_folder);
2091                 return;
2092         }
2093
2094         if (item->folder->klass->rename_folder(item->folder, item, new_folder) < 0) {
2095                 g_free(new_folder);
2096                 return;
2097         }
2098         g_free(new_folder);
2099
2100         gtk_clist_freeze(GTK_CLIST(ctree));
2101
2102         folderview_update_node(folderview, folderview->selected);
2103         folderview_sort_folders(folderview,
2104                                 GTK_CTREE_ROW(folderview->selected)->parent,
2105                                 item->folder);
2106         if (folderview->opened == folderview->selected) {
2107                 if (!GTK_CTREE_ROW(folderview->opened)->children)
2108                         gtk_ctree_expand(ctree, folderview->opened);
2109                 summary_show(folderview->summaryview, item);
2110         }
2111
2112         gtk_clist_thaw(GTK_CLIST(ctree));
2113
2114         folder_write_list();
2115 }
2116
2117 static void folderview_delete_folder_cb(FolderView *folderview, guint action,
2118                                         GtkWidget *widget)
2119 {
2120         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2121         FolderItem *item;
2122         gchar *message, *name, *name_;
2123         AlertValue avalue;
2124         gchar *old_path;
2125         gchar *old_id;
2126
2127         if (!folderview->selected) return;
2128
2129         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2130         g_return_if_fail(item != NULL);
2131         g_return_if_fail(item->path != NULL);
2132         g_return_if_fail(item->folder != NULL);
2133
2134         name_ = trim_string(item->name, 32);
2135         Xstrdup_a(name, name_, return);
2136         g_free(name_);
2137         message = g_strdup_printf
2138                 (_("All folder(s) and message(s) under `%s' will be deleted.\n"
2139                    "Do you really want to delete?"), name);
2140         avalue = alertpanel(_("Delete folder"), message,
2141                             _("Yes"), _("+No"), NULL);
2142         g_free(message);
2143         if (avalue != G_ALERTDEFAULT) return;
2144
2145         Xstrdup_a(old_path, item->path, return);
2146         old_id = folder_item_get_identifier(item);
2147
2148         if (folderview->opened == folderview->selected ||
2149             gtk_ctree_is_ancestor(ctree,
2150                                   folderview->selected,
2151                                   folderview->opened)) {
2152                 summary_clear_all(folderview->summaryview);
2153                 folderview->opened = NULL;
2154         }
2155
2156         if (item->folder->klass->remove_folder(item->folder, item) < 0) {
2157                 alertpanel_error(_("Can't remove the folder `%s'."), name);
2158                 if (folderview->opened == folderview->selected)
2159                         summary_show(folderview->summaryview,
2160                                      folderview->summaryview->folder_item);
2161                 g_free(old_id);
2162                 return;
2163         }
2164
2165         folder_write_list();
2166
2167         prefs_filtering_delete_path(old_id);
2168         g_free(old_id);
2169
2170 }
2171
2172 static void folderview_remove_mailbox_cb(FolderView *folderview, guint action,
2173                                          GtkWidget *widget)
2174 {
2175         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2176         GtkCTreeNode *node;
2177         FolderItem *item;
2178         gchar *name, *name_;
2179         gchar *message;
2180         AlertValue avalue;
2181
2182         if (!folderview->selected) return;
2183         node = folderview->selected;
2184         item = gtk_ctree_node_get_row_data(ctree, node);
2185         g_return_if_fail(item != NULL);
2186         g_return_if_fail(item->folder != NULL);
2187         if (item->parent) return;
2188
2189         name_ = trim_string(item->folder->name, 32);
2190         Xstrdup_a(name, name_, return);
2191         g_free(name_);
2192         message = g_strdup_printf
2193                 (_("Really remove the mailbox `%s' ?\n"
2194                    "(The messages are NOT deleted from the disk)"), name);
2195         avalue = alertpanel(_("Remove mailbox"), message,
2196                             _("Yes"), _("+No"), NULL);
2197         g_free(message);
2198         if (avalue != G_ALERTDEFAULT) return;
2199
2200         folderview_unselect(folderview);
2201         summary_clear_all(folderview->summaryview);
2202         gtk_ctree_remove_node(ctree, node);
2203
2204         folder_destroy(item->folder);
2205         folder_write_list();
2206 }
2207
2208 static void folderview_new_imap_folder_cb(FolderView *folderview, guint action,
2209                                           GtkWidget *widget)
2210 {
2211         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2212         FolderItem *item;
2213         FolderItem *new_item;
2214         gchar *new_folder;
2215         gchar *name, *name_;
2216         gchar *p;
2217
2218         if (!folderview->selected) return;
2219
2220         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2221         g_return_if_fail(item != NULL);
2222         g_return_if_fail(item->folder != NULL);
2223         g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP);
2224         g_return_if_fail(item->folder->account != NULL);
2225
2226         new_folder = input_dialog
2227                 (_("New folder"),
2228                  _("Input the name of new folder:\n"
2229                    "(if you want to create a folder to store subfolders,\n"
2230                    " append `/' at the end of the name)"),
2231                  _("NewFolder"));
2232         if (!new_folder) return;
2233
2234         if ((p = strchr(new_folder, G_DIR_SEPARATOR)) != NULL &&
2235             *(p + 1) != '\0') {
2236                 alertpanel_error(_("`%c' can't be included in folder name."),
2237                                  G_DIR_SEPARATOR);
2238                 g_free(new_folder);
2239                 return;
2240         }
2241
2242         name_ = trim_string(new_folder, 32);
2243         Xstrdup_a(name, name_, return);
2244         g_free(name_);
2245
2246         /* find whether the directory already exists */
2247         if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
2248                 alertpanel_error(_("The folder `%s' already exists."), name);
2249                 g_free(new_folder);
2250                 return;
2251         }
2252
2253         new_item = folder_create_folder(item, new_folder);
2254         if (!new_item) {
2255                 alertpanel_error(_("Can't create the folder `%s'."), name);
2256                 g_free(new_folder);
2257                 return;
2258         }
2259         g_free(new_folder);
2260
2261         folder_write_list();
2262 }
2263
2264 static void folderview_rm_imap_server_cb(FolderView *folderview, guint action,
2265                                          GtkWidget *widget)
2266 {
2267         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2268         FolderItem *item;
2269         PrefsAccount *account;
2270         gchar *name, *name_;
2271         gchar *message;
2272         AlertValue avalue;
2273
2274         if (!folderview->selected) return;
2275
2276         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2277         g_return_if_fail(item != NULL);
2278         g_return_if_fail(item->folder != NULL);
2279         g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP);
2280         g_return_if_fail(item->folder->account != NULL);
2281
2282         name_ = trim_string(item->folder->name, 32);
2283         Xstrdup_a(name, name_, return);
2284         g_free(name_);
2285         message = g_strdup_printf(_("Really delete IMAP4 account `%s'?"), name);
2286         avalue = alertpanel(_("Delete IMAP4 account"), message,
2287                             _("Yes"), _("+No"), NULL);
2288         g_free(message);
2289
2290         if (avalue != G_ALERTDEFAULT) return;
2291
2292         if (folderview->opened == folderview->selected ||
2293             gtk_ctree_is_ancestor(ctree,
2294                                   folderview->selected,
2295                                   folderview->opened)) {
2296                 summary_clear_all(folderview->summaryview);
2297                 folderview->opened = NULL;
2298         }
2299
2300         account = item->folder->account;
2301         folder_destroy(item->folder);
2302         account_destroy(account);
2303         gtk_ctree_remove_node(ctree, folderview->selected);
2304         account_set_menu();
2305         main_window_reflect_prefs_all();
2306         folder_write_list();
2307 }
2308
2309 static void folderview_new_news_group_cb(FolderView *folderview, guint action,
2310                                          GtkWidget *widget)
2311 {
2312         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2313         gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2314         GtkCTreeNode *servernode, *node;
2315         Folder *folder;
2316         FolderItem *item;
2317         FolderItem *rootitem;
2318         FolderItem *newitem;
2319         GSList *new_subscr;
2320         GSList *cur;
2321         GNode *gnode;
2322
2323         if (!folderview->selected) return;
2324
2325         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2326         g_return_if_fail(item != NULL);
2327         folder = item->folder;
2328         g_return_if_fail(folder != NULL);
2329         g_return_if_fail(FOLDER_TYPE(folder) == F_NEWS);
2330         g_return_if_fail(folder->account != NULL);
2331
2332         if (GTK_CTREE_ROW(folderview->selected)->parent != NULL)
2333                 servernode = GTK_CTREE_ROW(folderview->selected)->parent;
2334         else
2335                 servernode = folderview->selected;
2336
2337         rootitem = gtk_ctree_node_get_row_data(ctree, servernode);
2338
2339         new_subscr = grouplist_dialog(folder);
2340
2341         /* remove unsubscribed newsgroups */
2342         for (gnode = folder->node->children; gnode != NULL; ) {
2343                 GNode *next = gnode->next;
2344
2345                 item = FOLDER_ITEM(gnode->data);
2346                 if (g_slist_find_custom(new_subscr, item->path,
2347                                         (GCompareFunc)g_strcasecmp) != NULL) {
2348                         gnode = next;
2349                         continue;
2350                 }
2351
2352                 node = gtk_ctree_find_by_row_data(ctree, servernode, item);
2353                 if (!node) {
2354                         gnode = next;
2355                         continue;
2356                 }
2357
2358                 if (folderview->opened == node) {
2359                         summary_clear_all(folderview->summaryview);
2360                         folderview->opened = NULL;
2361                 }
2362
2363                 folder_item_remove(item);
2364                 gtk_ctree_remove_node(ctree, node);
2365
2366                 gnode = next;
2367         }
2368
2369         gtk_clist_freeze(GTK_CLIST(ctree));
2370
2371         /* add subscribed newsgroups */
2372         for (cur = new_subscr; cur != NULL; cur = cur->next) {
2373                 gchar *name = (gchar *)cur->data;
2374
2375                 if (folderview_find_by_name(ctree, servernode, name) != NULL)
2376                         continue;
2377
2378                 text[COL_FOLDER] = name;
2379                 node = gtk_ctree_insert_node(ctree, servernode, NULL, text,
2380                                              FOLDER_SPACING,
2381                                              folderxpm, folderxpmmask,
2382                                              folderopenxpm, folderopenxpmmask,
2383                                              FALSE, FALSE);
2384                 gtk_ctree_expand(ctree, servernode);
2385
2386                 newitem = folder_item_new(folder, name, name);
2387                 folder_item_append(rootitem, newitem);
2388                 gtk_ctree_node_set_row_data(ctree, node, newitem);
2389         }
2390
2391         folderview_sort_folders(folderview, servernode, folder);
2392         gtk_clist_thaw(GTK_CLIST(ctree));
2393
2394         slist_free_strings(new_subscr);
2395         g_slist_free(new_subscr);
2396
2397         folder_write_list();
2398 }
2399
2400 static void folderview_rm_news_group_cb(FolderView *folderview, guint action,
2401                                         GtkWidget *widget)
2402 {
2403         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2404         FolderItem *item;
2405         gchar *name, *name_;
2406         gchar *message;
2407         AlertValue avalue;
2408
2409         if (!folderview->selected) return;
2410
2411         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2412         g_return_if_fail(item != NULL);
2413         g_return_if_fail(item->folder != NULL);
2414         g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS);
2415         g_return_if_fail(item->folder->account != NULL);
2416
2417         name_ = trim_string(item->path, 32);
2418         Xstrdup_a(name, name_, return);
2419         g_free(name_);
2420         message = g_strdup_printf(_("Really delete newsgroup `%s'?"), name);
2421         avalue = alertpanel(_("Delete newsgroup"), message,
2422                             _("Yes"), _("+No"), NULL);
2423         g_free(message);
2424         if (avalue != G_ALERTDEFAULT) return;
2425
2426         if (folderview->opened == folderview->selected) {
2427                 summary_clear_all(folderview->summaryview);
2428                 folderview->opened = NULL;
2429         }
2430
2431         folder_item_remove(item);
2432         gtk_ctree_remove_node(ctree, folderview->selected);
2433         folder_write_list();
2434         
2435         prefs_filtering_delete_path(name);
2436 }
2437
2438 static void folderview_rm_news_server_cb(FolderView *folderview, guint action,
2439                                          GtkWidget *widget)
2440 {
2441         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2442         FolderItem *item;
2443         PrefsAccount *account;
2444         gchar *name, *name_;
2445         gchar *message;
2446         AlertValue avalue;
2447
2448         if (!folderview->selected) return;
2449
2450         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2451         g_return_if_fail(item != NULL);
2452         g_return_if_fail(item->folder != NULL);
2453         g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS);
2454         g_return_if_fail(item->folder->account != NULL);
2455
2456         name_ = trim_string(item->folder->name, 32);
2457         Xstrdup_a(name, name_, return);
2458         g_free(name_);
2459         message = g_strdup_printf(_("Really delete news account `%s'?"), name);
2460         avalue = alertpanel(_("Delete news account"), message,
2461                             _("Yes"), _("+No"), NULL);
2462         g_free(message);
2463
2464         if (avalue != G_ALERTDEFAULT) return;
2465
2466         if (folderview->opened == folderview->selected ||
2467             gtk_ctree_is_ancestor(ctree,
2468                                   folderview->selected,
2469                                   folderview->opened)) {
2470                 summary_clear_all(folderview->summaryview);
2471                 folderview->opened = NULL;
2472         }
2473
2474         account = item->folder->account;
2475         folder_destroy(item->folder);
2476         account_destroy(account);
2477         gtk_ctree_remove_node(ctree, folderview->selected);
2478         account_set_menu();
2479         main_window_reflect_prefs_all();
2480         folder_write_list();
2481 }
2482
2483 static void folderview_search_cb(FolderView *folderview, guint action,
2484                                  GtkWidget *widget)
2485 {
2486         summary_search(folderview->summaryview);
2487 }
2488
2489 static void folderview_property_cb(FolderView *folderview, guint action,
2490                                    GtkWidget *widget)
2491 {
2492         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2493         FolderItem *item;
2494
2495         if (!folderview->selected) return;
2496
2497         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2498         g_return_if_fail(item != NULL);
2499         g_return_if_fail(item->folder != NULL);
2500
2501         if (item->parent == NULL && item->folder->account)
2502                 account_open(item->folder->account);
2503         else {
2504                 prefs_folder_item_open(item);
2505         }
2506 }
2507
2508 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2509 {
2510         GSList *list = NULL;
2511         GSList *done = NULL;
2512         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2513         
2514         for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2515                 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2516                 &&  list->data != node) {
2517                         gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2518                         done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2519                 }
2520         }
2521         for (list = done; list != NULL; list = g_slist_next(list)) {
2522                 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse, 
2523                                                                  list->data);
2524         }
2525         g_slist_free(done);
2526 }
2527
2528 static void folderview_recollapse_all_nodes(FolderView *folderview)
2529 {
2530         GSList *list = folderview->nodes_to_recollapse;
2531         if (!list) return;
2532         for (; list != NULL; list = g_slist_next(list))
2533                 if (list->data) 
2534                         gtk_ctree_collapse(GTK_CTREE(folderview->ctree), 
2535                                            GTK_CTREE_NODE(list->data));
2536         g_slist_free(folderview->nodes_to_recollapse);  
2537         folderview->nodes_to_recollapse = NULL;
2538 }
2539
2540 static void folderview_move_to_cb(FolderView *folderview) 
2541 {
2542         FolderItem *from_folder = NULL, *to_folder = NULL;
2543
2544         if (folderview->selected)
2545                 from_folder = gtk_ctree_node_get_row_data(GTK_CTREE(folderview->ctree), folderview->selected);
2546         if (!from_folder || FOLDER_TYPE(from_folder->folder) == F_NEWS)
2547                 return;
2548
2549         to_folder = foldersel_folder_sel(from_folder->folder, FOLDER_SEL_MOVE, NULL);
2550         
2551         if (!to_folder || FOLDER_TYPE(to_folder->folder) == F_NEWS)
2552                 return;
2553
2554         folderview_move_to(folderview, from_folder, to_folder);
2555 }
2556
2557 static void folderview_move_to(FolderView *folderview, FolderItem *from_folder,
2558                                FolderItem *to_folder)
2559 {
2560         FolderItem *from_parent = NULL;
2561         FolderItem *new_folder = NULL;
2562         GtkCTreeNode *src_node = NULL;
2563         gchar *buf;
2564         gint status;
2565
2566         src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2567         from_parent = from_folder->parent;
2568         buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
2569         STATUSBAR_PUSH(folderview->mainwin, buf);
2570         g_free(buf);
2571         summary_clear_all(folderview->summaryview);
2572         folderview->opened = NULL;
2573         folderview->selected = NULL;
2574         gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2575         inc_lock();
2576         main_window_cursor_wait(folderview->mainwin);
2577         statusbar_verbosity_set(TRUE);
2578         folder_item_update_freeze();
2579         if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
2580                 statusbar_verbosity_set(FALSE);
2581                 main_window_cursor_normal(folderview->mainwin);
2582                 STATUSBAR_POP(folderview->mainwin);
2583                 folder_item_update_thaw();
2584                 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2585
2586                 folderview_sort_folders(folderview, 
2587                         gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), 
2588                                 NULL, new_folder->parent), new_folder->folder);
2589                 folderview_select(folderview, new_folder);
2590         } else {
2591                 statusbar_verbosity_set(FALSE);         
2592                 main_window_cursor_normal(folderview->mainwin);
2593                 STATUSBAR_POP(folderview->mainwin);
2594                 folder_item_update_thaw();
2595                 switch (status) {
2596                 case F_MOVE_FAILED_DEST_IS_PARENT:
2597                         alertpanel_error(_("Source and destination are the same."));
2598                         break;
2599                 case F_MOVE_FAILED_DEST_IS_CHILD:
2600                         alertpanel_error(_("Can't move a folder to one of its children."));
2601                         break;
2602                 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2603                         alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2604                         break;
2605                 default:
2606                         alertpanel_error(_("Move failed!"));
2607                         break;
2608                 }
2609         }       
2610         inc_unlock();           
2611         gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2612 }
2613
2614 static gint folderview_clist_compare(GtkCList *clist,
2615                                      gconstpointer ptr1, gconstpointer ptr2)
2616 {
2617         FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2618         FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2619
2620         if (!item1->name)
2621                 return (item2->name != NULL);
2622         if (!item2->name)
2623                 return -1;
2624
2625         return g_strcasecmp(item1->name, item2->name);
2626 }
2627
2628 static gint folderview_compare_name(gconstpointer a, gconstpointer b)
2629 {
2630         const FolderItem *item = a;
2631         const gchar *name = b;
2632
2633         if (!item->path) return -1;
2634         return strcmp2(g_basename(item->path), name);
2635 }
2636
2637 static void folderview_scoring_cb(FolderView *folderview, guint action,
2638                                    GtkWidget *widget)
2639 {
2640         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2641         FolderItem *item;
2642
2643         if (!folderview->selected) return;
2644
2645         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2646         g_return_if_fail(item != NULL);
2647         g_return_if_fail(item->folder != NULL);
2648
2649         prefs_scoring_open(item);
2650 }
2651
2652 static void folderview_processing_cb(FolderView *folderview, guint action,
2653                                      GtkWidget *widget)
2654 {
2655         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2656         FolderItem *item;
2657
2658         if (!folderview->selected) return;
2659
2660         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2661         g_return_if_fail(item != NULL);
2662         g_return_if_fail(item->folder != NULL);
2663
2664         prefs_filtering_open(item, NULL, NULL);
2665 }
2666
2667 void folderview_set_target_folder_color(gint color_op) 
2668 {
2669         gint firstone = 1;
2670         GList *list;
2671         FolderView *folderview;
2672
2673         for (list = folderview_list; list != NULL; list = list->next) {
2674                 folderview = (FolderView *)list->data;
2675                 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2676                 if (firstone) {
2677                         bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2678                                 folderview->color_op;
2679                         firstone = 0;
2680                 }
2681         }
2682 }
2683
2684 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2685 {
2686         folderview_init(folderview);
2687         folderview_set_all();
2688 }
2689
2690 static void drag_state_stop(FolderView *folderview)
2691 {
2692         if (folderview->drag_timer)
2693                 gtk_timeout_remove(folderview->drag_timer);
2694         folderview->drag_timer = 0;
2695         folderview->drag_node = NULL;
2696 }
2697
2698 static gint folderview_defer_expand(FolderView *folderview)
2699 {
2700         if (folderview->drag_node) {
2701                 folderview_recollapse_nodes(folderview, folderview->drag_node);
2702                 if (folderview->drag_item->collapsed) {
2703                         gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2704                         folderview->nodes_to_recollapse = g_slist_append
2705                                 (folderview->nodes_to_recollapse, folderview->drag_node);
2706                 }
2707         }
2708         folderview->drag_item  = NULL;
2709         folderview->drag_timer = 0;
2710         return FALSE;
2711 }
2712
2713 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2714 {
2715         /* the idea is that we call drag_state_start() whenever we want expansion to
2716          * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2717          * we need to call drag_state_stop() */
2718         drag_state_stop(folderview);
2719         /* request expansion */
2720         if (0 != (folderview->drag_timer = gtk_timeout_add
2721                         (prefs_common.hover_timeout, 
2722                          (GtkFunction)folderview_defer_expand,
2723                          folderview))) {
2724                 folderview->drag_node = node;
2725                 folderview->drag_item = item;
2726         }                        
2727 }
2728
2729 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2730                                   FolderView       *folderview)
2731 {
2732         GdkDragContext *context;
2733
2734         g_return_if_fail(folderview != NULL);
2735         if (folderview->selected == NULL) return;
2736         if (folderview->nodes_to_recollapse) 
2737                 g_slist_free(folderview->nodes_to_recollapse);
2738         folderview->nodes_to_recollapse = NULL;
2739         context = gtk_drag_begin(widget, folderview->target_list,
2740                                  GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2741         gtk_drag_set_icon_default(context);
2742 }
2743
2744 static void folderview_drag_data_get(GtkWidget        *widget,
2745                                      GdkDragContext   *drag_context,
2746                                      GtkSelectionData *selection_data,
2747                                      guint             info,
2748                                      guint             time,
2749                                      FolderView       *folderview)
2750 {
2751         FolderItem *item;
2752         GList *cur;
2753         gchar *source=NULL;
2754         
2755         for (cur = GTK_CLIST(folderview->ctree)->selection;
2756              cur != NULL; cur = cur->next) {
2757                 item = gtk_ctree_node_get_row_data
2758                         (GTK_CTREE(folderview->ctree), 
2759                          GTK_CTREE_NODE(cur->data));
2760                 if (item) {
2761                         source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2762                         gtk_selection_data_set(selection_data,
2763                                                selection_data->target, 8,
2764                                                source, strlen(source));
2765                         break;
2766                 } else
2767                         return;
2768         }
2769 }
2770
2771 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2772 {
2773         FolderUpdateData *hookdata;
2774         FolderView *folderview;
2775         GtkWidget *ctree;
2776
2777         hookdata = source;
2778         folderview = (FolderView *) userdata;   
2779         g_return_val_if_fail(hookdata != NULL, FALSE);
2780         g_return_val_if_fail(folderview != NULL, FALSE);
2781
2782         ctree = folderview->ctree;
2783         g_return_val_if_fail(ctree != NULL, FALSE);
2784
2785         if (hookdata->update_flags & FOLDER_NEW_FOLDERITEM)
2786                 folderview_create_folder_node(folderview, hookdata->item);
2787         else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2788                 GtkCTreeNode *node;
2789
2790                 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2791                 if (node != NULL)
2792                         gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2793         } else if (hookdata->update_flags & FOLDER_TREE_CHANGED)
2794                 folderview_set(folderview);
2795
2796         return FALSE;
2797 }
2798
2799 static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
2800                                           GdkDragContext *context,
2801                                           gint            x,
2802                                           gint            y,
2803                                           guint           time,
2804                                           FolderView     *folderview)
2805 {
2806         gint row, column;
2807         FolderItem *item, *src_item = NULL;
2808         GtkCTreeNode *node = NULL;
2809         gboolean acceptable = FALSE;
2810         gint height = folderview->ctree->allocation.height;
2811         gint total_height = folderview->ctree->requisition.height;
2812         GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2813                                 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2814         gfloat vpos = pos->value;
2815
2816         if (gtk_clist_get_selection_info
2817                 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2818                 if (y > height - 24 && height + vpos < total_height)
2819                         gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2820
2821                 if (y < 24 && y > 0)
2822                         gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2823
2824                 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2825                 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2826                 src_item = folderview->summaryview->folder_item;
2827
2828                 if (item && item->folder && item->path &&
2829                     src_item && src_item != item) {
2830                         switch (FOLDER_TYPE(item->folder)) {
2831                         case F_MH:
2832                         case F_MBOX:
2833                         case F_IMAP:
2834                                 acceptable = TRUE;
2835                                 break;
2836                         default:
2837                                 break;
2838                         }
2839                 } else if (item && item->folder && folder_item_get_path(item) &&
2840                            src_item && src_item != item) {
2841                         /* a root folder - acceptable only from folderview */
2842                         if (FOLDER_TYPE(item->folder) == F_MH || FOLDER_TYPE(item->folder) == F_IMAP)
2843                                 acceptable = TRUE;
2844                 }
2845                         
2846         }
2847
2848         if (acceptable || (src_item && src_item == item))
2849                 drag_state_start(folderview, node, item);
2850         
2851         if (acceptable) {
2852                 g_signal_handlers_block_by_func
2853                         (G_OBJECT(widget),
2854                          G_CALLBACK(folderview_selected), folderview);
2855                 gtk_ctree_select(GTK_CTREE(widget), node);
2856                 g_signal_handlers_unblock_by_func
2857                         (G_OBJECT(widget),
2858                          G_CALLBACK(folderview_selected), folderview);
2859                 gdk_drag_status(context, 
2860                                         (context->actions == GDK_ACTION_COPY ?
2861                                         GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2862         } else {
2863                 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2864                 gdk_drag_status(context, 0, time);
2865         }
2866
2867         return acceptable;
2868 }
2869
2870 static void folderview_drag_leave_cb(GtkWidget      *widget,
2871                                      GdkDragContext *context,
2872                                      guint           time,
2873                                      FolderView     *folderview)
2874 {
2875         drag_state_stop(folderview);
2876         gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2877 }
2878
2879 static void folderview_drag_received_cb(GtkWidget        *widget,
2880                                         GdkDragContext   *drag_context,
2881                                         gint              x,
2882                                         gint              y,
2883                                         GtkSelectionData *data,
2884                                         guint             info,
2885                                         guint             time,
2886                                         FolderView       *folderview)
2887 {
2888         gint row, column;
2889         FolderItem *item, *src_item;
2890         GtkCTreeNode *node;
2891
2892         drag_state_stop(folderview);
2893         if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2894                 /* comes from summaryview */
2895                 if (gtk_clist_get_selection_info
2896                         (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2897                         return;
2898
2899                 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2900                 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2901                 src_item = folderview->summaryview->folder_item;
2902                 
2903                 /* re-check (due to acceptable possibly set for folder moves */
2904                 if (!(item && item->folder && item->path &&
2905                       src_item && src_item != item && 
2906                       (FOLDER_TYPE(item->folder) == F_MH || FOLDER_TYPE(item->folder) == F_IMAP))) {
2907                         return;
2908                 }
2909                 if (item && src_item) {
2910                         switch (drag_context->action) {
2911                                 case GDK_ACTION_COPY:
2912                                         summary_copy_selected_to(folderview->summaryview, item);
2913                                         gtk_drag_finish(drag_context, TRUE, FALSE, time);
2914                                         break;
2915                                 case GDK_ACTION_MOVE:
2916                                 case GDK_ACTION_DEFAULT:
2917                                 default:
2918                         if (FOLDER_TYPE(src_item->folder) != FOLDER_TYPE(item->folder) ||
2919                             (FOLDER_TYPE(item->folder) == F_IMAP &&
2920                              src_item->folder != item->folder))
2921                                 summary_copy_selected_to(folderview->summaryview, item);
2922                         else
2923                                 summary_move_selected_to(folderview->summaryview, item);
2924                         gtk_drag_finish(drag_context, TRUE, TRUE, time);
2925                         }
2926                 } else
2927                         gtk_drag_finish(drag_context, FALSE, FALSE, time);
2928         } else {
2929                 /* comes from folderview */
2930                 char *source;
2931                 
2932                 source = data->data + 17;
2933                 if (gtk_clist_get_selection_info
2934                     (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2935                     || *source == 0) {
2936                         gtk_drag_finish(drag_context, FALSE, FALSE, time);                      
2937                         return;
2938                 }
2939                 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2940                 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2941                 src_item = folder_find_item_from_identifier(source);
2942
2943                 if (!item || !src_item || src_item->stype != F_NORMAL) {
2944                         gtk_drag_finish(drag_context, FALSE, FALSE, time);                      
2945                         return;
2946                 }
2947
2948                 folderview_move_to(folderview, src_item, item);
2949                 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2950         }
2951         folderview->nodes_to_recollapse = NULL;
2952 }
2953
2954 static void folderview_drag_end_cb(GtkWidget        *widget, 
2955                                    GdkDragContext   *drag_context,
2956                                    FolderView       *folderview)
2957 {
2958         drag_state_stop(folderview);
2959         g_slist_free(folderview->nodes_to_recollapse);
2960         folderview->nodes_to_recollapse = NULL;
2961 }