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