Statistics
| Revision:

root / src / folderview.c @ 1

History | View | Annotate | Download (65.6 KB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2004 Hiroyuki Yamamoto
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
 */
19

    
20
#include "defs.h"
21

    
22
#include <glib.h>
23
#include <gdk/gdkkeysyms.h>
24
#include <gtk/gtkwidget.h>
25
#include <gtk/gtkscrolledwindow.h>
26
#include <gtk/gtkctree.h>
27
#include <gtk/gtkcontainer.h>
28
#include <gtk/gtkclist.h>
29
#include <gtk/gtkstyle.h>
30
#include <gtk/gtksignal.h>
31
#include <gtk/gtkmain.h>
32
#include <gtk/gtkstatusbar.h>
33
#include <gtk/gtkmenu.h>
34
#include <gtk/gtkmenuitem.h>
35
#include <gtk/gtkitemfactory.h>
36
#include <stdio.h>
37
#include <string.h>
38
#include <stdlib.h>
39

    
40
#include "intl.h"
41
#include "main.h"
42
#include "mainwindow.h"
43
#include "folderview.h"
44
#include "summaryview.h"
45
#include "summary_search.h"
46
#include "inputdialog.h"
47
#include "grouplistdialog.h"
48
#include "manage_window.h"
49
#include "alertpanel.h"
50
#include "menu.h"
51
#include "stock_pixmap.h"
52
#include "statusbar.h"
53
#include "procmsg.h"
54
#include "utils.h"
55
#include "gtkutils.h"
56
#include "prefs_common.h"
57
#include "prefs_account.h"
58
#include "prefs_filter.h"
59
#include "prefs_folder_item.h"
60
#include "account.h"
61
#include "folder.h"
62
#include "inc.h"
63

    
64
typedef enum
65
{
66
        COL_FOLDER        = 0,
67
        COL_NEW                = 1,
68
        COL_UNREAD        = 2,
69
        COL_TOTAL        = 3
70
} FolderColumnPos;
71

    
72
#define N_FOLDER_COLS                4
73
#define COL_FOLDER_WIDTH        150
74
#define COL_NUM_WIDTH                32
75

    
76
#define STATUSBAR_PUSH(mainwin, str) \
77
{ \
78
        gtk_statusbar_push(GTK_STATUSBAR(mainwin->statusbar), \
79
                           mainwin->folderview_cid, str); \
80
        gtkut_widget_wait_for_draw(mainwin->hbox_stat); \
81
}
82

    
83
#define STATUSBAR_POP(mainwin) \
84
{ \
85
        gtk_statusbar_pop(GTK_STATUSBAR(mainwin->statusbar), \
86
                          mainwin->folderview_cid); \
87
}
88

    
89
static GList *folderview_list = NULL;
90

    
91
static GtkStyle *bold_style;
92
static GtkStyle *bold_color_style;
93

    
94
static GdkPixmap *inboxxpm;
95
static GdkBitmap *inboxxpmmask;
96
static GdkPixmap *outboxxpm;
97
static GdkBitmap *outboxxpmmask;
98
static GdkPixmap *folderxpm;
99
static GdkBitmap *folderxpmmask;
100
static GdkPixmap *folderopenxpm;
101
static GdkBitmap *folderopenxpmmask;
102
static GdkPixmap *foldernoselectxpm;
103
static GdkBitmap *foldernoselectxpmmask;
104
static GdkPixmap *trashxpm;
105
static GdkBitmap *trashxpmmask;
106

    
107
static void folderview_select_node         (FolderView        *folderview,
108
                                          GtkCTreeNode        *node);
109
static void folderview_set_folders         (FolderView        *folderview);
110
static void folderview_sort_folders         (FolderView        *folderview,
111
                                          GtkCTreeNode        *root,
112
                                          Folder        *folder);
113
static void folderview_append_folder         (FolderView        *folderview,
114
                                          Folder        *folder);
115
static void folderview_update_node         (FolderView        *folderview,
116
                                          GtkCTreeNode        *node);
117

    
118
static gint folderview_clist_compare        (GtkCList        *clist,
119
                                         gconstpointer         ptr1,
120
                                         gconstpointer         ptr2);
121

    
122
/* callback functions */
123
static gboolean folderview_button_pressed        (GtkWidget        *ctree,
124
                                                 GdkEventButton        *event,
125
                                                 FolderView        *folderview);
126
static gboolean folderview_button_released        (GtkWidget        *ctree,
127
                                                 GdkEventButton        *event,
128
                                                 FolderView        *folderview);
129

    
130
static gboolean folderview_key_pressed        (GtkWidget        *widget,
131
                                         GdkEventKey        *event,
132
                                         FolderView        *folderview);
133
static void folderview_selected                (GtkCTree        *ctree,
134
                                         GtkCTreeNode        *row,
135
                                         gint                 column,
136
                                         FolderView        *folderview);
137
static void folderview_tree_expanded        (GtkCTree        *ctree,
138
                                         GtkCTreeNode        *node,
139
                                         FolderView        *folderview);
140
static void folderview_tree_collapsed        (GtkCTree        *ctree,
141
                                         GtkCTreeNode        *node,
142
                                         FolderView        *folderview);
143
static void folderview_popup_close        (GtkMenuShell        *menu_shell,
144
                                         FolderView        *folderview);
145
static void folderview_col_resized        (GtkCList        *clist,
146
                                         gint                 column,
147
                                         gint                 width,
148
                                         FolderView        *folderview);
149

    
150
static void folderview_download_cb        (FolderView        *folderview,
151
                                         guint                 action,
152
                                         GtkWidget        *widget);
153

    
154
static void folderview_update_tree_cb        (FolderView        *folderview,
155
                                         guint                 action,
156
                                         GtkWidget        *widget);
157

    
158
static void folderview_new_folder_cb        (FolderView        *folderview,
159
                                         guint                 action,
160
                                         GtkWidget        *widget);
161
static void folderview_rename_folder_cb        (FolderView        *folderview,
162
                                         guint                 action,
163
                                         GtkWidget        *widget);
164
static void folderview_delete_folder_cb        (FolderView        *folderview,
165
                                         guint                 action,
166
                                         GtkWidget        *widget);
167
static void folderview_empty_trash_cb        (FolderView        *folderview,
168
                                         guint                 action,
169
                                         GtkWidget        *widget);
170
static void folderview_remove_mailbox_cb(FolderView        *folderview,
171
                                         guint                 action,
172
                                         GtkWidget        *widget);
173

    
174
static void folderview_rm_imap_server_cb (FolderView        *folderview,
175
                                          guint                 action,
176
                                          GtkWidget        *widget);
177

    
178
static void folderview_new_news_group_cb(FolderView        *folderview,
179
                                         guint                 action,
180
                                         GtkWidget        *widget);
181
static void folderview_rm_news_group_cb        (FolderView        *folderview,
182
                                         guint                 action,
183
                                         GtkWidget        *widget);
184
static void folderview_rm_news_server_cb(FolderView        *folderview,
185
                                         guint                 action,
186
                                         GtkWidget        *widget);
187

    
188
static void folderview_search_cb        (FolderView        *folderview,
189
                                         guint                 action,
190
                                         GtkWidget        *widget);
191

    
192
static void folderview_property_cb        (FolderView        *folderview,
193
                                         guint                 action,
194
                                         GtkWidget        *widget);
195

    
196
static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
197
                                          GdkDragContext *context,
198
                                          gint            x,
199
                                          gint            y,
200
                                          guint           time,
201
                                          FolderView     *folderview);
202
static void folderview_drag_leave_cb     (GtkWidget        *widget,
203
                                          GdkDragContext   *context,
204
                                          guint             time,
205
                                          FolderView       *folderview);
206
static void folderview_drag_received_cb  (GtkWidget        *widget,
207
                                          GdkDragContext   *context,
208
                                          gint              x,
209
                                          gint              y,
210
                                          GtkSelectionData *data,
211
                                          guint             info,
212
                                          guint             time,
213
                                          FolderView       *folderview);
214

    
215
static GtkItemFactoryEntry folderview_mail_popup_entries[] =
216
{
217
        {N_("/Create _new folder..."),        NULL, folderview_new_folder_cb,    0, NULL},
218
        {N_("/_Rename folder..."),        NULL, folderview_rename_folder_cb, 0, NULL},
219
        {N_("/_Delete folder"),                NULL, folderview_delete_folder_cb, 0, NULL},
220
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
221
        {N_("/Empty _trash"),                NULL, folderview_empty_trash_cb, 0, NULL},
222
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
223
        {N_("/_Check for new messages"),
224
                                        NULL, folderview_update_tree_cb, 0, NULL},
225
        {N_("/R_ebuild folder tree"),        NULL, folderview_update_tree_cb, 1, NULL},
226
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
227
        {N_("/_Search messages..."),        NULL, folderview_search_cb, 0, NULL},
228
        {N_("/_Properties..."),                NULL, folderview_property_cb, 0, NULL}
229
};
230

    
231
static GtkItemFactoryEntry folderview_imap_popup_entries[] =
232
{
233
        {N_("/Create _new folder..."),        NULL, folderview_new_folder_cb,    0, NULL},
234
        {N_("/_Rename folder..."),        NULL, folderview_rename_folder_cb, 0, NULL},
235
        {N_("/_Delete folder"),                NULL, folderview_delete_folder_cb, 0, NULL},
236
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
237
        {N_("/Empty _trash"),                NULL, folderview_empty_trash_cb, 0, NULL},
238
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
239
        {N_("/Down_load"),                NULL, folderview_download_cb, 0, NULL},
240
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
241
        {N_("/_Check for new messages"),
242
                                        NULL, folderview_update_tree_cb, 0, NULL},
243
        {N_("/R_ebuild folder tree"),        NULL, folderview_update_tree_cb, 1, NULL},
244
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
245
        {N_("/_Search messages..."),        NULL, folderview_search_cb, 0, NULL},
246
        {N_("/_Properties..."),                NULL, folderview_property_cb, 0, NULL}
247
};
248

    
249
static GtkItemFactoryEntry folderview_news_popup_entries[] =
250
{
251
        {N_("/Su_bscribe to newsgroup..."),
252
                                        NULL, folderview_new_news_group_cb, 0, NULL},
253
        {N_("/_Remove newsgroup"),        NULL, folderview_rm_news_group_cb, 0, NULL},
254
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
255
        {N_("/Down_load"),                NULL, folderview_download_cb, 0, NULL},
256
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
257
        {N_("/_Check for new messages"),
258
                                        NULL, folderview_update_tree_cb, 0, NULL},
259
        {N_("/---"),                        NULL, NULL, 0, "<Separator>"},
260
        {N_("/_Search messages..."),        NULL, folderview_search_cb, 0, NULL},
261
        {N_("/_Properties..."),                NULL, folderview_property_cb, 0, NULL}
262
};
263

    
264

    
265
FolderView *folderview_create(void)
266
{
267
        FolderView *folderview;
268
        GtkWidget *scrolledwin;
269
        GtkWidget *ctree;
270
        gchar *titles[N_FOLDER_COLS];
271
        GtkWidget *mail_popup;
272
        GtkWidget *news_popup;
273
        GtkWidget *imap_popup;
274
        GtkItemFactory *mail_factory;
275
        GtkItemFactory *news_factory;
276
        GtkItemFactory *imap_factory;
277
        gint n_entries;
278
        gint i;
279

    
280
        debug_print(_("Creating folder view...\n"));
281
        folderview = g_new0(FolderView, 1);
282

    
283
        titles[COL_FOLDER] = _("Folder");
284
        titles[COL_NEW]    = _("New");
285
        titles[COL_UNREAD] = _("Unread");
286
        titles[COL_TOTAL]  = _("#");
287

    
288
        scrolledwin = gtk_scrolled_window_new(NULL, NULL);
289
        gtk_scrolled_window_set_policy
290
                (GTK_SCROLLED_WINDOW(scrolledwin),
291
                 GTK_POLICY_AUTOMATIC,
292
                 prefs_common.folderview_vscrollbar_policy);
293
        gtk_widget_set_size_request(scrolledwin,
294
                                    prefs_common.folderview_width,
295
                                    prefs_common.folderview_height);
296

    
297
        ctree = gtk_ctree_new_with_titles(N_FOLDER_COLS, COL_FOLDER, titles);
298
        gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
299
        gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
300
        gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_NEW,
301
                                           GTK_JUSTIFY_RIGHT);
