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