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