302
        gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_UNREAD,
303
                                           GTK_JUSTIFY_RIGHT);
304
        gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_TOTAL,
305
                                           GTK_JUSTIFY_RIGHT);
306
        gtk_clist_set_column_width(GTK_CLIST(ctree), COL_FOLDER,
307
                                   prefs_common.folder_col_folder);
308
        gtk_clist_set_column_width(GTK_CLIST(ctree), COL_NEW,
309
                                   prefs_common.folder_col_new);
310
        gtk_clist_set_column_width(GTK_CLIST(ctree), COL_UNREAD,        
311
                                   prefs_common.folder_col_unread);
312
        gtk_clist_set_column_width(GTK_CLIST(ctree), COL_TOTAL,
313
                                   prefs_common.folder_col_total);
314
        gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
315
        gtk_ctree_set_expander_style(GTK_CTREE(ctree),
316
                                     GTK_CTREE_EXPANDER_SQUARE);
317
        gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
318
        gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
319

    
320
        /* don't let title buttons take key focus */
321
        for (i = 0; i < N_FOLDER_COLS; i++)
322
                GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
323
                                       GTK_CAN_FOCUS);
324

    
325
        /* popup menu */
326
        n_entries = sizeof(folderview_mail_popup_entries) /
327
                sizeof(folderview_mail_popup_entries[0]);
328
        mail_popup = menu_create_items(folderview_mail_popup_entries,
329
                                       n_entries,
330
                                       "<MailFolder>", &mail_factory,
331
                                       folderview);
332
        n_entries = sizeof(folderview_imap_popup_entries) /
333
                sizeof(folderview_imap_popup_entries[0]);
334
        imap_popup = menu_create_items(folderview_imap_popup_entries,
335
                                       n_entries,
336
                                       "<IMAPFolder>", &imap_factory,
337
                                       folderview);
338
        n_entries = sizeof(folderview_news_popup_entries) /
339
                sizeof(folderview_news_popup_entries[0]);
340
        news_popup = menu_create_items(folderview_news_popup_entries,
341
                                       n_entries,
342
                                       "<NewsFolder>", &news_factory,
343
                                       folderview);
344

    
345
        g_signal_connect(G_OBJECT(ctree), "key_press_event",
346
                         G_CALLBACK(folderview_key_pressed),
347
                         folderview);
348
        g_signal_connect(G_OBJECT(ctree), "button_press_event",
349
                         G_CALLBACK(folderview_button_pressed),
350
                         folderview);
351
        g_signal_connect(G_OBJECT(ctree), "button_release_event",
352
                         G_CALLBACK(folderview_button_released),
353
                         folderview);
354
        g_signal_connect(G_OBJECT(ctree), "tree_select_row",
355
                         G_CALLBACK(folderview_selected), folderview);
356

    
357
        g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
358
                               G_CALLBACK(folderview_tree_expanded),
359
                               folderview);
360
        g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
361
                               G_CALLBACK(folderview_tree_collapsed),
362
                               folderview);
363

    
364
        g_signal_connect(G_OBJECT(ctree), "resize_column",
365
                         G_CALLBACK(folderview_col_resized), folderview);
366

    
367
        g_signal_connect(G_OBJECT(mail_popup), "selection_done",
368
                         G_CALLBACK(folderview_popup_close), folderview);
369
        g_signal_connect(G_OBJECT(imap_popup), "selection_done",
370
                         G_CALLBACK(folderview_popup_close), folderview);
371
        g_signal_connect(G_OBJECT(news_popup), "selection_done",
372
                         G_CALLBACK(folderview_popup_close), folderview);
373

    
374
        /* drop callback */
375
        gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL &
376
                          ~GTK_DEST_DEFAULT_HIGHLIGHT,
377
                          summary_drag_types, 1,
378
                          GDK_ACTION_MOVE | GDK_ACTION_COPY);
379
        g_signal_connect(G_OBJECT(ctree), "drag_motion",
380
                         G_CALLBACK(folderview_drag_motion_cb), folderview);
381
        g_signal_connect(G_OBJECT(ctree), "drag_leave",
382
                         G_CALLBACK(folderview_drag_leave_cb), folderview);
383
        g_signal_connect(G_OBJECT(ctree), "drag_data_received",
384
                         G_CALLBACK(folderview_drag_received_cb), folderview);
385

    
386
        folderview->scrolledwin  = scrolledwin;
387
        folderview->ctree        = ctree;
388
        folderview->mail_popup   = mail_popup;
389
        folderview->mail_factory = mail_factory;
390
        folderview->imap_popup   = imap_popup;
391
        folderview->imap_factory = imap_factory;
392
        folderview->news_popup   = news_popup;
393
        folderview->news_factory = news_factory;
394

    
395
        gtk_widget_show_all(scrolledwin);
396

    
397
        folderview_list = g_list_append(folderview_list, folderview);
398

    
399
        return folderview;
400
}
401

    
402
void folderview_init(FolderView *folderview)
403
{
404
        GtkWidget *ctree = folderview->ctree;
405

    
406
        gtk_widget_realize(ctree);
407
        stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX, &inboxxpm, &inboxxpmmask);
408
        stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX,
409
                         &outboxxpm, &outboxxpmmask);
410
        stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE,
411
                         &folderxpm, &folderxpmmask);
412
        stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN,
413
                         &folderopenxpm, &folderopenxpmmask);
414
        stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT,
415
                         &foldernoselectxpm, &foldernoselectxpmmask);
416
        stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH, &trashxpm, &trashxpmmask);
417

    
418
        if (!bold_style) {
419
                PangoFontDescription *font_desc;
420
                bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
421
                font_desc = pango_font_description_from_string
422
                        (prefs_common.boldfont);
423
                if (font_desc) {
424
                        if (bold_style->font_desc)
425
                                pango_font_description_free
426
                                        (bold_style->font_desc);
427
                        bold_style->font_desc = font_desc;
428
                }
429
                bold_color_style = gtk_style_copy(bold_style);
430
                bold_color_style->fg[GTK_STATE_NORMAL] = folderview->color_new;
431
        }
432
}
433

    
434
void folderview_set(FolderView *folderview)
435
{
436
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
437
        MainWindow *mainwin = folderview->mainwin;
438

    
439
        debug_print(_("Setting folder info...\n"));
440
        STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
441

    
442
        main_window_cursor_wait(mainwin);
443

    
444
        folderview->selected = NULL;
445
        folderview->opened = NULL;
446

    
447
        gtk_clist_freeze(GTK_CLIST(ctree));
448
        gtk_clist_clear(GTK_CLIST(ctree));
449
        gtk_clist_thaw(GTK_CLIST(ctree));
450
        gtk_clist_freeze(GTK_CLIST(ctree));
451

    
452
        folderview_set_folders(folderview);
453

    
454
        gtk_clist_thaw(GTK_CLIST(ctree));
455
        main_window_cursor_normal(mainwin);
456
        STATUSBAR_POP(mainwin);
457
}
458

    
459
void folderview_set_all(void)
460
{
461
        GList *list;
462

    
463
        for (list = folderview_list; list != NULL; list = list->next)
464
                folderview_set((FolderView *)list->data);
465
}
466

    
467
void folderview_select(FolderView *folderview, FolderItem *item)
468
{
469
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
470
        GtkCTreeNode *node;
471

    
472
        if (!item) return;
473

    
474
        node = gtk_ctree_find_by_row_data(ctree, NULL, item);
475
        if (node) folderview_select_node(folderview, node);
476
}
477

    
478
static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
479
{
480
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
481

    
482
        g_return_if_fail(node != NULL);
483

    
484
        folderview->open_folder = TRUE;
485
        gtkut_ctree_set_focus_row(ctree, node);
486
        gtk_ctree_select(ctree, node);
487
        if (folderview->summaryview->folder_item &&
488
            folderview->summaryview->folder_item->total > 0)
489
                gtk_widget_grab_focus(folderview->summaryview->ctree);
490
        else
491
                gtk_widget_grab_focus(folderview->ctree);
492

    
493
        gtkut_ctree_expand_parent_all(ctree, node);
494
}
495

    
496
void folderview_unselect(FolderView *folderview)
497
{
498
        if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
499
                gtk_ctree_collapse
500
                        (GTK_CTREE(folderview->ctree), folderview->opened);
501

    
502
        folderview->selected = folderview->opened = NULL;
503
}
504

    
505
static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
506
                                                 GtkCTreeNode *node)
507
{
508
        FolderItem *item;
509

    
510
        if (node)
511
                node = gtkut_ctree_node_next(ctree, node);
512
        else
513
                node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
514

    
515
        for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
516
                item = gtk_ctree_node_get_row_data(ctree, node);
517
                if (item && item->unread > 0 && item->stype != F_TRASH)
518
                        return node;
519
        }
520

    
521
        return NULL;
522
}
523

    
524
void folderview_select_next_unread(FolderView *folderview)
525
{
526
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
527
        GtkCTreeNode *node = NULL;
528

    
529
        if ((node = folderview_find_next_unread(ctree, folderview->opened))
530
            != NULL) {
531
                folderview_select_node(folderview, node);
532
                return;
533
        }
534

    
535
        if (!folderview->opened ||
536
            folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list))
537
                return;
538
        /* search again from the first node */
539
        if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
540
                folderview_select_node(folderview, node);
