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