4e306d24ae181e0ba8cfb450fb3103f0070ad39c
[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 && use_color) {
1187                 style = bold_color_style;
1188         } else if (use_bold) {
1189                 style = bold_style;
1190                 if (item->op_count > 0) {
1191                         style = bold_tgtfold_style;
1192                 }
1193         } else if (use_color) {
1194                 style = normal_color_style;
1195                 gtk_ctree_node_set_foreground(ctree, node,
1196                                               &folderview->color_new);
1197         } else if (item->op_count > 0) {
1198                 style = bold_tgtfold_style;
1199         } else if (item->prefs->color > 0) {
1200                 GdkColor gdk_color;
1201
1202                 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1203                 color_style = gtk_style_copy(normal_style);
1204                 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1205                 style = color_style;
1206         } else {
1207                 style = normal_style;
1208         }
1209
1210         gtk_ctree_node_set_row_style(ctree, node, style);
1211
1212         if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1213                 folderview_update_node(folderview, node);
1214 }
1215
1216 gboolean folderview_update_item(gpointer source, gpointer data)
1217 {
1218         FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1219         FolderView *folderview = (FolderView *)data;
1220         GtkCTree *ctree;
1221         GtkCTreeNode *node;
1222
1223         g_return_val_if_fail(update_info != NULL, TRUE);
1224         g_return_val_if_fail(update_info->item != NULL, TRUE);
1225         g_return_val_if_fail(folderview != NULL, FALSE);
1226
1227         ctree = GTK_CTREE(folderview->ctree);
1228
1229         node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1230         if (node) {
1231                 if (update_info->update_flags & F_ITEM_UPDATE_MSGCNT)
1232                         folderview_update_node(folderview, node);
1233                 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1234                         summary_show(folderview->summaryview, update_info->item);
1235         }
1236         
1237         return FALSE;
1238 }
1239
1240 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1241                                       GNode *gnode, GtkCTreeNode *cnode,
1242                                       gpointer data)
1243 {
1244         FolderView *folderview = (FolderView *)data;
1245         FolderItem *item = FOLDER_ITEM(gnode->data);
1246
1247         g_return_val_if_fail(item != NULL, FALSE);
1248
1249         gtk_ctree_node_set_row_data(ctree, cnode, item);
1250         folderview_update_node(folderview, cnode);
1251
1252         return TRUE;
1253 }
1254
1255 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1256                                    gpointer data)
1257 {
1258         FolderView *folderview = (FolderView *)data;
1259         FolderItem *item;
1260
1261         if (GTK_CTREE_ROW(node)->children) {
1262                 item = gtk_ctree_node_get_row_data(ctree, node);
1263                 g_return_if_fail(item != NULL);
1264
1265                 if (!item->collapsed)
1266                         gtk_ctree_expand(ctree, node);
1267                 else
1268                         folderview_update_node(folderview, node);
1269         }
1270 }
1271
1272 #define SET_SPECIAL_FOLDER(ctree, item) \
1273 { \
1274         if (item) { \
1275                 GtkCTreeNode *node, *parent, *sibling; \
1276  \
1277                 node = gtk_ctree_find_by_row_data(ctree, root, item); \
1278                 if (!node) \
1279                         g_warning("%s not found.\n", item->path); \
1280                 else { \
1281                         parent = GTK_CTREE_ROW(node)->parent; \
1282                         if (prev && parent == GTK_CTREE_ROW(prev)->parent) \
1283                                 sibling = GTK_CTREE_ROW(prev)->sibling; \
1284                         else \
1285                                 sibling = GTK_CTREE_ROW(parent)->children; \
1286                         if (node != sibling) \
1287                                 gtk_ctree_move(ctree, node, parent, sibling); \
1288                 } \
1289  \
1290                 prev = node; \
1291         } \
1292 }
1293
1294 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1295                                     Folder *folder)
1296 {
1297         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1298         GtkCTreeNode *prev = NULL;
1299
1300         gtk_sctree_sort_recursive(ctree, root);
1301
1302         if (GTK_CTREE_ROW(root)->parent) return;
1303
1304         SET_SPECIAL_FOLDER(ctree, folder->inbox);
1305         SET_SPECIAL_FOLDER(ctree, folder->outbox);
1306         SET_SPECIAL_FOLDER(ctree, folder->draft);
1307         SET_SPECIAL_FOLDER(ctree, folder->queue);
1308         SET_SPECIAL_FOLDER(ctree, folder->trash);
1309 }
1310
1311 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1312 {
1313         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1314         GtkCTreeNode *root;
1315
1316         g_return_if_fail(folder != NULL);
1317
1318         root = gtk_ctree_insert_gnode(ctree, NULL, NULL, folder->node,
1319                                       folderview_gnode_func, folderview);
1320         gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1321                                 folderview);
1322         folderview_sort_folders(folderview, root, folder);
1323 }
1324
1325 void folderview_new_folder(FolderView *folderview)
1326 {
1327         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1328         FolderItem *item;
1329
1330         if (!folderview->selected) return;
1331
1332         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1333         g_return_if_fail(item != NULL);
1334         g_return_if_fail(item->folder != NULL);
1335
1336         switch (FOLDER_TYPE(item->folder)) {
1337         case F_MBOX:
1338                 folderview_new_mbox_folder_cb(folderview, 0, NULL);
1339                 break;
1340         case F_MH:
1341         case F_MAILDIR:
1342                 folderview_new_folder_cb(folderview, 0, NULL);
1343                 break;
1344         case F_IMAP:
1345                 folderview_new_imap_folder_cb(folderview, 0, NULL);
1346                 break;
1347         case F_NEWS:
1348         default:
1349                 break;
1350         }
1351 }
1352
1353 void folderview_rename_folder(FolderView *folderview)
1354 {
1355         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1356         FolderItem *item;
1357
1358         if (!folderview->selected) return;
1359
1360         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1361         g_return_if_fail(item != NULL);
1362         g_return_if_fail(item->folder != NULL);
1363         if (!item->path) return;
1364         if (item->stype != F_NORMAL) return;
1365
1366         switch (FOLDER_TYPE(item->folder)) {
1367         case F_MBOX:
1368                 folderview_rename_mbox_folder_cb(folderview, 0, NULL);
1369                 break;
1370         case F_MH:
1371         case F_MAILDIR:
1372         case F_IMAP:
1373                 folderview_rename_folder_cb(folderview, 0, NULL);
1374                 break;
1375         case F_NEWS:
1376         default:
1377                 break;
1378         }
1379 }
1380
1381 void folderview_delete_folder(FolderView *folderview)
1382 {
1383         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1384         FolderItem *item;
1385
1386         if (!folderview->selected) return;
1387
1388         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1389         g_return_if_fail(item != NULL);
1390         g_return_if_fail(item->folder != NULL);
1391         if (!item->path) return;
1392         if (item->stype != F_NORMAL) return;
1393
1394         switch (FOLDER_TYPE(item->folder)) {
1395         case F_MH:
1396         case F_MBOX:
1397         case F_MAILDIR:
1398         case F_IMAP:
1399                 folderview_delete_folder_cb(folderview, 0, NULL);
1400                 break;
1401         case F_NEWS:
1402         default:
1403                 break;
1404         }
1405 }
1406
1407
1408 /* callback functions */
1409
1410 static void folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1411                                       FolderView *folderview)
1412 {
1413         GtkCList *clist = GTK_CLIST(ctree);
1414         gint prev_row = -1, row = -1, column = -1;
1415         FolderItem *item;
1416         Folder *folder;
1417         GtkWidget *popup;
1418         gboolean mark_all_read   = FALSE;
1419         gboolean new_folder      = FALSE;
1420         gboolean rename_folder   = FALSE;
1421         gboolean move_folder     = FALSE;
1422         gboolean delete_folder   = FALSE;
1423         gboolean update_tree     = FALSE;
1424         gboolean rescan_tree     = FALSE;
1425         gboolean remove_tree     = FALSE;
1426         gboolean search_folder   = FALSE;
1427         gboolean folder_property = FALSE;
1428         gboolean folder_processing  = FALSE;
1429         gboolean folder_scoring  = FALSE;
1430
1431         if (!event) return;
1432
1433         if (event->button == 1) {
1434                 folderview->open_folder = TRUE;
1435                 return;
1436         }
1437
1438         if (event->button == 2 || event->button == 3) {
1439                 /* right clicked */
1440                 if (clist->selection) {
1441                         GtkCTreeNode *node;
1442
1443                         node = GTK_CTREE_NODE(clist->selection->data);
1444                         if (node)
1445                                 prev_row = gtkut_ctree_get_nth_from_node
1446                                         (GTK_CTREE(ctree), node);
1447                 }
1448
1449                 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1450                                                   &row, &column))
1451                         return;
1452                 if (prev_row != row) {
1453                         gtk_clist_unselect_all(clist);
1454                         if (event->button == 2)
1455                                 folderview_select_node
1456                                         (folderview,
1457                                          gtk_ctree_node_nth(GTK_CTREE(ctree),
1458                                                             row));
1459                         else
1460                                 gtk_clist_select_row(clist, row, column);
1461                 }
1462         }
1463
1464         if (event->button != 3) return;
1465
1466         item = gtk_clist_get_row_data(clist, row);
1467         g_return_if_fail(item != NULL);
1468         g_return_if_fail(item->folder != NULL);
1469         folder = item->folder;
1470
1471         if (folderview->mainwin->lock_count == 0) {
1472                 new_folder = TRUE;
1473                 if (item->parent == NULL) {
1474                         update_tree = remove_tree = TRUE;
1475                         if (folder->account)
1476                                 folder_property = TRUE;
1477                 } else
1478                         mark_all_read = search_folder = folder_property = TRUE;
1479                         
1480                 if (FOLDER_IS_LOCAL(folder) || FOLDER_TYPE(folder) == F_IMAP || FOLDER_TYPE(folder) == F_MBOX) {
1481                         if (item->parent == NULL)
1482                                 update_tree = rescan_tree = TRUE;
1483                         else if (item->stype == F_NORMAL)
1484                                 move_folder = rename_folder = delete_folder = folder_scoring = folder_processing = TRUE;
1485                         else if (item->stype == F_INBOX)
1486                                 folder_scoring = folder_processing = TRUE;
1487                         else if (item->stype == F_TRASH)
1488                                 folder_processing = TRUE;
1489                         else if (item->stype == F_OUTBOX)
1490                                 folder_processing = TRUE;
1491                 } else if (FOLDER_TYPE(folder) == F_NEWS) {
1492                         if (item->parent != NULL)
1493                                 delete_folder = folder_scoring = folder_processing = TRUE;
1494                 }
1495                 if (item->unread_msgs < 1) 
1496                         mark_all_read = FALSE;
1497         }
1498
1499 #define SET_SENS(factory, name, sens) \
1500         menu_set_sensitive(folderview->factory, name, sens)
1501         
1502         mark_all_read = mark_all_read && 
1503                         (item == folderview->summaryview->folder_item);
1504
1505         if (FOLDER_IS_LOCAL(folder)) {
1506                 popup = folderview->mail_popup;
1507                 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1508                 SET_SENS(mail_factory, "/Mark all read", mark_all_read);
1509                 SET_SENS(mail_factory, "/Create new folder...", new_folder);
1510                 SET_SENS(mail_factory, "/Rename folder...", rename_folder);
1511                 SET_SENS(mail_factory, "/Move folder...", move_folder);
1512                 SET_SENS(mail_factory, "/Delete folder", delete_folder);
1513                 SET_SENS(mail_factory, "/Check for new messages", update_tree);
1514                 SET_SENS(mail_factory, "/Rebuild folder tree", rescan_tree);
1515                 SET_SENS(mail_factory, "/Remove mailbox", remove_tree);
1516                 SET_SENS(mail_factory, "/Search folder...", search_folder);
1517                 SET_SENS(mail_factory, "/Properties...", folder_property);
1518                 SET_SENS(mail_factory, "/Processing...", folder_processing);
1519                 SET_SENS(mail_factory, "/Scoring...", folder_scoring);
1520         } else if (FOLDER_TYPE(folder) == F_IMAP) {
1521                 popup = folderview->imap_popup;
1522                 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1523                 SET_SENS(imap_factory, "/Mark all read", mark_all_read);
1524                 SET_SENS(imap_factory, "/Create new folder...", new_folder);
1525                 SET_SENS(imap_factory, "/Rename folder...", rename_folder);
1526                 SET_SENS(imap_factory, "/Move folder...", move_folder);
1527                 SET_SENS(imap_factory, "/Delete folder", delete_folder);
1528                 SET_SENS(imap_factory, "/Check for new messages", update_tree);
1529                 SET_SENS(imap_factory, "/Rebuild folder tree", rescan_tree);
1530                 SET_SENS(imap_factory, "/Remove IMAP4 account", remove_tree);
1531                 SET_SENS(imap_factory, "/Search folder...", search_folder);
1532                 SET_SENS(imap_factory, "/Properties...", folder_property);
1533                 SET_SENS(imap_factory, "/Processing...", folder_processing);
1534                 SET_SENS(imap_factory, "/Scoring...", folder_scoring);
1535         } else if (FOLDER_TYPE(folder) == F_NEWS) {
1536                 popup = folderview->news_popup;
1537                 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1538                 SET_SENS(news_factory, "/Mark all read", mark_all_read);
1539                 SET_SENS(news_factory, "/Subscribe to newsgroup...", new_folder);
1540                 SET_SENS(news_factory, "/Remove newsgroup", delete_folder);
1541                 SET_SENS(news_factory, "/Check for new messages", update_tree);
1542                 SET_SENS(news_factory, "/Remove news account", remove_tree);
1543                 SET_SENS(news_factory, "/Search folder...", search_folder);
1544                 SET_SENS(news_factory, "/Properties...", folder_property);
1545                 SET_SENS(news_factory, "/Processing...", folder_processing);
1546                 SET_SENS(news_factory, "/Scoring...", folder_scoring);
1547         } else if (FOLDER_TYPE(folder) == F_MBOX) {
1548                 popup = folderview->mbox_popup;
1549                 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1550                 SET_SENS(mbox_factory, "/Create new folder...", new_folder);
1551                 SET_SENS(mbox_factory, "/Rename folder...", rename_folder);
1552                 SET_SENS(mbox_factory, "/Move folder...", move_folder);
1553                 SET_SENS(mbox_factory, "/Delete folder", delete_folder);
1554                 SET_SENS(news_factory, "/Properties...", folder_property);
1555                 SET_SENS(mbox_factory, "/Processing...", folder_processing);
1556                 SET_SENS(mbox_factory, "/Scoring...", folder_scoring);
1557         } else
1558                 return;
1559
1560 #undef SET_SENS
1561
1562         gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1563                        event->button, event->time);
1564 }
1565
1566 static void folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1567                                        FolderView *folderview)
1568 {
1569         if (!event) return;
1570
1571         if (event->button == 1 && folderview->open_folder == FALSE &&
1572             folderview->opened != NULL) {
1573                 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1574                                           folderview->opened);
1575                 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1576         }
1577 }
1578
1579 static void folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1580                                    FolderView *folderview)
1581 {
1582         if (!event) return;
1583
1584         switch (event->keyval) {
1585         case GDK_Return:
1586                 if (folderview->selected) {
1587                         folderview_select_node(folderview,
1588                                                folderview->selected);
1589                 }
1590                 break;
1591         case GDK_space:
1592                 if (folderview->selected) {
1593                         if (folderview->opened == folderview->selected &&
1594                             folderview->summaryview->messages == 0)
1595                                 folderview_select_next_unread(folderview);
1596                         else
1597                                 folderview_select_node(folderview,
1598                                                        folderview->selected);
1599                 }
1600                 break;
1601         default:
1602                 break;
1603         }
1604 }
1605
1606 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
1607                                 gint column, FolderView *folderview)
1608 {
1609         static gboolean can_select = TRUE;      /* exclusive lock */
1610         gboolean opened;
1611         FolderItem *item;
1612         gchar *buf;
1613
1614         folderview->selected = row;
1615
1616         if (folderview->opened == row) {
1617                 folderview->open_folder = FALSE;
1618                 return;
1619         }
1620
1621         if (!can_select || summary_is_locked(folderview->summaryview)) {
1622                 gtkut_ctree_set_focus_row(ctree, folderview->opened);
1623                 gtk_ctree_select(ctree, folderview->opened);
1624                 return;
1625         }
1626
1627         if (!folderview->open_folder) return;
1628
1629         item = gtk_ctree_node_get_row_data(ctree, row);
1630         if (!item) return;
1631
1632         can_select = FALSE;
1633
1634         /* Save cache for old folder */
1635         /* We don't want to lose all caches if sylpheed crashed */
1636         if (folderview->opened) {
1637                 FolderItem *olditem;
1638                 
1639                 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
1640                 if (olditem) {
1641                         /* will be null if we just moved the previously opened folder */
1642                         summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
1643                         folder_item_close(olditem);
1644                 }
1645         }
1646
1647         /* CLAWS: set compose button type: news folder items 
1648          * always have a news folder as parent */
1649         if (item->folder) 
1650                 toolbar_set_compose_button
1651                         (folderview->mainwin->toolbar,
1652                          FOLDER_TYPE(item->folder) == F_NEWS ? 
1653                          COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
1654
1655         if (item->path)
1656                 debug_print("Folder %s is selected\n", item->path);
1657
1658         if (!GTK_CTREE_ROW(row)->children)
1659                 gtk_ctree_expand(ctree, row);
1660         if (folderview->opened &&
1661             !GTK_CTREE_ROW(folderview->opened)->children)
1662                 gtk_ctree_collapse(ctree, folderview->opened);
1663
1664         /* ungrab the mouse event */
1665         if (GTK_WIDGET_HAS_GRAB(ctree)) {
1666                 gtk_grab_remove(GTK_WIDGET(ctree));
1667                 if (gdk_pointer_is_grabbed())
1668                         gdk_pointer_ungrab(GDK_CURRENT_TIME);
1669         }
1670
1671         /* Open Folder */
1672         buf = g_strdup_printf(_("Opening Folder %s..."), item->path ? 
1673                                         item->path : "(null)");
1674         debug_print("%s\n", buf);
1675         STATUSBAR_PUSH(folderview->mainwin, buf);
1676         g_free(buf);
1677
1678         main_window_cursor_wait(folderview->mainwin);
1679
1680         if (folder_item_open(item) != 0) {
1681                 main_window_cursor_normal(folderview->mainwin);
1682                 STATUSBAR_POP(folderview->mainwin);
1683
1684                 alertpanel_error(_("Folder could not be opened."));
1685
1686                 return;
1687         }
1688
1689         main_window_cursor_normal(folderview->mainwin);
1690
1691         /* Show messages */
1692         summary_set_prefs_from_folderitem(folderview->summaryview, item);
1693         opened = summary_show(folderview->summaryview, item);
1694         
1695         folder_clean_cache_memory();
1696
1697         if (!opened) {
1698                 gtkut_ctree_set_focus_row(ctree, folderview->opened);
1699                 gtk_ctree_select(ctree, folderview->opened);
1700         } else {
1701                 folderview->opened = row;
1702                 if (gtk_ctree_node_is_visible(ctree, row)
1703                     != GTK_VISIBILITY_FULL)
1704                         gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
1705         }
1706
1707         STATUSBAR_POP(folderview->mainwin);
1708
1709         folderview->open_folder = FALSE;
1710         can_select = TRUE;
1711 }
1712
1713 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
1714                                      FolderView *folderview)
1715 {
1716         FolderItem *item;
1717
1718         item = gtk_ctree_node_get_row_data(ctree, node);
1719         g_return_if_fail(item != NULL);
1720         item->collapsed = FALSE;
1721         folderview_update_node(folderview, node);
1722 }
1723
1724 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
1725                                       FolderView *folderview)
1726 {
1727         FolderItem *item;
1728
1729         item = gtk_ctree_node_get_row_data(ctree, node);
1730         g_return_if_fail(item != NULL);
1731         item->collapsed= TRUE;
1732         folderview_update_node(folderview, node);
1733 }
1734
1735 static void folderview_popup_close(GtkMenuShell *menu_shell,
1736                                    FolderView *folderview)
1737 {
1738         if (!folderview->opened) return;
1739
1740         gtkut_ctree_set_focus_row(GTK_CTREE(folderview->ctree),
1741                                   folderview->opened);
1742         gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
1743 }
1744
1745 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
1746                                    FolderView *folderview)
1747 {
1748         switch (column) {
1749         case COL_FOLDER:
1750                 prefs_common.folder_col_folder = width;
1751                 break;
1752         case COL_NEW:
1753                 prefs_common.folder_col_new = width;
1754                 break;
1755         case COL_UNREAD:
1756                 prefs_common.folder_col_unread = width;
1757                 break;
1758         case COL_TOTAL:
1759                 prefs_common.folder_col_total = width;
1760                 break;
1761         default:
1762                 break;
1763         }
1764 }
1765
1766 static GtkCTreeNode *folderview_find_by_name(GtkCTree *ctree,
1767                                              GtkCTreeNode *node,
1768                                              const gchar *name)
1769 {
1770         FolderItem *item;
1771
1772         if (!node)
1773                 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1774         if (!node)
1775                 return NULL;
1776
1777         node = GTK_CTREE_ROW(node)->children;
1778
1779         while (node) {
1780                 item = gtk_ctree_node_get_row_data(ctree, node);
1781                 if (!folderview_compare_name(item, name))
1782                         return node;
1783                 node = GTK_CTREE_ROW(node)->sibling;
1784         }
1785
1786         return NULL;
1787 }
1788
1789 static void folderview_update_tree_cb(FolderView *folderview, guint action,
1790                                       GtkWidget *widget)
1791 {
1792         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1793         FolderItem *item;
1794
1795         if (!folderview->selected) return;
1796
1797         summary_show(folderview->summaryview, NULL);
1798
1799         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1800         g_return_if_fail(item != NULL);
1801         g_return_if_fail(item->folder != NULL);
1802
1803         if (action == 0)
1804                 folderview_check_new(item->folder);
1805         else
1806                 folderview_rescan_tree(item->folder);
1807 }
1808
1809 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
1810 {
1811         GNode *srcnode;
1812
1813         folderview_create_folder_node(folderview, item);
1814         
1815         srcnode = item->folder->node;   
1816         srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1817         srcnode = srcnode->children;
1818         while (srcnode != NULL) {
1819                 if (srcnode && srcnode->data) {
1820                         FolderItem *next_item = (FolderItem*) srcnode->data;
1821                         folderview_create_folder_node_recursive(folderview, next_item);
1822                 }
1823                 srcnode = srcnode->next;
1824         }
1825 }
1826
1827 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
1828 {
1829         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1830         gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
1831         GtkCTreeNode *node, *parent_node;
1832         
1833         parent_node = gtk_ctree_find_by_row_data(ctree, NULL, item->parent);
1834
1835         gtk_clist_freeze(GTK_CLIST(ctree));
1836
1837         text[COL_FOLDER] = item->name;
1838         node = gtk_ctree_insert_node(ctree, parent_node, NULL, text,
1839                                      FOLDER_SPACING,
1840                                      folderxpm, folderxpmmask,
1841                                      folderopenxpm, folderopenxpmmask,
1842                                      FALSE, FALSE);
1843         gtk_ctree_expand(ctree, parent_node);
1844         gtk_ctree_node_set_row_data(ctree, node, item);
1845         if (normal_style)
1846                 gtk_ctree_node_set_row_style(ctree, node, normal_style);
1847         folderview_sort_folders(folderview, folderview->selected, item->folder);
1848
1849         gtk_clist_thaw(GTK_CLIST(ctree));
1850 }
1851
1852 static void folderview_new_folder_cb(FolderView *folderview, guint action,
1853                                      GtkWidget *widget)
1854 {
1855         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1856         FolderItem *item;
1857         FolderItem *new_item;
1858         gchar *new_folder;
1859         gchar *name, *name_;
1860
1861         if (!folderview->selected) return;
1862
1863         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1864         g_return_if_fail(item != NULL);
1865         g_return_if_fail(item->folder != NULL);
1866
1867         new_folder = input_dialog(_("New folder"),
1868                                   _("Input the name of new folder:"),
1869                                   _("NewFolder"));
1870         if (!new_folder) return;
1871
1872         if (FOLDER_TYPE(item->folder) != F_MBOX) {
1873                 if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
1874                         alertpanel_error(_("`%c' can't be included in folder name."),
1875                                          G_DIR_SEPARATOR);
1876                         g_free(new_folder);
1877                         return;
1878                 }
1879         }
1880
1881         name_ = trim_string(new_folder, 32);
1882         Xstrdup_a(name, name_, {g_free(new_folder); return;});
1883         g_free(name_);
1884
1885         /* find whether the directory already exists */
1886         if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
1887                 alertpanel_error(_("The folder `%s' already exists."), name);
1888                 g_free(new_folder);
1889                 return;
1890         }
1891
1892         new_item = folder_create_folder(item, new_folder);
1893         if (!new_item) {
1894                 alertpanel_error(_("Can't create the folder `%s'."), name);
1895                 g_free(new_folder);
1896                 return;
1897         } 
1898         g_free(new_folder);
1899
1900         folderview_create_folder_node(folderview, new_item);
1901
1902         folder_write_list();
1903 }
1904
1905 static void folderview_new_mbox_folder_cb(FolderView *folderview, guint action,
1906                                           GtkWidget *widget)
1907 {
1908         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1909         FolderItem *item;
1910         FolderItem *new_item;
1911         gchar *new_folder;
1912
1913         if (!folderview->selected) return;
1914
1915         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1916         g_return_if_fail(item != NULL);
1917         g_return_if_fail(item->folder != NULL);
1918
1919         new_folder = input_dialog(_("New folder"),
1920                                   _("Input the name of new folder:"),
1921                                   _("NewFolder"));
1922         if (!new_folder) return;
1923
1924         /* find whether the directory already exists */
1925         if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
1926                 alertpanel_error(_("The folder `%s' already exists."),
1927                                  new_folder);
1928                 g_free(new_folder);
1929                 return;
1930         }
1931
1932         new_item = folder_create_folder(item, new_folder);
1933         g_free(new_folder);
1934         if (!new_item) return;
1935
1936         folderview_create_folder_node(folderview, new_item);
1937
1938         folder_write_list();
1939 }
1940
1941 static void folderview_rename_folder_cb(FolderView *folderview, guint action,
1942                                         GtkWidget *widget)
1943 {
1944         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1945         FolderItem *item;
1946         gchar *new_folder;
1947         gchar *name, *name_;
1948         gchar *message;
1949         gchar *old_path;
1950         gchar *old_id;
1951         gchar *new_id;
1952
1953         if (!folderview->selected) return;
1954
1955         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1956         g_return_if_fail(item != NULL);
1957         g_return_if_fail(item->path != NULL);
1958         g_return_if_fail(item->folder != NULL);
1959
1960         name_ = trim_string(item->name, 32);
1961         Xstrdup_a(name, name_, return);
1962         g_free(name_);
1963         message = g_strdup_printf(_("Input new name for `%s':"), name);
1964         new_folder = input_dialog(_("Rename folder"), message,
1965                                   g_basename(item->path));
1966         g_free(message);
1967         if (!new_folder) return;
1968
1969         if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
1970                 alertpanel_error(_("`%c' can't be included in folder name."),
1971                                  G_DIR_SEPARATOR);
1972                 g_free(new_folder);
1973                 return;
1974         }
1975
1976         if (folderview_find_by_name
1977                 (ctree, GTK_CTREE_ROW(folderview->selected)->parent,
1978                  new_folder)) {
1979                 name = trim_string(new_folder, 32);
1980                 alertpanel_error(_("The folder `%s' already exists."), name);
1981                 g_free(name);
1982                 g_free(new_folder);
1983                 return;
1984         }
1985
1986         Xstrdup_a(old_path, item->path, {g_free(new_folder); return;});
1987         old_id = folder_item_get_identifier(item);
1988
1989         if (item->folder->klass->rename_folder(item->folder, item, new_folder) < 0) {
1990                 g_free(old_id);
1991                 g_free(new_folder);
1992                 return;
1993         }
1994         g_free(new_folder);
1995
1996         /* if (FOLDER_TYPE(item->folder) == F_MH)
1997                 prefs_filtering_rename_path(old_path, item->path); */
1998         new_id = folder_item_get_identifier(item);
1999         prefs_filtering_rename_path(old_id, new_id);
2000
2001         g_free(old_id);
2002         g_free(new_id);
2003
2004         gtk_clist_freeze(GTK_CLIST(ctree));
2005
2006         folderview_update_node(folderview, folderview->selected);
2007         folderview_sort_folders(folderview,
2008                                 GTK_CTREE_ROW(folderview->selected)->parent,
2009                                 item->folder);
2010         if (folderview->opened == folderview->selected ||
2011             gtk_ctree_is_ancestor(ctree,
2012                                   folderview->selected,
2013                                   folderview->opened)) {
2014                 GtkCTreeNode *node = folderview->opened;
2015                 folderview_unselect(folderview);
2016                 folderview_select_node(folderview, node);
2017         }
2018
2019         gtk_clist_thaw(GTK_CLIST(ctree));
2020
2021         folder_write_list();
2022 }
2023
2024 static void folderview_rename_mbox_folder_cb(FolderView *folderview,
2025                                              guint action,
2026                                              GtkWidget *widget)
2027 {
2028         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2029         FolderItem *item;
2030         gchar *new_folder;
2031         gchar *message;
2032
2033         if (!folderview->selected) return;
2034
2035         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2036         g_return_if_fail(item != NULL);
2037         g_return_if_fail(item->path != NULL);
2038         g_return_if_fail(item->folder != NULL);
2039
2040         message = g_strdup_printf(_("Input new name for `%s':"),
2041                                   g_basename(item->path));
2042         new_folder = input_dialog(_("Rename folder"), message,
2043                                   g_basename(item->path));
2044         g_free(message);
2045         if (!new_folder) return;
2046
2047         if (folderview_find_by_name
2048                 (ctree, GTK_CTREE_ROW(folderview->selected)->parent,
2049                  new_folder)) {
2050                 alertpanel_error(_("The folder `%s' already exists."),
2051                                  new_folder);
2052                 g_free(new_folder);
2053                 return;
2054         }
2055
2056         if (item->folder->klass->rename_folder(item->folder, item, new_folder) < 0) {
2057                 g_free(new_folder);
2058                 return;
2059         }
2060         g_free(new_folder);
2061
2062         gtk_clist_freeze(GTK_CLIST(ctree));
2063
2064         folderview_update_node(folderview, folderview->selected);
2065         folderview_sort_folders(folderview,
2066                                 GTK_CTREE_ROW(folderview->selected)->parent,
2067                                 item->folder);
2068         if (folderview->opened == folderview->selected) {
2069                 if (!GTK_CTREE_ROW(folderview->opened)->children)
2070                         gtk_ctree_expand(ctree, folderview->opened);
2071                 summary_show(folderview->summaryview, item);
2072         }
2073
2074         gtk_clist_thaw(GTK_CLIST(ctree));
2075
2076         folder_write_list();
2077 }
2078
2079 static void folderview_delete_folder_cb(FolderView *folderview, guint action,
2080                                         GtkWidget *widget)
2081 {
2082         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2083         FolderItem *item;
2084         gchar *message, *name, *name_;
2085         AlertValue avalue;
2086         gchar *old_path;
2087         gchar *old_id;
2088
2089         if (!folderview->selected) return;
2090
2091         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2092         g_return_if_fail(item != NULL);
2093         g_return_if_fail(item->path != NULL);
2094         g_return_if_fail(item->folder != NULL);
2095
2096         name_ = trim_string(item->name, 32);
2097         Xstrdup_a(name, name_, return);
2098         g_free(name_);
2099         message = g_strdup_printf
2100                 (_("All folder(s) and message(s) under `%s' will be deleted.\n"
2101                    "Do you really want to delete?"), name);
2102         avalue = alertpanel(_("Delete folder"), message,
2103                             _("Yes"), _("+No"), NULL);
2104         g_free(message);
2105         if (avalue != G_ALERTDEFAULT) return;
2106
2107         Xstrdup_a(old_path, item->path, return);
2108         old_id = folder_item_get_identifier(item);
2109
2110         if (item->folder->klass->remove_folder(item->folder, item) < 0) {
2111                 alertpanel_error(_("Can't remove the folder `%s'."), name);
2112                 if (folderview->opened == folderview->selected)
2113                         summary_show(folderview->summaryview,
2114                                      folderview->summaryview->folder_item);
2115                 g_free(old_id);
2116                 return;
2117         }
2118
2119         /* if (FOLDER_TYPE(item->folder) == F_MH)
2120                 prefs_filtering_delete_path(old_path); */
2121
2122         if (folderview->opened == folderview->selected ||
2123             gtk_ctree_is_ancestor(ctree,
2124                                   folderview->selected,
2125                                   folderview->opened)) {
2126                 summary_clear_all(folderview->summaryview);
2127                 folderview->opened = NULL;
2128         }
2129
2130         gtk_ctree_remove_node(ctree, folderview->selected);
2131         folder_write_list();
2132
2133         prefs_filtering_delete_path(old_id);
2134         g_free(old_id);
2135
2136 }
2137
2138 static void folderview_remove_mailbox_cb(FolderView *folderview, guint action,
2139                                          GtkWidget *widget)
2140 {
2141         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2142         GtkCTreeNode *node;
2143         FolderItem *item;
2144         gchar *name, *name_;
2145         gchar *message;
2146         AlertValue avalue;
2147
2148         if (!folderview->selected) return;
2149         node = folderview->selected;
2150         item = gtk_ctree_node_get_row_data(ctree, node);
2151         g_return_if_fail(item != NULL);
2152         g_return_if_fail(item->folder != NULL);
2153         if (item->parent) return;
2154
2155         name_ = trim_string(item->folder->name, 32);
2156         Xstrdup_a(name, name_, return);
2157         g_free(name_);
2158         message = g_strdup_printf
2159                 (_("Really remove the mailbox `%s' ?\n"
2160                    "(The messages are NOT deleted from the disk)"), name);
2161         avalue = alertpanel(_("Remove mailbox"), message,
2162                             _("Yes"), _("+No"), NULL);
2163         g_free(message);
2164         if (avalue != G_ALERTDEFAULT) return;
2165
2166         folder_destroy(item->folder);
2167         summary_clear_all(folderview->summaryview);
2168         folderview_unselect(folderview);
2169         gtk_ctree_remove_node(ctree, node);
2170         folder_write_list();
2171 }
2172
2173 static void folderview_new_imap_folder_cb(FolderView *folderview, guint action,
2174                                           GtkWidget *widget)
2175 {
2176         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2177         FolderItem *item;
2178         FolderItem *new_item;
2179         gchar *new_folder;
2180         gchar *name, *name_;
2181         gchar *p;
2182
2183         if (!folderview->selected) return;
2184
2185         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2186         g_return_if_fail(item != NULL);
2187         g_return_if_fail(item->folder != NULL);
2188         g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP);
2189         g_return_if_fail(item->folder->account != NULL);
2190
2191         new_folder = input_dialog
2192                 (_("New folder"),
2193                  _("Input the name of new folder:\n"
2194                    "(if you want to create a folder to store subfolders,\n"
2195                    " append `/' at the end of the name)"),
2196                  _("NewFolder"));
2197         if (!new_folder) return;
2198
2199         if ((p = strchr(new_folder, G_DIR_SEPARATOR)) != NULL &&
2200             *(p + 1) != '\0') {
2201                 alertpanel_error(_("`%c' can't be included in folder name."),
2202                                  G_DIR_SEPARATOR);
2203                 g_free(new_folder);
2204                 return;
2205         }
2206
2207         name_ = trim_string(new_folder, 32);
2208         Xstrdup_a(name, name_, return);
2209         g_free(name_);
2210
2211         /* find whether the directory already exists */
2212         if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
2213                 alertpanel_error(_("The folder `%s' already exists."), name);
2214                 g_free(new_folder);
2215                 return;
2216         }
2217
2218         new_item = folder_create_folder(item, new_folder);
2219         if (!new_item) {
2220                 alertpanel_error(_("Can't create the folder `%s'."), name);
2221                 g_free(new_folder);
2222                 return;
2223         }
2224         g_free(new_folder);
2225
2226         folderview_create_folder_node(folderview, new_item);
2227
2228         folder_write_list();
2229 }
2230
2231 static void folderview_rm_imap_server_cb(FolderView *folderview, guint action,
2232                                          GtkWidget *widget)
2233 {
2234         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2235         FolderItem *item;
2236         PrefsAccount *account;
2237         gchar *name, *name_;
2238         gchar *message;
2239         AlertValue avalue;
2240
2241         if (!folderview->selected) return;
2242
2243         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2244         g_return_if_fail(item != NULL);
2245         g_return_if_fail(item->folder != NULL);
2246         g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP);
2247         g_return_if_fail(item->folder->account != NULL);
2248
2249         name_ = trim_string(item->folder->name, 32);
2250         Xstrdup_a(name, name_, return);
2251         g_free(name_);
2252         message = g_strdup_printf(_("Really delete IMAP4 account `%s'?"), name);
2253         avalue = alertpanel(_("Delete IMAP4 account"), message,
2254                             _("Yes"), _("+No"), NULL);
2255         g_free(message);
2256
2257         if (avalue != G_ALERTDEFAULT) return;
2258
2259         if (folderview->opened == folderview->selected ||
2260             gtk_ctree_is_ancestor(ctree,
2261                                   folderview->selected,
2262                                   folderview->opened)) {
2263                 summary_clear_all(folderview->summaryview);
2264                 folderview->opened = NULL;
2265         }
2266
2267         account = item->folder->account;
2268         folder_destroy(item->folder);
2269         account_destroy(account);
2270         gtk_ctree_remove_node(ctree, folderview->selected);
2271         account_set_menu();
2272         main_window_reflect_prefs_all();
2273         folder_write_list();
2274 }
2275
2276 static void folderview_new_news_group_cb(FolderView *folderview, guint action,
2277                                          GtkWidget *widget)
2278 {
2279         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2280         gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2281         GtkCTreeNode *servernode, *node;
2282         Folder *folder;
2283         FolderItem *item;
2284         FolderItem *rootitem;
2285         FolderItem *newitem;
2286         GSList *new_subscr;
2287         GSList *cur;
2288         GNode *gnode;
2289
2290         if (!folderview->selected) return;
2291
2292         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2293         g_return_if_fail(item != NULL);
2294         folder = item->folder;
2295         g_return_if_fail(folder != NULL);
2296         g_return_if_fail(FOLDER_TYPE(folder) == F_NEWS);
2297         g_return_if_fail(folder->account != NULL);
2298
2299         if (GTK_CTREE_ROW(folderview->selected)->parent != NULL)
2300                 servernode = GTK_CTREE_ROW(folderview->selected)->parent;
2301         else
2302                 servernode = folderview->selected;
2303
2304         rootitem = gtk_ctree_node_get_row_data(ctree, servernode);
2305
2306         new_subscr = grouplist_dialog(folder);
2307
2308         /* remove unsubscribed newsgroups */
2309         for (gnode = folder->node->children; gnode != NULL; ) {
2310                 GNode *next = gnode->next;
2311
2312                 item = FOLDER_ITEM(gnode->data);
2313                 if (g_slist_find_custom(new_subscr, item->path,
2314                                         (GCompareFunc)g_strcasecmp) != NULL) {
2315                         gnode = next;
2316                         continue;
2317                 }
2318
2319                 node = gtk_ctree_find_by_row_data(ctree, servernode, item);
2320                 if (!node) {
2321                         gnode = next;
2322                         continue;
2323                 }
2324
2325                 if (folderview->opened == node) {
2326                         summary_clear_all(folderview->summaryview);
2327                         folderview->opened = NULL;
2328                 }
2329
2330                 folder_item_remove(item);
2331                 gtk_ctree_remove_node(ctree, node);
2332
2333                 gnode = next;
2334         }
2335
2336         gtk_clist_freeze(GTK_CLIST(ctree));
2337
2338         /* add subscribed newsgroups */
2339         for (cur = new_subscr; cur != NULL; cur = cur->next) {
2340                 gchar *name = (gchar *)cur->data;
2341
2342                 if (folderview_find_by_name(ctree, servernode, name) != NULL)
2343                         continue;
2344
2345                 text[COL_FOLDER] = name;
2346                 node = gtk_ctree_insert_node(ctree, servernode, NULL, text,
2347                                              FOLDER_SPACING,
2348                                              folderxpm, folderxpmmask,
2349                                              folderopenxpm, folderopenxpmmask,
2350                                              FALSE, FALSE);
2351                 gtk_ctree_expand(ctree, servernode);
2352
2353                 newitem = folder_item_new(folder, name, name);
2354                 folder_item_append(rootitem, newitem);
2355                 gtk_ctree_node_set_row_data(ctree, node, newitem);
2356         }
2357
2358         folderview_sort_folders(folderview, servernode, folder);
2359         gtk_clist_thaw(GTK_CLIST(ctree));
2360
2361         slist_free_strings(new_subscr);
2362         g_slist_free(new_subscr);
2363
2364         folder_write_list();
2365 }
2366
2367 static void folderview_rm_news_group_cb(FolderView *folderview, guint action,
2368                                         GtkWidget *widget)
2369 {
2370         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2371         FolderItem *item;
2372         gchar *name, *name_;
2373         gchar *message;
2374         AlertValue avalue;
2375
2376         if (!folderview->selected) return;
2377
2378         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2379         g_return_if_fail(item != NULL);
2380         g_return_if_fail(item->folder != NULL);
2381         g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS);
2382         g_return_if_fail(item->folder->account != NULL);
2383
2384         name_ = trim_string(item->path, 32);
2385         Xstrdup_a(name, name_, return);
2386         g_free(name_);
2387         message = g_strdup_printf(_("Really delete newsgroup `%s'?"), name);
2388         avalue = alertpanel(_("Delete newsgroup"), message,
2389                             _("Yes"), _("+No"), NULL);
2390         g_free(message);
2391         if (avalue != G_ALERTDEFAULT) return;
2392
2393         if (folderview->opened == folderview->selected) {
2394                 summary_clear_all(folderview->summaryview);
2395                 folderview->opened = NULL;
2396         }
2397
2398         folder_item_remove(item);
2399         gtk_ctree_remove_node(ctree, folderview->selected);
2400         folder_write_list();
2401         
2402         prefs_filtering_delete_path(name);
2403 }
2404
2405 static void folderview_rm_news_server_cb(FolderView *folderview, guint action,
2406                                          GtkWidget *widget)
2407 {
2408         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2409         FolderItem *item;
2410         PrefsAccount *account;
2411         gchar *name, *name_;
2412         gchar *message;
2413         AlertValue avalue;
2414
2415         if (!folderview->selected) return;
2416
2417         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2418         g_return_if_fail(item != NULL);
2419         g_return_if_fail(item->folder != NULL);
2420         g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS);
2421         g_return_if_fail(item->folder->account != NULL);
2422
2423         name_ = trim_string(item->folder->name, 32);
2424         Xstrdup_a(name, name_, return);
2425         g_free(name_);
2426         message = g_strdup_printf(_("Really delete news account `%s'?"), name);
2427         avalue = alertpanel(_("Delete news account"), message,
2428                             _("Yes"), _("+No"), NULL);
2429         g_free(message);
2430
2431         if (avalue != G_ALERTDEFAULT) return;
2432
2433         if (folderview->opened == folderview->selected ||
2434             gtk_ctree_is_ancestor(ctree,
2435                                   folderview->selected,
2436                                   folderview->opened)) {
2437                 summary_clear_all(folderview->summaryview);
2438                 folderview->opened = NULL;
2439         }
2440
2441         account = item->folder->account;
2442         folder_destroy(item->folder);
2443         account_destroy(account);
2444         gtk_ctree_remove_node(ctree, folderview->selected);
2445         account_set_menu();
2446         main_window_reflect_prefs_all();
2447         folder_write_list();
2448 }
2449
2450 static void folderview_search_cb(FolderView *folderview, guint action,
2451                                  GtkWidget *widget)
2452 {
2453         summary_search(folderview->summaryview);
2454 }
2455
2456 static void folderview_property_cb(FolderView *folderview, guint action,
2457                                    GtkWidget *widget)
2458 {
2459         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2460         FolderItem *item;
2461
2462         if (!folderview->selected) return;
2463
2464         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2465         g_return_if_fail(item != NULL);
2466         g_return_if_fail(item->folder != NULL);
2467
2468         if (item->parent == NULL && item->folder->account)
2469                 account_open(item->folder->account);
2470         else {
2471                 summary_save_prefs_to_folderitem(folderview->summaryview, item);
2472                 prefs_folder_item_create(folderview, item);
2473         }
2474 }
2475
2476 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2477 {
2478         GSList *list = NULL;
2479         GSList *done = NULL;
2480         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2481         
2482         for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2483                 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2484                 &&  list->data != node) {
2485                         gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2486                         done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2487                 }
2488         }
2489         for (list = done; list != NULL; list = g_slist_next(list)) {
2490                 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse, 
2491                                                                  list->data);
2492         }
2493         g_slist_free(done);
2494 }
2495
2496 static void folderview_move_to_cb(FolderView *folderview) 
2497 {
2498         FolderItem *from_folder = NULL, *to_folder = NULL;
2499
2500         if (folderview->selected)
2501                 from_folder = gtk_ctree_node_get_row_data(GTK_CTREE(folderview->ctree), folderview->selected);
2502         if (!from_folder || FOLDER_TYPE(from_folder->folder) == F_NEWS)
2503                 return;
2504
2505         to_folder = foldersel_folder_sel(from_folder->folder, FOLDER_SEL_MOVE, NULL);
2506         
2507         if (!to_folder || FOLDER_TYPE(to_folder->folder) == F_NEWS)
2508                 return;
2509
2510         folderview_move_to(folderview, from_folder, to_folder);
2511 }
2512
2513 static void folderview_move_to(FolderView *folderview, FolderItem *from_folder,
2514                                FolderItem *to_folder)
2515 {
2516         FolderItem *from_parent = NULL;
2517         FolderItem *new_folder = NULL;
2518         GtkCTreeNode *src_node = NULL;
2519         gchar *buf;
2520         gint status;
2521
2522         src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2523         from_parent = from_folder->parent;
2524         buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
2525         STATUSBAR_PUSH(folderview->mainwin, buf);
2526         g_free(buf);
2527         summary_clear_all(folderview->summaryview);
2528         folderview->opened = NULL;
2529         folderview->selected = NULL;
2530         gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2531         inc_lock();
2532         main_window_cursor_wait(folderview->mainwin);
2533         statusbar_verbosity_set(TRUE);
2534         folder_item_update_freeze();
2535         if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
2536                 statusbar_verbosity_set(FALSE);
2537                 main_window_cursor_normal(folderview->mainwin);
2538                 STATUSBAR_POP(folderview->mainwin);
2539                 folder_item_update_thaw();
2540                 if (src_node)
2541                         gtk_ctree_remove_node(GTK_CTREE(folderview->ctree), src_node);
2542                 else 
2543                         debug_print("can't remove src node: is null\n");
2544
2545                 folderview_create_folder_node_recursive(folderview, new_folder);
2546
2547                 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2548
2549                 folderview_sort_folders(folderview, 
2550                         gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), 
2551                                 NULL, new_folder->parent), new_folder->folder);
2552                 folderview_select(folderview, new_folder);
2553         } else {
2554                 statusbar_verbosity_set(FALSE);         
2555                 main_window_cursor_normal(folderview->mainwin);
2556                 STATUSBAR_POP(folderview->mainwin);
2557                 folder_item_update_thaw();
2558                 switch (status) {
2559                 case F_MOVE_FAILED_DEST_IS_PARENT:
2560                         alertpanel_error(_("Source and destination are the same."));
2561                         break;
2562                 case F_MOVE_FAILED_DEST_IS_CHILD:
2563                         alertpanel_error(_("Can't move a folder to one of its children."));
2564                         break;
2565                 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2566                         alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2567                         break;
2568                 default:
2569                         alertpanel_error(_("Move failed!"));
2570                         break;
2571                 }
2572         }       
2573         inc_unlock();           
2574         gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2575 }
2576
2577 static gint folderview_clist_compare(GtkCList *clist,
2578                                      gconstpointer ptr1, gconstpointer ptr2)
2579 {
2580         FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2581         FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2582
2583         if (!item1->name)
2584                 return (item2->name != NULL);
2585         if (!item2->name)
2586                 return -1;
2587
2588         return g_strcasecmp(item1->name, item2->name);
2589 }
2590
2591 static gint folderview_compare_name(gconstpointer a, gconstpointer b)
2592 {
2593         const FolderItem *item = a;
2594         const gchar *name = b;
2595
2596         if (!item->path) return -1;
2597         return strcmp2(g_basename(item->path), name);
2598 }
2599
2600 static void folderview_scoring_cb(FolderView *folderview, guint action,
2601                                    GtkWidget *widget)
2602 {
2603         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2604         FolderItem *item;
2605
2606         if (!folderview->selected) return;
2607
2608         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2609         g_return_if_fail(item != NULL);
2610         g_return_if_fail(item->folder != NULL);
2611
2612         prefs_scoring_open(item);
2613 }
2614
2615 static void folderview_processing_cb(FolderView *folderview, guint action,
2616                                      GtkWidget *widget)
2617 {
2618         GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2619         FolderItem *item;
2620
2621         if (!folderview->selected) return;
2622
2623         item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2624         g_return_if_fail(item != NULL);
2625         g_return_if_fail(item->folder != NULL);
2626
2627         prefs_filtering_open(item, NULL, NULL);
2628 }
2629
2630 void folderview_set_target_folder_color(gint color_op) 
2631 {
2632         gint firstone = 1;
2633         GList *list;
2634         FolderView *folderview;
2635
2636         for (list = folderview_list; list != NULL; list = list->next) {
2637                 folderview = (FolderView *)list->data;
2638                 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2639                 if (firstone) {
2640                         bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2641                                 folderview->color_op;
2642                         firstone = 0;
2643                 }
2644         }
2645 }
2646
2647 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2648 {
2649         folderview_init(folderview);
2650         folderview_set_all();
2651 }
2652
2653 static void drag_state_stop(FolderView *folderview)
2654 {
2655         if (folderview->drag_timer)
2656                 gtk_timeout_remove(folderview->drag_timer);
2657         folderview->drag_timer = 0;
2658         folderview->drag_node = NULL;
2659 }
2660
2661 static gint folderview_defer_expand(FolderView *folderview)
2662 {
2663         if (folderview->drag_node) {
2664                 folderview_recollapse_nodes(folderview, folderview->drag_node);
2665                 if (folderview->drag_item->collapsed) {
2666                         gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2667                         folderview->nodes_to_recollapse = g_slist_append
2668                                 (folderview->nodes_to_recollapse, folderview->drag_node);
2669                 }
2670         }
2671         folderview->drag_item  = NULL;
2672         folderview->drag_timer = 0;
2673         return FALSE;
2674 }
2675
2676 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2677 {
2678         /* the idea is that we call drag_state_start() whenever we want expansion to
2679          * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2680          * we need to call drag_state_stop() */
2681         drag_state_stop(folderview);
2682         /* request expansion */
2683         if (0 != (folderview->drag_timer = gtk_timeout_add
2684                         (prefs_common.hover_timeout, 
2685                          (GtkFunction)folderview_defer_expand,
2686                          folderview))) {
2687                 folderview->drag_node = node;
2688                 folderview->drag_item = item;
2689         }                        
2690 }
2691
2692 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2693                                   FolderView       *folderview)
2694 {
2695         GdkDragContext *context;
2696
2697         g_return_if_fail(folderview != NULL);
2698         if (folderview->selected == NULL) return;
2699
2700         folderview->nodes_to_recollapse = NULL; /* in case the last drag has been cancelled */
2701         
2702         context = gtk_drag_begin(widget, folderview->target_list,
2703                                  GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2704         gtk_drag_set_icon_default(context);
2705 }
2706
2707 static void folderview_drag_data_get(GtkWidget        *widget,
2708                                      GdkDragContext   *drag_context,
2709                                      GtkSelectionData *selection_data,
2710                                      guint             info,
2711                                      guint             time,
2712                                      FolderView       *folderview)
2713 {
2714         FolderItem *item;
2715         GList *cur;
2716         gchar *source=NULL;
2717         
2718         for (cur = GTK_CLIST(folderview->ctree)->selection;
2719              cur != NULL; cur = cur->next) {
2720                 item = gtk_ctree_node_get_row_data
2721                         (GTK_CTREE(folderview->ctree), 
2722                          GTK_CTREE_NODE(cur->data));
2723                 if (item) {
2724                         source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2725                         gtk_selection_data_set(selection_data,
2726                                                selection_data->target, 8,
2727                                                source, strlen(source));
2728                         break;
2729                 } else
2730                         return;
2731         }
2732 }
2733
2734 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2735 {
2736         FolderUpdateData *hookdata;
2737         FolderView *folderview;
2738         GtkWidget *ctree;
2739
2740         hookdata = source;
2741         folderview = (FolderView *) userdata;   
2742         g_return_val_if_fail(hookdata != NULL, FALSE);
2743         g_return_val_if_fail(folderview != NULL, FALSE);
2744
2745         ctree = folderview->ctree;
2746         g_return_val_if_fail(ctree != NULL, FALSE);
2747
2748         if (hookdata->update_flags & FOLDER_TREE_CHANGED) {
2749                 folderview_set(folderview);
2750         }
2751
2752         return FALSE;
2753 }
2754
2755 static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
2756                                           GdkDragContext *context,
2757                                           gint            x,
2758                                           gint            y,
2759                                           guint           time,
2760                                           FolderView     *folderview)
2761 {
2762         gint row, column;
2763         FolderItem *item, *src_item = NULL;
2764         GtkCTreeNode *node = NULL;
2765         gboolean acceptable = FALSE;
2766         gint height = folderview->ctree->allocation.height;
2767         gint total_height = folderview->ctree->requisition.height;
2768         GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2769                                 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2770         gfloat vpos = pos->value;
2771
2772         if (gtk_clist_get_selection_info
2773                 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2774                 if (y > height - 24 && height + vpos < total_height)
2775                         gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2776
2777                 if (y < 24 && y > 0)
2778                         gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2779
2780                 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2781                 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2782                 src_item = folderview->summaryview->folder_item;
2783
2784                 if (item && item->folder && item->path &&
2785                     src_item && src_item != item) {
2786                         switch (FOLDER_TYPE(item->folder)) {
2787                         case F_MH:
2788                         case F_MBOX:
2789                         case F_IMAP:
2790                                 acceptable = TRUE;
2791                                 break;
2792                         default:
2793                                 break;
2794                         }
2795                 } else if (item && item->folder && folder_item_get_path(item) &&
2796                            src_item && src_item != item) {
2797                         /* a root folder - acceptable only from folderview */
2798                         if (FOLDER_TYPE(item->folder) == F_MH || FOLDER_TYPE(item->folder) == F_IMAP)
2799                                 acceptable = TRUE;
2800                 }
2801                         
2802         }
2803
2804         if (acceptable || (src_item && src_item == item))
2805                 drag_state_start(folderview, node, item);
2806         
2807         if (acceptable) {
2808                 gtk_signal_handler_block_by_func
2809                         (GTK_OBJECT(widget),
2810                          GTK_SIGNAL_FUNC(folderview_selected), folderview);
2811                 gtk_ctree_select(GTK_CTREE(widget), node);
2812                 gtk_signal_handler_unblock_by_func
2813                         (GTK_OBJECT(widget),
2814                          GTK_SIGNAL_FUNC(folderview_selected), folderview);
2815                 gdk_drag_status(context, 
2816                                         (context->actions == GDK_ACTION_COPY ?
2817                                         GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2818         } else {
2819                 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2820                 gdk_drag_status(context, 0, time);
2821         }
2822
2823         return acceptable;
2824 }
2825
2826 static void folderview_drag_leave_cb(GtkWidget      *widget,
2827                                      GdkDragContext *context,
2828                                      guint           time,
2829                                      FolderView     *folderview)
2830 {
2831         drag_state_stop(folderview);
2832         gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2833 }
2834
2835 static void folderview_drag_received_cb(GtkWidget        *widget,
2836                                         GdkDragContext   *drag_context,
2837                                         gint              x,
2838                                         gint              y,
2839                                         GtkSelectionData *data,
2840                                         guint             info,
2841                                         guint             time,
2842                                         FolderView       *folderview)
2843 {
2844         gint row, column;
2845         FolderItem *item, *src_item;
2846         GtkCTreeNode *node;
2847
2848         drag_state_stop(folderview);
2849         if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2850                 /* comes from summaryview */
2851                 if (gtk_clist_get_selection_info
2852                         (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2853                         return;
2854
2855                 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2856                 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2857                 src_item = folderview->summaryview->folder_item;
2858                 
2859                 /* re-check (due to acceptable possibly set for folder moves */
2860                 if (!(item && item->folder && item->path &&
2861                       src_item && src_item != item && 
2862                       (FOLDER_TYPE(item->folder) == F_MH || FOLDER_TYPE(item->folder) == F_IMAP))) {
2863                         return;
2864                 }
2865                 if (item && src_item) {
2866                         switch (drag_context->action) {
2867                                 case GDK_ACTION_COPY:
2868                                         summary_copy_selected_to(folderview->summaryview, item);
2869                                         gtk_drag_finish(drag_context, TRUE, FALSE, time);
2870                                         break;
2871                                 case GDK_ACTION_MOVE:
2872                                 case GDK_ACTION_DEFAULT:
2873                                 default:
2874                         if (FOLDER_TYPE(src_item->folder) != FOLDER_TYPE(item->folder) ||
2875                             (FOLDER_TYPE(item->folder) == F_IMAP &&
2876                              src_item->folder != item->folder))
2877                                 summary_copy_selected_to(folderview->summaryview, item);
2878                         else
2879                                 summary_move_selected_to(folderview->summaryview, item);
2880                         gtk_drag_finish(drag_context, TRUE, TRUE, time);
2881                         }
2882                 } else
2883                         gtk_drag_finish(drag_context, FALSE, FALSE, time);
2884         } else {
2885                 /* comes from folderview */
2886                 char *source;
2887                 
2888                 source = data->data + 17;
2889                 if (gtk_clist_get_selection_info
2890                     (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2891                     || *source == 0) {
2892                         gtk_drag_finish(drag_context, FALSE, FALSE, time);                      
2893                         return;
2894                 }
2895                 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2896                 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2897                 src_item = folder_find_item_from_identifier(source);
2898
2899                 if (!item || !src_item || src_item->stype != F_NORMAL) {
2900                         gtk_drag_finish(drag_context, FALSE, FALSE, time);                      
2901                         return;
2902                 }
2903
2904                 folderview_move_to(folderview, src_item, item);
2905                 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2906         }
2907         folderview->nodes_to_recollapse = NULL;
2908 }
2909
2910 static void folderview_drag_end_cb(GtkWidget        *widget, 
2911                                    GdkDragContext   *drag_context,
2912                                    FolderView       *folderview)
2913 {
2914         drag_state_stop(folderview);
2915 }
2916