541
}
542

    
543
FolderItem *folderview_get_selected_item(FolderView *folderview)
544
{
545
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
546

    
547
        if (!folderview->selected) return NULL;
548
        return gtk_ctree_node_get_row_data(ctree, folderview->selected);
549
}
550

    
551
void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
552
{
553
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
554
        static GtkCTreeNode *prev_row = NULL;
555
        FolderItem *item;
556
        gint new, unread, total;
557
        gchar *new_str, *unread_str, *total_str;
558

    
559
        if (!row) return;
560

    
561
        item = gtk_ctree_node_get_row_data(ctree, row);
562
        if (!item) return;
563

    
564
        gtk_ctree_node_get_text(ctree, row, COL_NEW, &new_str);
565
        gtk_ctree_node_get_text(ctree, row, COL_UNREAD, &unread_str);
566
        gtk_ctree_node_get_text(ctree, row, COL_TOTAL, &total_str);
567
        new = atoi(new_str);
568
        unread = atoi(unread_str);
569
        total = atoi(total_str);
570

    
571
        if (prev_row     == row    &&
572
            item->new    == new    &&
573
            item->unread == unread &&
574
            item->total  == total)
575
                return;
576

    
577
        prev_row = row;
578

    
579
        folderview_update_node(folderview, row);
580
}
581

    
582
void folderview_append_item(FolderItem *item)
583
{
584
        FolderItem *parent;
585
        GList *list;
586

    
587
        g_return_if_fail(item != NULL);
588
        g_return_if_fail(item->folder != NULL);
589
        g_return_if_fail(item->parent != NULL);
590

    
591
        parent = item->parent;
592

    
593
        for (list = folderview_list; list != NULL; list = list->next) {
594
                FolderView *folderview = (FolderView *)list->data;
595
                GtkCTree *ctree = GTK_CTREE(folderview->ctree);
596
                GtkCTreeNode *node, *child;
597

    
598
                node = gtk_ctree_find_by_row_data(ctree, NULL, parent);
599
                if (node) {
600
                        child = gtk_ctree_find_by_row_data(ctree, node, item);
601
                        if (!child) {
602
                                gchar *text[N_FOLDER_COLS] =
603
                                        {NULL, "0", "0", "0"};
604

    
605
                                gtk_clist_freeze(GTK_CLIST(ctree));
606

    
607
                                text[COL_FOLDER] = item->name;
608
                                child = gtk_ctree_insert_node
609
                                        (ctree, node, NULL, text,
610
                                         FOLDER_SPACING,
611
                                         folderxpm, folderxpmmask,
612
                                         folderopenxpm, folderopenxpmmask,
613
                                         FALSE, FALSE);
614
                                gtk_ctree_node_set_row_data(ctree, child, item);
615
                                gtk_ctree_expand(ctree, node);
616
                                folderview_update_node(folderview, child);
617
                                folderview_sort_folders(folderview, node,
618
                                                        item->folder);
619

    
620
                                gtk_clist_thaw(GTK_CLIST(ctree));
621
                        }
622
                }
623
        }
624
}
625

    
626
static void folderview_set_folders(FolderView *folderview)
627
{
628
        GList *list;
629

    
630
        list = folder_get_list();
631

    
632
        for (; list != NULL; list = list->next)
633
                folderview_append_folder(folderview, FOLDER(list->data));
634
}
635

    
636
static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
637
                                      gpointer data)
638
{
639
        GList *list;
640
        gchar *rootpath;
641

    
642
        if (FOLDER_IS_LOCAL(folder))
643
                rootpath = LOCAL_FOLDER(folder)->rootpath;
644
        else if (FOLDER_TYPE(folder) == F_IMAP && folder->account &&
645
                 folder->account->recv_server)
646
                rootpath = folder->account->recv_server;
647
        else if (FOLDER_TYPE(folder) == F_NEWS && folder->account &&
648
                 folder->account->nntp_server)
649
                rootpath = folder->account->nntp_server;
650
        else
651
                return;
652

    
653
        for (list = folderview_list; list != NULL; list = list->next) {
654
                FolderView *folderview = (FolderView *)list->data;
655
                MainWindow *mainwin = folderview->mainwin;
656
                gchar *str;
657

    
658
                if (item->path)
659
                        str = g_strdup_printf(_("Scanning folder %s%c%s ..."),
660
                                              rootpath, G_DIR_SEPARATOR,
661
                                              item->path);
662
                else
663
                        str = g_strdup_printf(_("Scanning folder %s ..."),
664
                                              rootpath);
665

    
666
                STATUSBAR_PUSH(mainwin, str);
667
                STATUSBAR_POP(mainwin);
668
                g_free(str);
669
        }
670
}
671

    
672
static GtkWidget *label_window_create(const gchar *str)
673
{
674
        GtkWidget *window;
675
        GtkWidget *label;
676

    
677
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
678
        gtk_widget_set_size_request(window, 380, 60);
679
        gtk_container_set_border_width(GTK_CONTAINER(window), 8);
680
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
681
        gtk_window_set_title(GTK_WINDOW(window), str);
682
        gtk_window_set_modal(GTK_WINDOW(window), TRUE);
683
        gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
684
        manage_window_set_transient(GTK_WINDOW(window));
685

    
686
        label = gtk_label_new(str);
687
        gtk_container_add(GTK_CONTAINER(window), label);
688
        gtk_widget_show(label);
689

    
690
        gtk_widget_show_now(window);
691

    
692
        return window;
693
}
694

    
695
static void folderview_rescan_tree(FolderView *folderview, Folder *folder)
696
{
697
        GtkWidget *window;
698
        AlertValue avalue;
699

    
700
        g_return_if_fail(folder != NULL);
701

    
702
        if (!folder->klass->scan_tree) return;
703

    
704
        avalue = alertpanel
705
                (_("Rebuild folder tree"),
706
                 _("The folder tree will be rebuilt. Continue?"),
707
                 _("Yes"), _("No"), NULL);
708
        if (avalue != G_ALERTDEFAULT) return;
709

    
710
        if (!FOLDER_IS_LOCAL(folder) &&
711
            !main_window_toggle_online_if_offline(folderview->mainwin))
712
                return;
713

    
714
        inc_lock();
715
        window = label_window_create(_("Rebuilding folder tree..."));
716

    
717
        summary_show(folderview->summaryview, NULL, FALSE);
718

    
719
        folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
720
        if (folder->klass->scan_tree(folder) < 0)
721
                alertpanel_error(_("Rebuilding of the folder tree failed."));
722
        folder_set_ui_func(folder, NULL, NULL);
723

    
724
        folder_write_list();
725
        folderview_set_all();
726
        statusbar_pop_all();
727

    
728
        gtk_widget_destroy(window);
729
        inc_unlock();
730
}
731

    
732
#if 0
733
void folderview_rescan_all(void)
734
{
735
        GList *list;
736
        GtkWidget *window;
737

738
        inc_lock();
739
        window = label_window_create(_("Rebuilding all folder trees..."));
740

741
        list = folder_get_list();
742
        for (; list != NULL; list = list->next) {
743
                Folder *folder = list->data;
744

745
                if (!folder->klass->scan_tree) continue;
746
                folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
747
                folder->klass->scan_tree(folder);
748
                folder_set_ui_func(folder, NULL, NULL);
749
        }
750

751
        folder_write_list();
752
        folderview_set_all();
753
        gtk_widget_destroy(window);
754
        inc_unlock();
755
}
756
#endif
757

    
758
void folderview_check_new(Folder *folder)
759
{
760
        GList *list;
761
        FolderItem *item;
762
        FolderView *folderview;
763
        GtkCTree *ctree;
764
        GtkCTreeNode *node;
765

    
766
        for (list = folderview_list; list != NULL; list = list->next) {
767
                folderview = (FolderView *)list->data;
768
                ctree = GTK_CTREE(folderview->ctree);
769

    
770
                if (folder && !FOLDER_IS_LOCAL(folder)) {
771
                        if (!main_window_toggle_online_if_offline
772
                                (folderview->mainwin))
773
                                return;
774
                }
775

    
776
                inc_lock();
777
                main_window_lock(folderview->mainwin);
778
                gtk_widget_set_sensitive(folderview->ctree, FALSE);
779

    
780
                for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
781
                     node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
782
                        item = gtk_ctree_node_get_row_data(ctree, node);
783
                        if (!item || !item->path || !item->folder) continue;
784
                        if (item->no_select) continue;
785
                        if (folder && folder != item->folder) continue;
786
                        if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
787

    
788
                        folderview_scan_tree_func(item->folder, item, NULL);
789
                        if (folder_item_scan(item) < 0) {
790
                                if (folder && !FOLDER_IS_LOCAL(folder))
791
                                        break;
792
                        }
793
                        folderview_update_node(folderview, node);
794
                }
795

    
796
                gtk_widget_set_sensitive(folderview->ctree, TRUE);
797
                main_window_unlock(folderview->mainwin);
798
                inc_unlock();
799
                statusbar_pop_all();
800
        }
801

    
802
        folder_write_list();
803
}
804

    
805
void folderview_check_new_all(void)
806
{
807
        GList *list;
808
        GtkWidget *window;
809
        FolderView *folderview;
810

    
811
        folderview = (FolderView *)folderview_list->data;
812

    
813
        inc_lock();
814
        main_window_lock(folderview->mainwin);
815
        window = label_window_create
816
                (_("Checking for new messages in all folders..."));
817

    
818
        list = folder_get_list();
819
        for (; list != NULL; list = list->next) {
820
                Folder *folder = list->data;
821

    
822
                folderview_check_new(folder);
823
        }
824

    
825
        gtk_widget_destroy(window);
826
        main_window_unlock(folderview->mainwin);
827
        inc_unlock();
828
}
829

    
830
static gboolean folderview_search_new_recursive(GtkCTree *ctree,
831
                                                GtkCTreeNode *node)
832
{
833
        FolderItem *item;
834

    
835
        if (node) {
836
                item = gtk_ctree_node_get_row_data(ctree, node);
837
                if (item) {
838
                        if (item->new > 0 ||
839
                            (item->stype == F_QUEUE && item->total > 0))
840
                                return TRUE;
841
                }
842
                node = GTK_CTREE_ROW(node)->children;
843
        } else
844
                node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
845

    
846
        while (node) {
847
                if (folderview_search_new_recursive(ctree, node) == TRUE)
848
                        return TRUE;
849
                node = GTK_CTREE_ROW(node)->sibling;
850
        }
851

    
852
        return FALSE;
853
}
854

    
855
static gboolean folderview_have_new_children(FolderView *folderview,
856
                                             GtkCTreeNode *node)
857
{
858
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
859

    
860
        if (!node)
861
                node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
862
        if (!node)
863
                return FALSE;
864

    
865
        node = GTK_CTREE_ROW(node)->children;
866

    
867
        while (node) {
868
                if (folderview_search_new_recursive(ctree, node) == TRUE)
869
                        return TRUE;
870
                node = GTK_CTREE_ROW(node)->sibling;
871
        }
872

    
873
        return FALSE;
874
}
875

    
876
static gboolean folderview_search_unread_recursive(GtkCTree *ctree,
877
                                                   GtkCTreeNode *node)
