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