878
{
879
        FolderItem *item;
880

    
881
        if (node) {
882
                item = gtk_ctree_node_get_row_data(ctree, node);
883
                if (item) {
884
                        if (item->unread > 0 ||
885
                            (item->stype == F_QUEUE && item->total > 0))
886
                                return TRUE;
887
                }
888
                node = GTK_CTREE_ROW(node)->children;
889
        } else
890
                node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
891

    
892
        while (node) {
893
                if (folderview_search_unread_recursive(ctree, node) == TRUE)
894
                        return TRUE;
895
                node = GTK_CTREE_ROW(node)->sibling;
896
        }
897

    
898
        return FALSE;
899
}
900

    
901
static gboolean folderview_have_unread_children(FolderView *folderview,
902
                                                GtkCTreeNode *node)
903
{
904
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
905

    
906
        if (!node)
907
                node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
908
        if (!node)
909
                return FALSE;
910

    
911
        node = GTK_CTREE_ROW(node)->children;
912

    
913
        while (node) {
914
                if (folderview_search_unread_recursive(ctree, node) == TRUE)
915
                        return TRUE;
916
                node = GTK_CTREE_ROW(node)->sibling;
917
        }
918

    
919
        return FALSE;
920
}
921

    
922
static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
923
{
924
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
925
        GtkStyle *style = NULL;
926
        FolderItem *item;
927
        GdkPixmap *xpm, *openxpm;
928
        GdkBitmap *mask, *openmask;
929
        gchar *name;
930
        gchar *str;
931
        gboolean add_unread_mark;
932
        gboolean use_bold, use_color;
933

    
934
        item = gtk_ctree_node_get_row_data(ctree, node);
935
        g_return_if_fail(item != NULL);
936

    
937
        switch (item->stype) {
938
        case F_INBOX:
939
                xpm = openxpm = inboxxpm;
940
                mask = openmask = inboxxpmmask;
941
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
942
                                !strcmp2(item->name, INBOX_DIR) ? _("Inbox") :
943
                                item->name);
944
                break;
945
        case F_OUTBOX:
946
                xpm = openxpm = outboxxpm;
947
                mask = openmask = outboxxpmmask;
948
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
949
                                !strcmp2(item->name, OUTBOX_DIR) ? _("Sent") :
950
                                item->name);
951
                break;
952
        case F_QUEUE:
953
                xpm = openxpm = outboxxpm;
954
                mask = openmask = outboxxpmmask;
955
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
956
                                !strcmp2(item->name, QUEUE_DIR) ? _("Queue") :
957
                                item->name);
958
                break;
959
        case F_TRASH:
960
                xpm = openxpm = trashxpm;
961
                mask = openmask = trashxpmmask;
962
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
963
                                !strcmp2(item->name, TRASH_DIR) ? _("Trash") :
964
                                item->name);
965
                break;
966
        case F_DRAFT:
967
                xpm = folderxpm;
968
                mask = folderxpmmask;
969
                openxpm = folderopenxpm;
970
                openmask = folderopenxpmmask;
971
                name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
972
                                !strcmp2(item->name, DRAFT_DIR) ? _("Drafts") :
973
                                item->name);
974
                break;
975
        default:
976
                if (item->no_select) {
977
                        xpm = openxpm = foldernoselectxpm;
978
                        mask = openmask = foldernoselectxpmmask;
979
                } else {
980
                        xpm = folderxpm;
981
                        mask = folderxpmmask;
982
                        openxpm = folderopenxpm;
983
                        openmask = folderopenxpmmask;
984
                }
985

    
986
                if (!item->parent) {
987
                        switch (FOLDER_TYPE(item->folder)) {
988
                        case F_MH:
989
                                name = " (MH)"; break;
990
                        case F_IMAP:
991
                                name = " (IMAP4)"; break;
992
                        case F_NEWS:
993
                                name = " (News)"; break;
994
                        default:
995
                                name = "";
996
                        }
997
                        name = g_strconcat(item->name, name, NULL);
998
                } else {
999
                        if (FOLDER_TYPE(item->folder) == F_NEWS &&
1000
                            item->path &&
1001
                            !strcmp2(item->name, item->path))
1002
                                name = get_abbrev_newsgroup_name
1003
                                        (item->path,
1004
                                         prefs_common.ng_abbrev_len);
1005
                        else
1006
                                name = g_strdup(item->name);
1007
                }
1008
        }
1009

    
1010
        if (!GTK_CTREE_ROW(node)->expanded &&
1011
            folderview_have_unread_children(folderview, node))
1012
                add_unread_mark = TRUE;
1013
        else
1014
                add_unread_mark = FALSE;
1015

    
1016
        if (item->stype == F_QUEUE && item->total > 0 &&
1017
            prefs_common.display_folder_unread) {
1018
                str = g_strdup_printf("%s (%d%s)", name, item->total,
1019
                                      add_unread_mark ? "+" : "");
1020
                gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1021
                                        xpm, mask, openxpm, openmask,
1022
                                        FALSE, GTK_CTREE_ROW(node)->expanded);
1023
                g_free(str);
1024
        } else if ((item->unread > 0 || add_unread_mark) &&
1025
                 prefs_common.display_folder_unread) {
1026

    
1027
                if (item->unread > 0)
1028
                        str = g_strdup_printf("%s (%d%s)", name, item->unread,
1029
                                              add_unread_mark ? "+" : "");
1030
                else
1031
                        str = g_strdup_printf("%s (+)", name);
1032
                gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1033
                                        xpm, mask, openxpm, openmask,
1034
                                        FALSE, GTK_CTREE_ROW(node)->expanded);
1035
                g_free(str);
1036
        } else
1037
                gtk_ctree_set_node_info(ctree, node, name, FOLDER_SPACING,
1038
                                        xpm, mask, openxpm, openmask,
1039
                                        FALSE, GTK_CTREE_ROW(node)->expanded);
1040
        g_free(name);
1041

    
1042
        if (!item->parent) {
1043
                gtk_ctree_node_set_text(ctree, node, COL_NEW,    "-");
1044
                gtk_ctree_node_set_text(ctree, node, COL_UNREAD, "-");
1045
                gtk_ctree_node_set_text(ctree, node, COL_TOTAL,  "-");
1046
        } else {
1047
                gtk_ctree_node_set_text(ctree, node, COL_NEW,    itos(item->new));
1048
                gtk_ctree_node_set_text(ctree, node, COL_UNREAD, itos(item->unread));
1049
                gtk_ctree_node_set_text(ctree, node, COL_TOTAL,  itos(item->total));
1050
        }
1051

    
1052
        if (item->stype == F_OUTBOX || item->stype == F_DRAFT ||
1053
            item->stype == F_TRASH) {
1054
                use_bold = use_color = FALSE;
1055
        } else if (item->stype == F_QUEUE) {
1056
                /* highlight queue folder if there are any messages */
1057
                use_bold = use_color = (item->total > 0);
1058
        } else {
1059
                /* if unread messages exist, print with bold font */
1060
                use_bold = (item->unread > 0) || add_unread_mark;
1061
                /* if new messages exist, print with colored letter */
1062
                use_color =
1063
                        (item->new > 0) ||
1064
                        (add_unread_mark &&
1065
                         folderview_have_new_children(folderview, node));
1066
        }
1067

    
1068
        gtk_ctree_node_set_foreground(ctree, node, NULL);
1069

    
1070
        if (item->no_select)
1071
                gtk_ctree_node_set_foreground(ctree, node,
1072
                                              &folderview->color_noselect);
1073
        else if (use_bold && use_color)
1074
                style = bold_color_style;
1075
        else if (use_bold)
1076
                style = bold_style;
1077
        else if (use_color)
1078
                gtk_ctree_node_set_foreground(ctree, node,
1079
                                              &folderview->color_new);
1080

    
1081
        gtk_ctree_node_set_row_style(ctree, node, style);
1082

    
1083
        item->updated = FALSE;
1084

    
1085
        if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1086
                folderview_update_node(folderview, node);
1087
}
1088

    
1089
void folderview_update_item(FolderItem *item, gboolean update_summary)
1090
{
1091
        GList *list;
1092
        FolderView *folderview;
1093
        GtkCTree *ctree;
1094
        GtkCTreeNode *node;
1095

    
1096
        g_return_if_fail(item != NULL);
1097

    
1098
        for (list = folderview_list; list != NULL; list = list->next) {
1099
                folderview = (FolderView *)list->data;
1100
                ctree = GTK_CTREE(folderview->ctree);
1101

    
1102
                node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1103
                if (node) {
1104
                        folderview_update_node(folderview, node);
1105
                        if (update_summary && folderview->opened == node)
1106
                                summary_show(folderview->summaryview,
1107
                                             item, FALSE);
1108
                }
1109
        }
1110
}
1111

    
1112
static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1113
                                                gpointer data)
1114
{
1115
        folderview_update_item((FolderItem *)key, GPOINTER_TO_INT(data));
1116
}
1117

    
1118
void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1119
{
1120
        g_hash_table_foreach(table, folderview_update_item_foreach_func,
1121
                             GINT_TO_POINTER(update_summary));
1122
}
1123

    
1124
static gboolean folderview_update_all_updated_func(GNode *node, gpointer data)
1125
{
1126
        FolderItem *item;
1127

    
1128
        item = FOLDER_ITEM(node->data);
1129
        if (item->updated) {
1130
                debug_print("folderview_update_all_updated(): '%s' is updated\n", item->path);
1131
                folderview_update_item(item, GPOINTER_TO_INT(data));
1132
        }
1133

    
1134
        return FALSE;
1135
}
1136

    
1137
void folderview_update_all_updated(gboolean update_summary)
1138
{
1139
        GList *list;
1140
        Folder *folder;
1141

    
1142
        for (list = folder_get_list(); list != NULL; list = list->next) {
1143
                folder = (Folder *)list->data;
1144
                g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1145
                                folderview_update_all_updated_func,
1146
                                GINT_TO_POINTER(update_summary));
1147
        }
1148
}
1149

    
1150
static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1151
                                      GNode *gnode, GtkCTreeNode *cnode,
1152
                                      gpointer data)
1153
{
1154
        FolderView *folderview = (FolderView *)data;
1155
        FolderItem *item = FOLDER_ITEM(gnode->data);
1156

    
1157
        g_return_val_if_fail(item != NULL, FALSE);
1158

    
1159
        gtk_ctree_node_set_row_data(ctree, cnode, item);
1160
        folderview_update_node(folderview, cnode);
1161

    
1162
        return TRUE;
1163
}
1164

    
1165
static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1166
                                   gpointer data)
1167
{
1168
        FolderView *folderview = (FolderView *)data;
1169
        FolderItem *item;
1170

    
1171
        if (GTK_CTREE_ROW(node)->children) {
1172
                item = gtk_ctree_node_get_row_data(ctree, node);
1173
                g_return_if_fail(item != NULL);
1174

    
1175
                if (!item->collapsed)
1176
                        gtk_ctree_expand(ctree, node);
1177
                else
1178
                        folderview_update_node(folderview, node);
1179
        }
1180
}
1181

    
1182
#define SET_SPECIAL_FOLDER(ctree, item) \
1183
{ \
1184
        if (item) { \
1185
                GtkCTreeNode *node, *parent, *sibling; \
1186
 \
1187
                node = gtk_ctree_find_by_row_data(ctree, root, item); \
1188
                if (!node) \
1189
                        g_warning("%s not found.\n", item->path); \
1190
                else { \
1191
                        parent = GTK_CTREE_ROW(node)->parent; \
1192
                        if (prev && parent == GTK_CTREE_ROW(prev)->parent) \
1193
                                sibling = GTK_CTREE_ROW(prev)->sibling; \
1194
                        else \
1195
                                sibling = GTK_CTREE_ROW(parent)->children; \
1196
                        while (sibling) { \
1197
                                FolderItem *tmp; \
1198
 \
1199
                                tmp = gtk_ctree_node_get_row_data \
1200
                                        (ctree, sibling); \
1201
                                if (tmp->stype != F_NORMAL) \
1202
                                        sibling = GTK_CTREE_ROW(sibling)->sibling; \
1203
                                else \
1204
                                        break; \
1205
                        } \
1206
                        if (node != sibling) \
1207
                                gtk_ctree_move(ctree, node, parent, sibling); \
1208
                } \
1209
 \
1210
                prev = node; \
1211
        } \
1212
}
1213

    
1214
static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1215
                                    Folder *folder)
1216
{
1217
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1218
        GtkCTreeNode *prev = NULL;
1219

    
1220
        gtk_ctree_sort_recursive(ctree, root);
1221

    
1222
        if (GTK_CTREE_ROW(root)->parent) return;
1223

    
1224
        SET_SPECIAL_FOLDER(ctree, folder->inbox);
1225
        SET_SPECIAL_FOLDER(ctree, folder->outbox);
1226
        SET_SPECIAL_FOLDER(ctree, folder->draft);
1227
        SET_SPECIAL_FOLDER(ctree, folder->queue);
1228
        SET_SPECIAL_FOLDER(ctree, folder->trash);
1229
}
1230

    
1231
static void folderview_append_folder(FolderView *folderview, Folder *folder)
1232
{
1233
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1234
        GtkCTreeNode *root;
1235

    
1236
        g_return_if_fail(folder != NULL);
1237

    
1238
        root = gtk_ctree_insert_gnode(ctree, NULL, NULL, folder->node,
1239
                                      folderview_gnode_func, folderview);
1240
        gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1241
                                folderview);
1242
        folderview_sort_folders(folderview, root, folder);
1243
}
1244

    
1245
void folderview_new_folder(FolderView *folderview)
1246
{
1247
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1248
        FolderItem *item;
1249

    
1250
        if (!folderview->selected) return;
1251

    
1252
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1253
        g_return_if_fail(item != NULL);
1254
        g_return_if_fail(item->folder != NULL);
1255

    
1256
        switch (FOLDER_TYPE(item->folder)) {
1257
        case F_MH:
1258
        case F_MBOX:
1259
        case F_MAILDIR:
1260
        case F_IMAP:
1261
                folderview_new_folder_cb(folderview, 0, NULL);
1262
                break;
1263
        case F_NEWS:
1264
                folderview_new_news_group_cb(folderview, 0, NULL);
1265
                break;
1266
        default:
1267
                break;
1268
        }
1269
}
1270

    
1271
void folderview_rename_folder(FolderView *folderview)
1272
{
1273
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1274
        FolderItem *item;
1275

    
1276
        if (!folderview->selected) return;
1277

    
1278
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1279
        g_return_if_fail(item != NULL);
1280
        g_return_if_fail(item->folder != NULL);
1281
        if (!item->path) return;
1282
        if (item->stype != F_NORMAL) return;
1283

    
1284
        switch (FOLDER_TYPE(item->folder)) {
1285
        case F_MH:
1286
        case F_MBOX:
1287
        case F_MAILDIR:
1288
        case F_IMAP:
1289
                folderview_rename_folder_cb(folderview, 0, NULL);
1290
                break;
1291
        case F_NEWS:
1292
        default:
1293
                break;
1294
        }
1295
}
1296

    
1297
void folderview_delete_folder(FolderView *folderview)
1298
{
1299
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1300
        FolderItem *item;
1301

    
1302
        if (!folderview->selected) return;
1303

    
1304
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1305
        g_return_if_fail(item != NULL);
1306
        g_return_if_fail(item->folder != NULL);
1307
        if (!item->path) return;
1308
        if (item->stype != F_NORMAL) return;
1309

    
1310
        switch (FOLDER_TYPE(item->folder)) {
1311
        case F_MH:
1312
        case F_MBOX:
1313
        case F_MAILDIR:
1314
        case F_IMAP:
1315
                folderview_delete_folder_cb(folderview, 0, NULL);
1316
                break;
1317
        case F_NEWS:
1318
                folderview_rm_news_group_cb(folderview, 0, NULL);
1319
                break;
1320
        default:
1321
                break;
1322
        }
1323
}
1324

    
1325
void folderview_check_new_selected(FolderView *folderview)
1326
{
1327
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1328
        FolderItem *item;
1329

    
1330
        if (!folderview->selected) return;
1331

    
1332
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1333
        g_return_if_fail(item != NULL);
1334
        g_return_if_fail(item->folder != NULL);
1335
        if (item->parent != NULL) return;
1336

    
1337
        folderview_check_new(item->folder);
1338
}
1339

    
1340
void folderview_remove_mailbox(FolderView *folderview)
1341
{
1342
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1343
        FolderItem *item;
1344

    
1345
        if (!folderview->selected) return;
1346

    
1347
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1348
        g_return_if_fail(item != NULL);
1349
        g_return_if_fail(item->folder != NULL);
1350
        if (item->parent != NULL) return;
1351

    
1352
        switch (FOLDER_TYPE(item->folder)) {
1353
        case F_MH:
1354
        case F_MBOX:
1355
        case F_MAILDIR:
1356
                folderview_remove_mailbox_cb(folderview, 0, NULL);
1357
                break;
1358
        case F_IMAP:
1359
                folderview_rm_imap_server_cb(folderview, 0, NULL);
1360
                break;
1361
        case F_NEWS:
1362
                folderview_rm_news_server_cb(folderview, 0, NULL);
1363
                break;
1364
        default:
1365
                break;
1366
        }
1367
}
1368

    
1369
void folderview_rebuild_tree(FolderView *folderview)
1370
{
1371
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1372
        FolderItem *item;
1373

    
1374
        if (!folderview->selected) return;
1375

    
1376
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1377
        g_return_if_fail(item != NULL);
1378
        g_return_if_fail(item->folder != NULL);
1379
        if (item->parent != NULL) return;
1380

    
1381
        folderview_rescan_tree(folderview, item->folder);
1382
}
1383

    
1384

    
1385
/* callback functions */
1386

    
1387
static gboolean folderview_button_pressed(GtkWidget *ctree,
1388
                                          GdkEventButton *event,
1389
                                          FolderView *folderview)
1390
{
1391
        GtkCList *clist = GTK_CLIST(ctree);
1392
        gint prev_row = -1, row = -1, column = -1;
1393
        FolderItem *item;
1394
        Folder *folder;
1395
        GtkWidget *popup;
1396
        gboolean new_folder      = FALSE;
1397
        gboolean rename_folder   = FALSE;
1398
        gboolean delete_folder   = FALSE;
1399
        gboolean empty_trash     = FALSE;
1400
        gboolean download_msg    = FALSE;
1401
        gboolean update_tree     = FALSE;
1402
        gboolean rescan_tree     = FALSE;
1403
        gboolean remove_tree     = FALSE;
1404
        gboolean search_folder   = FALSE;
1405
        gboolean folder_property = FALSE;
1406

    
1407
        if (!event) return FALSE;
1408

    
1409
        if (event->button == 1) {
1410
                folderview->open_folder = TRUE;
1411
                return FALSE;
1412
        }
1413

    
1414
        if (event->button == 2 || event->button == 3) {
1415
                /* right clicked */
1416
                if (clist->selection) {
1417
                        GtkCTreeNode *node;
1418

    
1419
                        node = GTK_CTREE_NODE(clist->selection->data);
1420
                        if (node)
1421
                                prev_row = gtkut_ctree_get_nth_from_node
1422
                                        (GTK_CTREE(ctree), node);
1423
                }
1424

    
1425
                if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1426
                                                  &row, &column))
1427
                        return FALSE;
1428
                if (prev_row != row) {
1429
                        gtk_clist_unselect_all(clist);
1430
                        if (event->button == 2)
1431
                                folderview_select_node
1432
                                        (folderview,
1433
                                         gtk_ctree_node_nth(GTK_CTREE(ctree),
1434
                                                             row));
1435
                        else
1436
                                gtk_clist_select_row(clist, row, column);
1437
                }
1438
        }
1439

    
1440
        if (event->button != 3) return FALSE;
1441

    
1442
        item = gtk_clist_get_row_data(clist, row);
1443
        g_return_val_if_fail(item != NULL, FALSE);
1444
        g_return_val_if_fail(item->folder != NULL, FALSE);
1445
        folder = item->folder;
1446

    
1447
        if (folderview->mainwin->lock_count == 0) {
1448
                new_folder = TRUE;
1449
                if (item->parent == NULL) {
1450
                        update_tree = remove_tree = TRUE;
1451
                        if (folder->account)
1452
                                folder_property = TRUE;
1453
                } else {
1454
                        folder_property = TRUE;
1455
                        if (folderview->selected == folderview->opened)
1456
                                search_folder = TRUE;
1457
                }
1458
                if (FOLDER_IS_LOCAL(folder) || FOLDER_TYPE(folder) == F_IMAP) {
1459
                        if (item->parent == NULL)
1460
                                update_tree = rescan_tree = TRUE;
1461
                        else if (item->stype == F_NORMAL)
1462
                                rename_folder = delete_folder = TRUE;
1463
                        else if (item->stype == F_TRASH)
1464
                                empty_trash = TRUE;
1465
                } else if (FOLDER_TYPE(folder) == F_NEWS) {
1466
                        if (item->parent != NULL)
1467
                                delete_folder = TRUE;
1468
                }
1469
                if (FOLDER_TYPE(folder) == F_IMAP ||
1470
                    FOLDER_TYPE(folder) == F_NEWS) {
1471
                        if (item->parent != NULL && item->no_select == FALSE)
1472
                                download_msg = TRUE;
1473
                }
1474
        }
1475

    
1476
#define SET_SENS(factory, name, sens) \
1477
        menu_set_sensitive(folderview->factory, name, sens)
1478

    
1479
        if (FOLDER_IS_LOCAL(folder)) {
1480
                popup = folderview->mail_popup;
1481
                menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1482
                SET_SENS(mail_factory, "/Create new folder...", new_folder);
1483
                SET_SENS(mail_factory, "/Rename folder...", rename_folder);
1484
                SET_SENS(mail_factory, "/Delete folder", delete_folder);
1485
                SET_SENS(mail_factory, "/Empty trash", empty_trash);
1486
                SET_SENS(mail_factory, "/Check for new messages", update_tree);
1487
                SET_SENS(mail_factory, "/Rebuild folder tree", rescan_tree);
1488
                SET_SENS(mail_factory, "/Search messages...", search_folder);
1489
                SET_SENS(mail_factory, "/Properties...", folder_property);
1490
        } else if (FOLDER_TYPE(folder) == F_IMAP) {
1491
                popup = folderview->imap_popup;
1492
                menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1493
                SET_SENS(imap_factory, "/Create new folder...", new_folder);
1494
                SET_SENS(imap_factory, "/Rename folder...", rename_folder);
1495
                SET_SENS(imap_factory, "/Delete folder", delete_folder);
1496
                SET_SENS(imap_factory, "/Empty trash", empty_trash);
1497
                SET_SENS(imap_factory, "/Download", download_msg);
1498
                SET_SENS(imap_factory, "/Check for new messages", update_tree);
1499
                SET_SENS(imap_factory, "/Rebuild folder tree", rescan_tree);
1500
                SET_SENS(imap_factory, "/Search messages...", search_folder);
1501
                SET_SENS(imap_factory, "/Properties...", folder_property);
1502
        } else if (FOLDER_TYPE(folder) == F_NEWS) {
1503
                popup = folderview->news_popup;
1504
                menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1505
                SET_SENS(news_factory, "/Subscribe to newsgroup...", new_folder);
1506
                SET_SENS(news_factory, "/Remove newsgroup", delete_folder);
1507
                SET_SENS(news_factory, "/Download", download_msg);
1508
                SET_SENS(news_factory, "/Check for new messages", update_tree);
1509
                SET_SENS(news_factory, "/Search messages...", search_folder);
1510
                SET_SENS(news_factory, "/Properties...", folder_property);
1511
        } else
1512
                return FALSE;
1513

    
1514
#undef SET_SENS
1515

    
1516
        gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1517
                       event->button, event->time);
1518

    
1519
        return FALSE;
1520
}
1521

    
1522
static gboolean folderview_button_released(GtkWidget *ctree,
1523
                                           GdkEventButton *event,
1524
                                           FolderView *folderview)
1525
{
1526
        if (!event) return FALSE;
1527

    
1528
        if (event->button == 1 && folderview->open_folder == FALSE &&
1529
            folderview->opened != NULL) {
1530
                gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1531
                                          folderview->opened);
1532
                gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1533
        }
1534

    
1535
        return FALSE;
1536
}
1537

    
1538
static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1539
                                       FolderView *folderview)
1540
{
1541
        if (!event) return FALSE;
1542

    
1543
        switch (event->keyval) {
1544
        case GDK_Return:
1545
                if (folderview->selected) {
1546
                        folderview_select_node(folderview,
1547
                                               folderview->selected);
1548
                }
1549
                break;
1550
        case GDK_space:
1551
                if (folderview->selected) {
1552
                        if (folderview->opened == folderview->selected &&
1553
                            (!folderview->summaryview->folder_item ||
1554
                             folderview->summaryview->folder_item->total == 0))
1555
                                folderview_select_next_unread(folderview);
1556
                        else
1557
                                folderview_select_node(folderview,
1558
                                                       folderview->selected);
1559
                }
1560
                break;
1561
        default:
1562
                break;
1563
        }
1564

    
1565
        return FALSE;
1566
}
1567

    
1568
static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
1569
                                gint column, FolderView *folderview)
1570
{
1571
        static gboolean can_select = TRUE;        /* exclusive lock */
1572
        gboolean opened;
1573
        FolderItem *item;
1574

    
1575
        folderview->selected = row;
1576

    
1577
        main_window_set_menu_sensitive(folderview->mainwin);
1578

    
1579
        if (folderview->opened == row) {
1580
                folderview->open_folder = FALSE;
1581
                return;
1582
        }
1583

    
1584
        if (!can_select || summary_is_locked(folderview->summaryview)) {
1585
                gtkut_ctree_set_focus_row(ctree, folderview->opened);
1586
                gtk_ctree_select(ctree, folderview->opened);
1587
                return;
1588
        }
1589

    
1590
        if (!folderview->open_folder) return;
1591

    
1592
        item = gtk_ctree_node_get_row_data(ctree, row);
1593
        if (!item) return;
1594

    
1595
        can_select = FALSE;
1596

    
1597
        if (item->path)
1598
                debug_print(_("Folder %s is selected\n"), item->path);
1599

    
1600
        if (!GTK_CTREE_ROW(row)->children)
1601
                gtk_ctree_expand(ctree, row);
1602
        if (folderview->opened &&
1603
            !GTK_CTREE_ROW(folderview->opened)->children)
1604
                gtk_ctree_collapse(ctree, folderview->opened);
1605

    
1606
        /* ungrab the mouse event */
1607
        if (GTK_WIDGET_HAS_GRAB(ctree)) {
1608
                gtk_grab_remove(GTK_WIDGET(ctree));
1609
                if (gdk_pointer_is_grabbed())
1610
                        gdk_pointer_ungrab(GDK_CURRENT_TIME);
1611
        }
1612

    
1613
        opened = summary_show(folderview->summaryview, item, FALSE);
1614

    
1615
        if (!opened) {
1616
                gtkut_ctree_set_focus_row(ctree, folderview->opened);
1617
                gtk_ctree_select(ctree, folderview->opened);
1618
        } else {
1619
                folderview->opened = row;
1620
                if (gtk_ctree_node_is_visible(ctree, row)
1621
                    != GTK_VISIBILITY_FULL)
1622
                        gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
1623
        }
1624

    
1625
        folderview->open_folder = FALSE;
1626
        can_select = TRUE;
1627
}
1628

    
1629
static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
1630
                                     FolderView *folderview)
1631
{
1632
        FolderItem *item;
1633

    
1634
        item = gtk_ctree_node_get_row_data(ctree, node);
1635
        g_return_if_fail(item != NULL);
1636
        item->collapsed = FALSE;
1637
        folderview_update_node(folderview, node);
1638
}
1639

    
1640
static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
1641
                                      FolderView *folderview)
1642
{
1643
        FolderItem *item;
1644

    
1645
        item = gtk_ctree_node_get_row_data(ctree, node);
1646
        g_return_if_fail(item != NULL);
1647
        item->collapsed= TRUE;
1648
        folderview_update_node(folderview, node);
1649
}
1650

    
1651
static void folderview_popup_close(GtkMenuShell *menu_shell,
1652
                                   FolderView *folderview)
1653
{
1654
        if (!folderview->opened) return;
1655

    
1656
        gtkut_ctree_set_focus_row(GTK_CTREE(folderview->ctree),
1657
                                  folderview->opened);
1658
        gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
1659
}
1660

    
1661
static void folderview_col_resized(GtkCList *clist, gint column, gint width,
1662
                                   FolderView *folderview)
1663
{
1664
        switch (column) {
1665
        case COL_FOLDER:
1666
                prefs_common.folder_col_folder = width;
1667
                break;
1668
        case COL_NEW:
1669
                prefs_common.folder_col_new = width;
1670
                break;
1671
        case COL_UNREAD:
1672
                prefs_common.folder_col_unread = width;
1673
                break;
1674
        case COL_TOTAL:
1675
                prefs_common.folder_col_total = width;
1676
                break;
1677
        default:
1678
                break;
1679
        }
1680
}
1681

    
1682
static void folderview_download_func(Folder *folder, FolderItem *item,
1683
                                     gpointer data)
1684
{
1685
        GList *list;
1686

    
1687
        for (list = folderview_list; list != NULL; list = list->next) {
1688
                FolderView *folderview = (FolderView *)list->data;
1689
                MainWindow *mainwin = folderview->mainwin;
1690
                gchar *str;
1691

    
1692
                str = g_strdup_printf
1693
                        (_("Downloading messages in %s ..."), item->path);
1694
                main_window_progress_set(mainwin,
1695
                                         GPOINTER_TO_INT(data), item->total);
1696
                STATUSBAR_PUSH(mainwin, str);
1697
                STATUSBAR_POP(mainwin);
1698
                g_free(str);
1699
        }
1700
}
1701

    
1702
static void folderview_download_cb(FolderView *folderview, guint action,
1703
                                   GtkWidget *widget)
1704
{
1705
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1706
        MainWindow *mainwin = folderview->mainwin;
1707
        FolderItem *item;
1708

    
1709
        if (!folderview->selected) return;
1710

    
1711
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1712
        g_return_if_fail(item != NULL);
1713
        g_return_if_fail(item->folder != NULL);
1714

    
1715
        if (!main_window_toggle_online_if_offline(folderview->mainwin))
1716
                return;
1717

    
1718
        main_window_cursor_wait(mainwin);
1719
        inc_lock();
1720
        main_window_lock(mainwin);
1721
        gtk_widget_set_sensitive(folderview->ctree, FALSE);
1722
        main_window_progress_on(mainwin);
1723
        GTK_EVENTS_FLUSH();
1724
        folder_set_ui_func(item->folder, folderview_download_func, NULL);
1725
        if (folder_item_fetch_all_msg(item) < 0) {
1726
                gchar *name;
1727

    
1728
                name = trim_string(item->name, 32);
1729
                alertpanel_error(_("Error occurred while downloading messages in `%s'."), name);
1730
                g_free(name);
1731
        }
1732
        folder_set_ui_func(item->folder, NULL, NULL);
1733
        main_window_progress_off(mainwin);
1734
        gtk_widget_set_sensitive(folderview->ctree, TRUE);
1735
        main_window_unlock(mainwin);
1736
        inc_unlock();
1737
        main_window_cursor_normal(mainwin);
1738
        statusbar_pop_all();
1739
}
1740

    
1741
static void folderview_update_tree_cb(FolderView *folderview, guint action,
1742
                                      GtkWidget *widget)
1743
{
1744
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1745
        FolderItem *item;
1746

    
1747
        if (!folderview->selected) return;
1748

    
1749
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1750
        g_return_if_fail(item != NULL);
1751
        g_return_if_fail(item->folder != NULL);
1752

    
1753
        if (action == 0)
1754
                folderview_check_new(item->folder);
1755
        else
1756
                folderview_rescan_tree(folderview, item->folder);
1757
}
1758

    
1759
static void folderview_new_folder_cb(FolderView *folderview, guint action,
1760
                                     GtkWidget *widget)
1761
{
1762
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1763
        FolderItem *item;
1764
        FolderItem *new_item;
1765
        gchar *new_folder;
1766
        gchar *name;
1767
        gchar *p;
1768

    
1769
        if (!folderview->selected) return;
1770

    
1771
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1772
        g_return_if_fail(item != NULL);
1773
        g_return_if_fail(item->folder != NULL);
1774
        if (FOLDER_TYPE(item->folder) == F_IMAP)
1775
                g_return_if_fail(item->folder->account != NULL);
1776

    
1777
        if (FOLDER_TYPE(item->folder) == F_IMAP) {
1778
                new_folder = input_dialog
1779
                        (_("New folder"),
1780
                         _("Input the name of new folder:\n"
1781
                           "(if you want to create a folder to store subfolders,\n"
1782
                           " append `/' at the end of the name)"),
1783
                         _("NewFolder"));
1784
        } else {
1785
                new_folder = input_dialog(_("New folder"),
1786
                                          _("Input the name of new folder:"),
1787
                                          _("NewFolder"));
1788
        }
1789
        if (!new_folder) return;
1790
        AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
1791

    
1792
        p = strchr(new_folder, G_DIR_SEPARATOR);
1793
        if ((p && FOLDER_TYPE(item->folder) != F_IMAP) ||
1794
            (p && FOLDER_TYPE(item->folder) == F_IMAP && *(p + 1) != '\0')) {
1795
                alertpanel_error(_("`%c' can't be included in folder name."),
1796
                                 G_DIR_SEPARATOR);
1797
                return;
1798
        }
1799

    
1800
        name = trim_string(new_folder, 32);
1801
        AUTORELEASE_STR(name, {g_free(name); return;});
1802

    
1803
        /* find whether the directory already exists */
1804
        if (folder_find_child_item_by_name(item, new_folder)) {
1805
                alertpanel_error(_("The folder `%s' already exists."), name);
1806
                return;
1807
        }
1808

    
1809
        new_item = item->folder->klass->create_folder(item->folder, item,
1810
                                                      new_folder);
1811
        if (!new_item) {
1812
                alertpanel_error(_("Can't create the folder `%s'."), name);
1813
                return;
1814
        }
1815

    
1816
        folderview_append_item(new_item);
1817
        folder_write_list();
1818
}
1819

    
1820
static void folderview_rename_folder_cb(FolderView *folderview, guint action,
1821
                                        GtkWidget *widget)
1822
{
1823
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1824
        FolderItem *item;
1825
        gchar *new_folder;
1826
        gchar *name;
1827
        gchar *message;
1828
        gchar *old_path;
1829
        gchar *old_id;
1830
        gchar *new_id;
1831

    
1832
        if (!folderview->selected) return;
1833

    
1834
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1835
        g_return_if_fail(item != NULL);
1836
        g_return_if_fail(item->path != NULL);
1837
        g_return_if_fail(item->folder != NULL);
1838

    
1839
        name = trim_string(item->name, 32);
1840
        message = g_strdup_printf(_("Input new name for `%s':"), name);
1841
        new_folder = input_dialog(_("Rename folder"), message,
1842
                                  g_basename(item->path));
1843
        g_free(message);
1844
        g_free(name);
1845
        if (!new_folder) return;
1846
        AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
1847

    
1848
        if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
1849
                alertpanel_error(_("`%c' can't be included in folder name."),
1850
                                 G_DIR_SEPARATOR);
1851
                return;
1852
        }
1853

    
1854
        if (folder_find_child_item_by_name(item->parent, new_folder)) {
1855
                name = trim_string(new_folder, 32);
1856
                alertpanel_error(_("The folder `%s' already exists."), name);
1857
                g_free(name);
1858
                return;
1859
        }
1860

    
1861
        Xstrdup_a(old_path, item->path, {g_free(new_folder); return;});
1862
        old_id = folder_item_get_identifier(item);
1863

    
1864
        if (item->folder->klass->rename_folder(item->folder, item,
1865
                                               new_folder) < 0) {
1866
                g_free(old_id);
1867
                return;
1868
        }
1869

    
1870
        if (folder_get_default_folder() == item->folder)
1871
                prefs_filter_rename_path(old_path, item->path);
1872
        new_id = folder_item_get_identifier(item);
1873
        prefs_filter_rename_path(old_id, new_id);
1874
        g_free(old_id);
1875
        g_free(new_id);
1876

    
1877
        gtk_clist_freeze(GTK_CLIST(ctree));
1878

    
1879
        folderview_update_node(folderview, folderview->selected);
1880
        folderview_sort_folders(folderview,
1881
                                GTK_CTREE_ROW(folderview->selected)->parent,
1882
                                item->folder);
1883
        if (folderview->opened == folderview->selected ||
1884
            gtk_ctree_is_ancestor(ctree,
1885
                                  folderview->selected,
1886
                                  folderview->opened)) {
1887
                GtkCTreeNode *node = folderview->opened;
1888
                folderview_unselect(folderview);
1889
                folderview_select_node(folderview, node);
1890
        }
1891

    
1892
        gtk_clist_thaw(GTK_CLIST(ctree));
1893

    
1894
        folder_write_list();
1895
}
1896

    
1897
static void folderview_delete_folder_cb(FolderView *folderview, guint action,
1898
                                        GtkWidget *widget)
1899
{
1900
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1901
        Folder *folder;
1902
        FolderItem *item;
1903
        gchar *message, *name;
1904
        AlertValue avalue;
1905
        gchar *old_path;
1906
        gchar *old_id;
1907

    
1908
        if (!folderview->selected) return;
1909

    
1910
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1911
        g_return_if_fail(item != NULL);
1912
        g_return_if_fail(item->path != NULL);
1913
        g_return_if_fail(item->folder != NULL);
1914

    
1915
        folder = item->folder;
1916

    
1917
        name = trim_string(item->name, 32);
1918
        AUTORELEASE_STR(name, {g_free(name); return;});
1919
        message = g_strdup_printf
1920
                (_("All folder(s) and message(s) under `%s' will be deleted.\n"
1921
                   "Do you really want to delete?"), name);
1922
        avalue = alertpanel(_("Delete folder"), message,
1923
                            _("Yes"), _("+No"), NULL);
1924
        g_free(message);
1925
        if (avalue != G_ALERTDEFAULT) return;
1926

    
1927
        Xstrdup_a(old_path, item->path, return);
1928
        old_id = folder_item_get_identifier(item);
1929

    
1930
        if (folderview->opened == folderview->selected ||
1931
            gtk_ctree_is_ancestor(ctree,
1932
                                  folderview->selected, folderview->opened)) {
1933
                summary_clear_all(folderview->summaryview);
1934
                folderview->opened = NULL;
1935
        }
1936

    
1937
        if (folder->klass->remove_folder(folder, item) < 0) {
1938
                alertpanel_error(_("Can't remove the folder `%s'."), name);
1939
                g_free(old_id);
1940
                return;
1941
        }
1942

    
1943
        if (folder_get_default_folder() == folder)
1944
                prefs_filter_delete_path(old_path);
1945
        prefs_filter_delete_path(old_id);
1946
        g_free(old_id);
1947

    
1948
        gtk_ctree_remove_node(ctree, folderview->selected);
1949
        folder_write_list();
1950
}
1951

    
1952
static void folderview_empty_trash_cb(FolderView *folderview, guint action,
1953
                                      GtkWidget *widget)
1954
{
1955
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1956
        FolderItem *item;
1957
        Folder *folder;
1958

    
1959
        if (!folderview->selected) return;
1960

    
1961
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1962
        g_return_if_fail(item != NULL);
1963
        g_return_if_fail(item->path != NULL);
1964
        g_return_if_fail(item->folder != NULL);
1965

    
1966
        folder = item->folder;
1967

    
1968
        if (folder->trash != item) return;
1969
        if (item->stype != F_TRASH) return;
1970

    
1971
        if (alertpanel(_("Empty trash"), _("Empty all messages in trash?"),
1972
                       _("Yes"), _("No"), NULL) != G_ALERTDEFAULT)
1973
                return;
1974

    
1975
        procmsg_empty_trash(folder->trash);
1976
        statusbar_pop_all();
1977
        folderview_update_item(folder->trash, TRUE);
1978

    
1979
        if (folderview->opened == folderview->selected)
1980
                gtk_widget_grab_focus(folderview->ctree);
1981
}
1982

    
1983
static void folderview_remove_mailbox_cb(FolderView *folderview, guint action,
1984
                                         GtkWidget *widget)
1985
{
1986
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1987
        GtkCTreeNode *node;
1988
        FolderItem *item;
1989
        gchar *name;
1990
        gchar *message;
1991
        AlertValue avalue;
1992

    
1993
        if (!folderview->selected) return;
1994
        node = folderview->selected;
1995
        item = gtk_ctree_node_get_row_data(ctree, node);
1996
        g_return_if_fail(item != NULL);
1997
        g_return_if_fail(item->folder != NULL);
1998
        if (item->parent) return;
1999

    
2000
        name = trim_string(item->folder->name, 32);
2001
        message = g_strdup_printf
2002
                (_("Really remove the mailbox `%s' ?\n"
2003
                   "(The messages are NOT deleted from the disk)"), name);
2004
        avalue = alertpanel(_("Remove mailbox"), message,
2005
                            _("Yes"), _("+No"), NULL);
2006
        g_free(message);
2007
        g_free(name);
2008
        if (avalue != G_ALERTDEFAULT) return;
2009

    
2010
        if (folderview->summaryview->folder_item &&
2011
            folderview->summaryview->folder_item->folder == item->folder) {
2012
                summary_clear_all(folderview->summaryview);
2013
                folderview->opened = NULL;
2014
        }
2015
        folder_destroy(item->folder);
2016
        gtk_ctree_remove_node(ctree, node);
2017
        folder_write_list();
2018
}
2019

    
2020
static void folderview_rm_imap_server_cb(FolderView *folderview, guint action,
2021
                                         GtkWidget *widget)
2022
{
2023
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2024
        FolderItem *item;
2025
        PrefsAccount *account;
2026
        gchar *name;
2027
        gchar *message;
2028
        AlertValue avalue;
2029

    
2030
        if (!folderview->selected) return;
2031

    
2032
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2033
        g_return_if_fail(item != NULL);
2034
        g_return_if_fail(item->folder != NULL);
2035
        g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP);
2036
        g_return_if_fail(item->folder->account != NULL);
2037

    
2038
        name = trim_string(item->folder->name, 32);
2039
        message = g_strdup_printf(_("Really delete IMAP4 account `%s'?"), name);
2040
        avalue = alertpanel(_("Delete IMAP4 account"), message,
2041
                            _("Yes"), _("+No"), NULL);
2042
        g_free(message);
2043
        g_free(name);
2044

    
2045
        if (avalue != G_ALERTDEFAULT) return;
2046

    
2047
        if (folderview->summaryview->folder_item &&
2048
            folderview->summaryview->folder_item->folder == item->folder) {
2049
                summary_clear_all(folderview->summaryview);
2050
                folderview->opened = NULL;
2051
        }
2052

    
2053
        account = item->folder->account;
2054
        folder_destroy(item->folder);
2055
        account_destroy(account);
2056
        gtk_ctree_remove_node(ctree, folderview->selected);
2057
        account_set_menu();
2058
        main_window_reflect_prefs_all();
2059
        folder_write_list();
2060
}
2061

    
2062
static void folderview_new_news_group_cb(FolderView *folderview, guint action,
2063
                                         GtkWidget *widget)
2064
{
2065
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2066
        GtkCTreeNode *servernode, *node;
2067
        Folder *folder;
2068
        FolderItem *item;
2069
        FolderItem *rootitem;
2070
        FolderItem *newitem;
2071
        GSList *new_subscr;
2072
        GSList *cur;
2073
        GNode *gnode;
2074

    
2075
        if (!folderview->selected) return;
2076

    
2077
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2078
        g_return_if_fail(item != NULL);
2079
        folder = item->folder;
2080
        g_return_if_fail(folder != NULL);
2081
        g_return_if_fail(FOLDER_TYPE(folder) == F_NEWS);
2082
        g_return_if_fail(folder->account != NULL);
2083

    
2084
        if (GTK_CTREE_ROW(folderview->selected)->parent != NULL)
2085
                servernode = GTK_CTREE_ROW(folderview->selected)->parent;
2086
        else
2087
                servernode = folderview->selected;
2088

    
2089
        rootitem = gtk_ctree_node_get_row_data(ctree, servernode);
2090

    
2091
        new_subscr = grouplist_dialog(folder);
2092

    
2093
        /* remove unsubscribed newsgroups */
2094
        for (gnode = folder->node->children; gnode != NULL; ) {
2095
                GNode *next = gnode->next;
2096

    
2097
                item = FOLDER_ITEM(gnode->data);
2098
                if (g_slist_find_custom(new_subscr, item->path,
2099
                                        (GCompareFunc)g_strcasecmp) != NULL) {
2100
                        gnode = next;
2101
                        continue;
2102
                }
2103

    
2104
                node = gtk_ctree_find_by_row_data(ctree, servernode, item);
2105
                if (!node) {
2106
                        gnode = next;
2107
                        continue;
2108
                }
2109

    
2110
                if (folderview->opened == node) {
2111
                        summary_clear_all(folderview->summaryview);
2112
                        folderview->opened = NULL;
2113
                }
2114

    
2115
                folder_item_remove(item);
2116
                gtk_ctree_remove_node(ctree, node);
2117

    
2118
                gnode = next;
2119
        }
2120

    
2121
        gtk_clist_freeze(GTK_CLIST(ctree));
2122

    
2123
        /* add subscribed newsgroups */
2124
        for (cur = new_subscr; cur != NULL; cur = cur->next) {
2125
                gchar *name = (gchar *)cur->data;
2126

    
2127
                if (folder_find_child_item_by_name(rootitem, name) != NULL)
2128
                        continue;
2129

    
2130
                newitem = folder_item_new(name, name);
2131
                folder_item_append(rootitem, newitem);
2132
                folderview_append_item(newitem);
2133
        }
2134

    
2135
        gtk_clist_thaw(GTK_CLIST(ctree));
2136

    
2137
        slist_free_strings(new_subscr);
2138
        g_slist_free(new_subscr);
2139

    
2140
        folder_write_list();
2141
}
2142

    
2143
static void folderview_rm_news_group_cb(FolderView *folderview, guint action,
2144
                                        GtkWidget *widget)
2145
{
2146
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2147
        FolderItem *item;
2148
        gchar *name;
2149
        gchar *message;
2150
        AlertValue avalue;
2151

    
2152
        if (!folderview->selected) return;
2153

    
2154
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2155
        g_return_if_fail(item != NULL);
2156
        g_return_if_fail(item->folder != NULL);
2157
        g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS);
2158
        g_return_if_fail(item->folder->account != NULL);
2159

    
2160
        name = trim_string_before(item->path, 32);
2161
        message = g_strdup_printf(_("Really delete newsgroup `%s'?"), name);
2162
        avalue = alertpanel(_("Delete newsgroup"), message,
2163
                            _("Yes"), _("+No"), NULL);
2164
        g_free(message);
2165
        g_free(name);
2166
        if (avalue != G_ALERTDEFAULT) return;
2167

    
2168
        if (folderview->opened == folderview->selected) {
2169
                summary_clear_all(folderview->summaryview);
2170
                folderview->opened = NULL;
2171
        }
2172

    
2173
        folder_item_remove(item);
2174
        gtk_ctree_remove_node(ctree, folderview->selected);
2175
        folder_write_list();
2176
}
2177

    
2178
static void folderview_rm_news_server_cb(FolderView *folderview, guint action,
2179
                                         GtkWidget *widget)
2180
{
2181
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2182
        FolderItem *item;
2183
        PrefsAccount *account;
2184
        gchar *name;
2185
        gchar *message;
2186
        AlertValue avalue;
2187

    
2188
        if (!folderview->selected) return;
2189

    
2190
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2191
        g_return_if_fail(item != NULL);
2192
        g_return_if_fail(item->folder != NULL);
2193
        g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS);
2194
        g_return_if_fail(item->folder->account != NULL);
2195

    
2196
        name = trim_string(item->folder->name, 32);
2197
        message = g_strdup_printf(_("Really delete news account `%s'?"), name);
2198
        avalue = alertpanel(_("Delete news account"), message,
2199
                            _("Yes"), _("+No"), NULL);
2200
        g_free(message);
2201
        g_free(name);
2202

    
2203
        if (avalue != G_ALERTDEFAULT) return;
2204

    
2205
        if (folderview->summaryview->folder_item &&
2206
            folderview->summaryview->folder_item->folder == item->folder) {
2207
                summary_clear_all(folderview->summaryview);
2208
                folderview->opened = NULL;
2209
        }
2210

    
2211
        account = item->folder->account;
2212
        folder_destroy(item->folder);
2213
        account_destroy(account);
2214
        gtk_ctree_remove_node(ctree, folderview->selected);
2215
        account_set_menu();
2216
        main_window_reflect_prefs_all();
2217
        folder_write_list();
2218
}
2219

    
2220
static void folderview_search_cb(FolderView *folderview, guint action,
2221
                                 GtkWidget *widget)
2222
{
2223
        summary_search(folderview->summaryview);
2224
}
2225

    
2226
static void folderview_property_cb(FolderView *folderview, guint action,
2227
                                   GtkWidget *widget)
2228
{
2229
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2230
        FolderItem *item;
2231

    
2232
        if (!folderview->selected) return;
2233

    
2234
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2235
        g_return_if_fail(item != NULL);
2236
        g_return_if_fail(item->folder != NULL);
2237

    
2238
        if (item->parent == NULL && item->folder->account)
2239
                account_open(item->folder->account);
2240
        else
2241
                prefs_folder_item_open(item);
2242
}
2243

    
2244
static void folderview_defer_expand_stop(FolderView *folderview)
2245
{
2246
        if (folderview->spring_timer > 0) {
2247
                gtk_timeout_remove(folderview->spring_timer);
2248
                folderview->spring_timer = 0;
2249
        }
2250
        folderview->spring_node = NULL;
2251
}
2252

    
2253
static gint folderview_defer_expand(gpointer data)
2254
{
2255
        FolderView *folderview = (FolderView *)data;
2256

    
2257
        if (folderview->spring_node) {
2258
                gtk_ctree_expand(GTK_CTREE(folderview->ctree),
2259
                                 folderview->spring_node);
2260
        }
2261
        folderview_defer_expand_stop(folderview);
2262

    
2263
        return FALSE;
2264
}
2265

    
2266
static gboolean folderview_drag_motion_cb(GtkWidget      *widget,
2267
                                          GdkDragContext *context,
2268
                                          gint            x,
2269
                                          gint            y,
2270
                                          guint           time,
2271
                                          FolderView     *folderview)
2272
{
2273
        gint row, column;
2274
        FolderItem *item, *src_item;
2275
        GtkCTreeNode *node = NULL;
2276
        gboolean acceptable = FALSE;
2277

    
2278
        if (gtk_clist_get_selection_info
2279
                (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2280
                node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2281
                item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2282
                src_item = folderview->summaryview->folder_item;
2283
                if (src_item && src_item != item)
2284
                        acceptable = FOLDER_ITEM_CAN_ADD(item);
2285
        }
2286

    
2287
        if (node != folderview->spring_node) {
2288
                folderview_defer_expand_stop(folderview);
2289
                if (node && !GTK_CTREE_ROW(node)->expanded &&
2290
                    GTK_CTREE_ROW(node)->children) {
2291
                        folderview->spring_timer =
2292
                                gtk_timeout_add(1000, folderview_defer_expand,
2293
                                                folderview);
2294
                        folderview->spring_node = node;
2295
                }
2296
        }
2297

    
2298
        if (acceptable) {
2299
                g_signal_handlers_block_by_func
2300
                        (G_OBJECT(widget),
2301
                         G_CALLBACK(folderview_selected), folderview);
2302
                gtk_ctree_select(GTK_CTREE(widget), node);
2303
                g_signal_handlers_unblock_by_func
2304
                        (G_OBJECT(widget),
2305
                         G_CALLBACK(folderview_selected), folderview);
2306
                if ((context->actions & GDK_ACTION_MOVE) != 0)
2307
                        gdk_drag_status(context, GDK_ACTION_MOVE, time);
2308
                else if ((context->actions & GDK_ACTION_COPY) != 0)
2309
                        gdk_drag_status(context, GDK_ACTION_COPY, time);
2310
                else if ((context->actions & GDK_ACTION_LINK) != 0)
2311
                        gdk_drag_status(context, GDK_ACTION_LINK, time);
2312
                else
2313
                        gdk_drag_status(context, 0, time);
2314
        } else {
2315
                gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2316
                gdk_drag_status(context, 0, time);
2317
        }
2318

    
2319
        return acceptable;
2320
}
2321

    
2322
static void folderview_drag_leave_cb(GtkWidget      *widget,
2323
                                     GdkDragContext *context,
2324
                                     guint           time,
2325
                                     FolderView     *folderview)
2326
{
2327
        folderview_defer_expand_stop(folderview);
2328
        gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2329
}
2330

    
2331
static void folderview_drag_received_cb(GtkWidget        *widget,
2332
                                        GdkDragContext   *context,
2333
                                        gint              x,
2334
                                        gint              y,
2335
                                        GtkSelectionData *data,
2336
                                        guint             info,
2337
                                        guint             time,
2338
                                        FolderView       *folderview)
2339
{
2340
        gint row, column;
2341
        FolderItem *item, *src_item;
2342
        GtkCTreeNode *node;
2343

    
2344
        folderview_defer_expand_stop(folderview);
2345

    
2346
        if (gtk_clist_get_selection_info
2347
                (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2348
                return;
2349

    
2350
        node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2351
        item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2352
        src_item = folderview->summaryview->folder_item;
2353
        if (FOLDER_ITEM_CAN_ADD(item) && src_item && src_item != item) {
2354
                if ((context->actions & GDK_ACTION_MOVE) != 0) {
2355
                        summary_move_selected_to(folderview->summaryview, item);
2356
                        gtk_drag_finish(context, TRUE, TRUE, time);
2357
                } else if ((context->actions & GDK_ACTION_COPY) != 0) {
2358
                        summary_copy_selected_to(folderview->summaryview, item);
2359
                        gtk_drag_finish(context, TRUE, TRUE, time);
2360
                } else
2361
                        gtk_drag_finish(context, FALSE, FALSE, time);
2362
        } else
2363
                gtk_drag_finish(context, FALSE, FALSE, time);
2364
}
2365

    
2366
static gint folderview_clist_compare(GtkCList *clist,
2367
                                     gconstpointer ptr1, gconstpointer ptr2)
2368
{
2369
        FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2370
        FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2371

    
2372
        if (!item1->name)
2373
                return (item2->name != NULL);
2374
        if (!item2->name)
2375
                return -1;
2376

    
2377
        return g_strcasecmp(item1->name, item2->name);
2378
}