Statistics
| Revision:

root / src / prefs_filter.c @ 3047

History | View | Annotate | Download (23.1 kB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2012 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
#ifdef HAVE_CONFIG_H
21
#  include "config.h"
22
#endif
23
24
#include "defs.h"
25
26
#include <glib.h>
27
#include <glib/gi18n.h>
28
#include <gtk/gtk.h>
29
#include <gdk/gdkkeysyms.h>
30
#include <stdio.h>
31
#include <stdlib.h>
32
#include <string.h>
33
#include <errno.h>
34
35
#include "main.h"
36
#include "prefs.h"
37
#include "prefs_ui.h"
38
#include "prefs_filter.h"
39
#include "prefs_filter_edit.h"
40
#include "prefs_common.h"
41
#include "mainwindow.h"
42
#include "foldersel.h"
43
#include "manage_window.h"
44
#include "stock_pixmap.h"
45
#include "inc.h"
46
#include "procheader.h"
47
#include "menu.h"
48
#include "filter.h"
49
#include "utils.h"
50
#include "gtkutils.h"
51
#include "alertpanel.h"
52
#include "xml.h"
53
#include "plugin.h"
54
55
static struct FilterRuleListWindow {
56
        GtkWidget *window;
57
58
        GtkWidget *treeview;
59
        GtkListStore *store;
60
        GtkTreeSelection *selection;
61
62
        GtkWidget *add_btn;
63
        GtkWidget *edit_btn;
64
        GtkWidget *copy_btn;
65
        GtkWidget *del_btn;
66
67
        GSList *default_hdr_list;
68
        GSList *user_hdr_list;
69
        GSList *msg_hdr_list;
70
71
        GHashTable *msg_hdr_table;
72
73
        GtkWidget *close_btn;
74
75
        gboolean on_init;
76
        gboolean modified;
77
} rule_list_window;
78
79
enum {
80
        COL_ENABLED,
81
        COL_NAME,
82
        COL_FILTER_RULE,
83
        N_COLS
84
};
85
86
static void prefs_filter_create                        (void);
87
88
static void prefs_filter_set_dialog                (void);
89
static void prefs_filter_set_list_row                (GtkTreeIter        *iter,
90
                                                 FilterRule        *rule,
91
                                                 gboolean         move_view);
92
93
static void prefs_filter_set_list                (void);
94
95
/* callback functions */
96
static void prefs_filter_add_cb                (void);
97
static void prefs_filter_edit_cb        (void);
98
static void prefs_filter_copy_cb        (void);
99
static void prefs_filter_delete_cb        (void);
100
static void prefs_filter_top                (void);
101
static void prefs_filter_up                (void);
102
static void prefs_filter_down                (void);
103
static void prefs_filter_bottom                (void);
104
105
static gboolean prefs_filter_select        (GtkTreeSelection        *selection,
106
                                         GtkTreeModel                *model,
107
                                         GtkTreePath                *path,
108
                                         gboolean                 cur_selected,
109
                                         gpointer                 data);
110
static void prefs_filter_enable_toggled        (GtkCellRenderer        *cell,
111
                                         gchar                        *path,
112
                                         gpointer                 data);
113
114
static void prefs_filter_row_activated        (GtkTreeView                *treeview,
115
                                         GtkTreePath                *path,
116
                                         GtkTreeViewColumn        *column,
117
                                         gpointer                 data);
118
static void prefs_filter_row_reordered        (GtkTreeModel                *model,
119
                                         GtkTreePath                *path,
120
                                         GtkTreeIter                *iter,
121
                                         gpointer                 data,
122
                                         gpointer                 user_data);
123
124
static gint prefs_filter_deleted        (GtkWidget        *widget,
125
                                         GdkEventAny        *event,
126
                                         gpointer         data);
127
static gboolean prefs_filter_key_pressed(GtkWidget        *widget,
128
                                         GdkEventKey        *event,
129
                                         gpointer         data);
130
static void prefs_filter_close                (void);
131
132
133
void prefs_filter_open(MsgInfo *msginfo, const gchar *header, const gchar *key)
134
{
135
        inc_lock();
136
137
        rule_list_window.on_init = TRUE;
138
139
        if (!rule_list_window.window)
140
                prefs_filter_create();
141
142
        prefs_filter_set_header_list(msginfo);
143
144
        manage_window_set_transient(GTK_WINDOW(rule_list_window.window));
145
        gtk_widget_grab_focus(rule_list_window.close_btn);
146
147
        prefs_filter_set_dialog();
148
149
        gtk_widget_show(rule_list_window.window);
150
        manage_window_focus_in(rule_list_window.window, NULL, NULL);
151
152
        rule_list_window.modified = FALSE;
153
154
        syl_plugin_signal_emit("prefs-filter-open", rule_list_window.window);
155
156
        if (msginfo) {
157
                FilterRule *rule;
158
159
                rule = prefs_filter_edit_open(NULL, header, key);
160
                gtk_window_present(GTK_WINDOW(rule_list_window.window));
161
162
                if (rule) {
163
                        prefs_filter_set_list_row(NULL, rule, TRUE);
164
                        prefs_filter_set_list();
165
                }
166
        }
167
168
        rule_list_window.on_init = FALSE;
169
}
170
171
static void prefs_filter_create(void)
172
{
173
        GtkWidget *window;
174
        GtkWidget *vbox;
175
        GtkWidget *close_btn;
176
        GtkWidget *confirm_area;
177
178
        GtkWidget *hbox;
179
        GtkWidget *scrolledwin;
180
        GtkWidget *treeview;
181
        GtkListStore *store;
182
        GtkTreeSelection *selection;
183
        GtkTreeViewColumn *column;
184
        GtkCellRenderer *renderer;
185
186
        GtkWidget *btn_vbox;
187
        GtkWidget *spc_vbox;
188
        GtkWidget *top_btn;
189
        GtkWidget *up_btn;
190
        GtkWidget *down_btn;
191
        GtkWidget *bottom_btn;
192
193
        GtkWidget *btn_hbox;
194
        GtkWidget *add_btn;
195
        GtkWidget *edit_btn;
196
        GtkWidget *copy_btn;
197
        GtkWidget *del_btn;
198
        GtkWidget *image;
199
200
        debug_print("Creating filter setting window...\n");
201
202
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
203
        gtk_container_set_border_width(GTK_CONTAINER(window), 8);
204
        gtk_widget_set_size_request(window, 540, 360);
205
        gtk_window_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
206
        gtk_window_set_modal(GTK_WINDOW(window), TRUE);
207
        gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, FALSE);
208
209
        vbox = gtk_vbox_new(FALSE, 6);
210
        gtk_widget_show(vbox);
211
        gtk_container_add(GTK_CONTAINER(window), vbox);
212
213
        gtkut_stock_button_set_create(&confirm_area,
214
                                      &close_btn, GTK_STOCK_CLOSE,
215
                                      NULL, NULL, NULL, NULL);
216
        gtk_widget_show(confirm_area);
217
        gtk_box_pack_end(GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
218
        gtk_widget_grab_default(close_btn);
219
220
        gtk_window_set_title(GTK_WINDOW(window),
221
                             _("Filter settings"));
222
        g_signal_connect(G_OBJECT(window), "delete_event",
223
                         G_CALLBACK(prefs_filter_deleted), NULL);
224
        g_signal_connect(G_OBJECT(window), "key_press_event",
225
                         G_CALLBACK(prefs_filter_key_pressed), NULL);
226
        MANAGE_WINDOW_SIGNALS_CONNECT (window);
227
        g_signal_connect(G_OBJECT(close_btn), "clicked",
228
                         G_CALLBACK(prefs_filter_close), NULL);
229
230
        /* Rule list */
231
232
        hbox = gtk_hbox_new(FALSE, 8);
233
        gtk_widget_show(hbox);
234
        gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
235
236
        scrolledwin = gtk_scrolled_window_new(NULL, NULL);
237
        gtk_widget_show(scrolledwin);
238
        gtk_widget_set_size_request(scrolledwin, -1, 150);
239
        gtk_box_pack_start(GTK_BOX(hbox), scrolledwin, TRUE, TRUE, 0);
240
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
241
                                       GTK_POLICY_AUTOMATIC,
242
                                       GTK_POLICY_AUTOMATIC);
243
        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
244
                                            GTK_SHADOW_IN);
245
246
        store = gtk_list_store_new
247
                (N_COLS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER);
248
249
        treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
250
        g_object_unref(G_OBJECT(store));
251
        gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE);
252
        gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
253
        gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), COL_NAME);
254
        gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview), TRUE);
255
256
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
257
        gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
258
        gtk_tree_selection_set_select_function(selection, prefs_filter_select,
259
                                               NULL, NULL);
260
261
        renderer = gtk_cell_renderer_toggle_new();
262
        g_signal_connect(renderer, "toggled",
263
                         G_CALLBACK(prefs_filter_enable_toggled), NULL);
264
        column = gtk_tree_view_column_new_with_attributes
265
                (_("Enabled"), renderer, "active", COL_ENABLED, NULL);
266
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
267
268
        renderer = gtk_cell_renderer_text_new();
269
        column = gtk_tree_view_column_new_with_attributes
270
                (_("Name"), renderer, "text", COL_NAME, NULL);
271
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
272
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
273
274
        gtk_widget_show(treeview);
275
        gtk_container_add(GTK_CONTAINER(scrolledwin), treeview);
276
277
        g_signal_connect(G_OBJECT(treeview), "row-activated",
278
                         G_CALLBACK(prefs_filter_row_activated), NULL);
279
        g_signal_connect_after(G_OBJECT(store), "rows-reordered",
280
                               G_CALLBACK(prefs_filter_row_reordered), NULL);
281
282
        /* Up / Down */
283
284
        btn_vbox = gtk_vbox_new (FALSE, 8);
285
        gtk_widget_show(btn_vbox);
286
        gtk_box_pack_start(GTK_BOX(hbox), btn_vbox, FALSE, FALSE, 0);
287
288
        top_btn = gtk_button_new_from_stock(GTK_STOCK_GOTO_TOP);
289
        gtk_widget_show(top_btn);
290
        gtk_box_pack_start(GTK_BOX(btn_vbox), top_btn, FALSE, FALSE, 0);
291
        g_signal_connect(G_OBJECT(top_btn), "clicked",
292
                         G_CALLBACK(prefs_filter_top), NULL);
293
294
        PACK_VSPACER(btn_vbox, spc_vbox, VSPACING_NARROW_2);
295
296
        up_btn = gtk_button_new();
297
        image = gtk_image_new_from_stock(GTK_STOCK_GO_UP, GTK_ICON_SIZE_BUTTON);
298
        gtk_widget_show(image);
299
        gtk_button_set_image(GTK_BUTTON(up_btn), image);
300
        gtk_widget_show(up_btn);
301
        gtk_box_pack_start(GTK_BOX(btn_vbox), up_btn, FALSE, FALSE, 0);
302
        g_signal_connect(G_OBJECT(up_btn), "clicked",
303
                         G_CALLBACK(prefs_filter_up), NULL);
304
305
        down_btn = gtk_button_new();
306
        image = gtk_image_new_from_stock(GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON);
307
        gtk_widget_show(image);
308
        gtk_button_set_image(GTK_BUTTON(down_btn), image);
309
        gtk_widget_show(down_btn);
310
        gtk_box_pack_start(GTK_BOX(btn_vbox), down_btn, FALSE, FALSE, 0);
311
        g_signal_connect(G_OBJECT(down_btn), "clicked",
312
                         G_CALLBACK(prefs_filter_down), NULL);
313
314
        PACK_VSPACER(btn_vbox, spc_vbox, VSPACING_NARROW_2);
315
316
        bottom_btn = gtk_button_new_from_stock(GTK_STOCK_GOTO_BOTTOM);
317
        gtk_widget_show(bottom_btn);
318
        gtk_box_pack_start(GTK_BOX(btn_vbox), bottom_btn, FALSE, FALSE, 0);
319
        g_signal_connect(G_OBJECT(bottom_btn), "clicked",
320
                         G_CALLBACK(prefs_filter_bottom), NULL);
321
322
        /* add / edit / copy / delete */
323
324
        hbox = gtk_hbox_new(FALSE, 4);
325
        gtk_widget_show(hbox);
326
        gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
327
328
        btn_hbox = gtk_hbox_new(TRUE, 4);
329
        gtk_widget_show(btn_hbox);
330
        gtk_box_pack_start(GTK_BOX(hbox), btn_hbox, FALSE, FALSE, 0);
331
332
        add_btn = gtk_button_new_from_stock(GTK_STOCK_ADD);
333
        gtk_widget_show(add_btn);
334
        gtk_box_pack_start(GTK_BOX(btn_hbox), add_btn, FALSE, TRUE, 0);
335
        g_signal_connect(G_OBJECT(add_btn), "clicked",
336
                         G_CALLBACK(prefs_filter_add_cb), NULL);
337
338
#ifdef GTK_STOCK_EDIT
339
        edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
340
#else
341
        edit_btn = gtk_button_new_with_label(_("Edit"));
342
#endif
343
        gtk_widget_show(edit_btn);
344
        gtk_box_pack_start(GTK_BOX(btn_hbox), edit_btn, FALSE, TRUE, 0);
345
        g_signal_connect(G_OBJECT(edit_btn), "clicked",
346
                         G_CALLBACK(prefs_filter_edit_cb), NULL);
347
348
        copy_btn = gtk_button_new_from_stock(GTK_STOCK_COPY);
349
        gtk_widget_show(copy_btn);
350
        gtk_box_pack_start(GTK_BOX(btn_hbox), copy_btn, FALSE, TRUE, 0);
351
        g_signal_connect(G_OBJECT(copy_btn), "clicked",
352
                         G_CALLBACK(prefs_filter_copy_cb), NULL);
353
354
        del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
355
        gtk_widget_show(del_btn);
356
        gtk_box_pack_start(GTK_BOX(btn_hbox), del_btn, FALSE, TRUE, 0);
357
        g_signal_connect(G_OBJECT(del_btn), "clicked",
358
                         G_CALLBACK(prefs_filter_delete_cb), NULL);
359
360
        gtk_widget_show_all(window);
361
362
        rule_list_window.window = window;
363
        rule_list_window.close_btn = close_btn;
364
365
        rule_list_window.treeview = treeview;
366
        rule_list_window.store = store;
367
        rule_list_window.selection = selection;
368
369
        rule_list_window.add_btn = add_btn;
370
        rule_list_window.edit_btn = edit_btn;
371
        rule_list_window.copy_btn = copy_btn;
372
        rule_list_window.del_btn = del_btn;
373
374
        rule_list_window.default_hdr_list = NULL;
375
        rule_list_window.user_hdr_list = NULL;
376
        rule_list_window.msg_hdr_list = NULL;
377
        rule_list_window.msg_hdr_table = NULL;
378
}
379
380
static void prefs_filter_set_dialog(void)
381
{
382
        GSList *cur;
383
384
        gtk_list_store_clear(rule_list_window.store);
385
386
        for (cur = prefs_common.fltlist; cur != NULL; cur = cur->next) {
387
                FilterRule *rule = (FilterRule *)cur->data;
388
                prefs_filter_set_list_row(NULL, rule, FALSE);
389
        }
390
}
391
392
static void prefs_filter_set_list_row(GtkTreeIter *iter, FilterRule *rule,
393
                                      gboolean move_view)
394
{
395
        GtkListStore *store = rule_list_window.store;
396
        gchar *rule_name;
397
        GtkTreeIter iter_;
398
399
        g_return_if_fail(rule != NULL);
400
401
        if (rule->name && *rule->name)
402
                rule_name = g_strdup(rule->name);
403
        else
404
                rule_name = filter_get_str(rule);
405
406
        if (!iter) {
407
                gtk_list_store_append(store, &iter_);
408
                gtk_list_store_set(store, &iter_,
409
                                   COL_ENABLED, rule->enabled,
410
                                   COL_NAME, rule_name,
411
                                   COL_FILTER_RULE, rule, -1);
412
        } else {
413
                FilterRule *prev_rule = NULL;
414
415
                iter_ = *iter;
416
                gtk_tree_model_get(GTK_TREE_MODEL(store), &iter_,
417
                                   COL_FILTER_RULE, &prev_rule, -1);
418
                if (!prev_rule) {
419
                        g_warning("rule at the row not found\n");
420
                        gtk_list_store_append(store, &iter_);
421
                }
422
423
                gtk_list_store_set(store, &iter_,
424
                                   COL_ENABLED, rule->enabled,
425
                                   COL_NAME, rule_name,
426
                                   COL_FILTER_RULE, rule, -1);
427
428
                if (prev_rule && prev_rule != rule)
429
                        filter_rule_free(prev_rule);
430
        }
431
432
        g_free(rule_name);
433
434
        if (move_view) {
435
                GtkTreePath *path;
436
437
                path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter_);
438
                gtk_tree_view_scroll_to_cell
439
                        (GTK_TREE_VIEW(rule_list_window.treeview),
440
                         path, NULL, TRUE, 0.5, 0.0);
441
                gtk_tree_path_free(path);
442
        }
443
444
        rule_list_window.modified = TRUE;
445
}
446
447
#define APPEND_HDR_LIST(hdr_list)                                          \
448
        for (cur = hdr_list; cur != NULL; cur = cur->next) {                  \
449
                header = (Header *)cur->data;                                  \
450
                                                                          \
451
                if (!g_hash_table_lookup(table, header->name)) {          \
452
                        g_hash_table_insert(table, header->name, header); \
453
                        list = procheader_add_header_list                  \
454
                                (list, header->name, header->body);          \
455
                }                                                          \
456
        }
457
458
GSList *prefs_filter_get_header_list(void)
459
{
460
        GSList *list = NULL;
461
        GSList *cur;
462
        GHashTable *table;
463
        Header *header;
464
465
        table = g_hash_table_new(str_case_hash, str_case_equal);
466
467
        APPEND_HDR_LIST(rule_list_window.default_hdr_list)
468
        APPEND_HDR_LIST(rule_list_window.user_hdr_list);
469
        APPEND_HDR_LIST(rule_list_window.msg_hdr_list);
470
471
        g_hash_table_destroy(table);
472
473
        return list;
474
}
475
476
#undef APPEND_HDR_LIST
477
478
GSList *prefs_filter_get_user_header_list(void)
479
{
480
        return rule_list_window.user_hdr_list;
481
}
482
483
gchar *prefs_filter_get_msg_header_field(const gchar *header_name)
484
{
485
        if (!rule_list_window.msg_hdr_table)
486
                return NULL;
487
488
        return (gchar *)g_hash_table_lookup
489
                (rule_list_window.msg_hdr_table, header_name);
490
}
491
492
void prefs_filter_set_user_header_list(GSList *list)
493
{
494
        procheader_header_list_destroy(rule_list_window.user_hdr_list);
495
        rule_list_window.user_hdr_list = list;
496
}
497
498
void prefs_filter_set_msg_header_list(MsgInfo *msginfo)
499
{
500
        gchar *file;
501
        GSList *cur;
502
        GSList *next;
503
        Header *header;
504
505
        if (rule_list_window.msg_hdr_table) {
506
                g_hash_table_destroy(rule_list_window.msg_hdr_table);
507
                rule_list_window.msg_hdr_table = NULL;
508
        }
509
        if (rule_list_window.msg_hdr_list) {
510
                procheader_header_list_destroy(rule_list_window.msg_hdr_list);
511
                rule_list_window.msg_hdr_list = NULL;
512
        }
513
514
        if (!msginfo)
515
                return;
516
517
        file = procmsg_get_message_file(msginfo);
518
        g_return_if_fail(file != NULL);
519
520
        rule_list_window.msg_hdr_list =
521
                procheader_get_header_list_from_file(file);
522
523
        g_free(file);
524
525
        rule_list_window.msg_hdr_table =
526
                g_hash_table_new(str_case_hash, str_case_equal);
527
528
        for (cur = rule_list_window.msg_hdr_list; cur != NULL;
529
             cur = next) {
530
                next = cur->next;
531
                header = (Header *)cur->data;
532
                if (!g_ascii_strcasecmp(header->name, "Received") ||
533
                    !g_ascii_strcasecmp(header->name, "Mime-Version") ||
534
                    !g_ascii_strcasecmp(header->name, "X-UIDL")) {
535
                        procheader_header_free(header);
536
                        rule_list_window.msg_hdr_list =
537
                                g_slist_remove(rule_list_window.msg_hdr_list,
538
                                               header);
539
                        continue;
540
                }
541
                if (!g_hash_table_lookup(rule_list_window.msg_hdr_table,
542
                                         header->name)) {
543
                        g_hash_table_insert(rule_list_window.msg_hdr_table,
544
                                            header->name, header->body);
545
                }
546
        }
547
}
548
549
void prefs_filter_set_header_list(MsgInfo *msginfo)
550
{
551
        GSList *list = NULL;
552
        gchar *path;
553
        FILE *fp;
554
555
        list = procheader_add_header_list(list, "From", NULL);
556
        list = procheader_add_header_list(list, "To", NULL);
557
        list = procheader_add_header_list(list, "Cc", NULL);
558
        list = procheader_add_header_list(list, "Subject", NULL);
559
        list = procheader_add_header_list(list, "Reply-To", NULL);
560
        list = procheader_add_header_list(list, "List-Id", NULL);
561
        list = procheader_add_header_list(list, "X-ML-Name", NULL);
562
563
        procheader_header_list_destroy(rule_list_window.default_hdr_list);
564
        rule_list_window.default_hdr_list = list;
565
566
        list = NULL;
567
        path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_HEADER_RC,
568
                           NULL);
569
        if ((fp = g_fopen(path, "rb")) != NULL) {
570
                gchar buf[PREFSBUFSIZE];
571
572
                while (fgets(buf, sizeof(buf), fp) != NULL) {
573
                        g_strstrip(buf);
574
                        if (buf[0] == '\0') continue;
575
                        list = procheader_add_header_list(list, buf, NULL);
576
                }
577
578
                fclose(fp);
579
        } else
580
                if (ENOENT != errno) FILE_OP_ERROR(path, "fopen");
581
        g_free(path);
582
583
        prefs_filter_set_user_header_list(list);
584
        prefs_filter_set_msg_header_list(msginfo);
585
}
586
587
void prefs_filter_write_user_header_list(void)
588
{
589
        gchar *path;
590
        PrefFile *pfile;
591
        GSList *cur;
592
593
        path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_HEADER_RC,
594
                           NULL);
595
596
        if ((pfile = prefs_file_open(path)) == NULL) {
597
                g_warning("failed to write filter user header list\n");
598
                g_free(path);
599
                return;
600
        }
601
        g_free(path);
602
603
        for (cur = rule_list_window.user_hdr_list; cur != NULL;
604
             cur = cur->next) {
605
                Header *header = (Header *)cur->data;
606
                fputs(header->name, pfile->fp);
607
                fputc('\n', pfile->fp);
608
        }
609
610
        if (prefs_file_close(pfile) < 0)
611
                g_warning("failed to write filter user header list\n");
612
}
613
614
static void prefs_filter_set_list(void)
615
{
616
        FilterRule *rule;
617
        GtkTreeIter iter;
618
        GtkTreeModel *model = GTK_TREE_MODEL(rule_list_window.store);
619
620
        g_slist_free(prefs_common.fltlist);
621
        prefs_common.fltlist = NULL;
622
623
        if (!gtk_tree_model_get_iter_first(model, &iter))
624
                return;
625
626
        do {
627
                gtk_tree_model_get(model, &iter, COL_FILTER_RULE, &rule, -1);
628
                if (rule)
629
                        prefs_common.fltlist =
630
                                g_slist_append(prefs_common.fltlist, rule);
631
        } while (gtk_tree_model_iter_next(model, &iter));
632
}
633
634
static void prefs_filter_add_cb(void)
635
{
636
        FilterRule *rule;
637
638
        rule = prefs_filter_edit_open(NULL, NULL, NULL);
639
        gtk_window_present(GTK_WINDOW(rule_list_window.window));
640
641
        if (rule) {
642
                prefs_filter_set_list_row(NULL, rule, TRUE);
643
                prefs_filter_set_list();
644
        }
645
}
646
647
static void prefs_filter_edit_cb(void)
648
{
649
        GtkTreeIter iter;
650
        FilterRule *rule, *new_rule;
651
652
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
653
                                             NULL, &iter))
654
                return;
655
656
        gtk_tree_model_get(GTK_TREE_MODEL(rule_list_window.store), &iter,
657
                           COL_FILTER_RULE, &rule, -1);
658
        g_return_if_fail(rule != NULL);
659
660
        new_rule = prefs_filter_edit_open(rule, NULL, NULL);
661
        gtk_window_present(GTK_WINDOW(rule_list_window.window));
662
663
        if (new_rule) {
664
                prefs_filter_set_list_row(&iter, new_rule, TRUE);
665
                prefs_filter_set_list();
666
        }
667
}
668
669
static void prefs_filter_copy_cb(void)
670
{
671
        GtkTreeIter iter;
672
        FilterRule *rule, *new_rule;
673
674
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
675
                                             NULL, &iter))
676
                return;
677
678
        gtk_tree_model_get(GTK_TREE_MODEL(rule_list_window.store), &iter,
679
                           COL_FILTER_RULE, &rule, -1);
680
        g_return_if_fail(rule != NULL);
681
682
        new_rule = prefs_filter_edit_open(rule, NULL, NULL);
683
        gtk_window_present(GTK_WINDOW(rule_list_window.window));
684
685
        if (new_rule) {
686
                prefs_filter_set_list_row(NULL, new_rule, TRUE);
687
                prefs_filter_set_list();
688
        }
689
}
690
691
static void prefs_filter_delete_cb(void)
692
{
693
        GtkTreeIter iter;
694
        FilterRule *rule;
695
        gchar buf[BUFFSIZE];
696
        gboolean valid;
697
698
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
699
                                             NULL, &iter))
700
                return;
701
702
        gtk_tree_model_get(GTK_TREE_MODEL(rule_list_window.store), &iter,
703
                           COL_FILTER_RULE, &rule, -1);
704
        g_return_if_fail(rule != NULL);
705
706
        g_snprintf(buf, sizeof(buf),
707
                   _("Do you really want to delete the rule '%s'?"),
708
                   rule->name ? rule->name : _("(Untitled)"));
709
        if (alertpanel(_("Delete rule"), buf,
710
                       GTK_STOCK_YES, GTK_STOCK_NO, NULL) != G_ALERTDEFAULT)
711
                return;
712
713
        valid = gtk_list_store_remove(rule_list_window.store, &iter);
714
        if (valid)
715
                gtk_tree_selection_select_iter(rule_list_window.selection,
716
                                               &iter);
717
718
        prefs_common.fltlist = g_slist_remove(prefs_common.fltlist, rule);
719
        filter_rule_free(rule);
720
721
        rule_list_window.modified = TRUE;
722
}
723
724
static void prefs_filter_top(void)
725
{
726
        GtkTreeIter iter;
727
728
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
729
                                             NULL, &iter))
730
                return;
731
732
        gtk_list_store_move_after(rule_list_window.store, &iter, NULL);
733
}
734
735
static void prefs_filter_up(void)
736
{
737
        GtkTreeModel *model = GTK_TREE_MODEL(rule_list_window.store);
738
        GtkTreeIter iter, prev;
739
        GtkTreePath *path;
740
741
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
742
                                             NULL, &iter))
743
                return;
744
745
        path = gtk_tree_model_get_path(model, &iter);
746
        if (gtk_tree_path_prev(path)) {
747
                gtk_tree_model_get_iter(model, &prev, path);
748
                gtk_list_store_swap(rule_list_window.store, &iter, &prev);
749
        }
750
        gtk_tree_path_free(path);
751
}
752
753
static void prefs_filter_down(void)
754
{
755
        GtkTreeIter iter, next;
756
757
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
758
                                             NULL, &iter))
759
                return;
760
761
        next = iter;
762
        if (gtk_tree_model_iter_next(GTK_TREE_MODEL(rule_list_window.store),
763
                                     &next))
764
                gtk_list_store_swap(rule_list_window.store, &iter, &next);
765
}
766
767
static void prefs_filter_bottom(void)
768
{
769
        GtkTreeIter iter;
770
771
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
772
                                             NULL, &iter))
773
                return;
774
775
        gtk_list_store_move_before(rule_list_window.store, &iter, NULL);
776
}
777
778
static gboolean prefs_filter_select(GtkTreeSelection *selection,
779
                                    GtkTreeModel *model, GtkTreePath *path,
780
                                    gboolean cur_selected, gpointer data)
781
{
782
        return TRUE;
783
}
784
785
static void prefs_filter_enable_toggled(GtkCellRenderer *cell, gchar *path_str,
786
                                        gpointer data)
787
{
788
        FilterRule *rule;
789
        GtkTreeIter iter;
790
        GtkTreePath *path;
791
792
        path = gtk_tree_path_new_from_string(path_str);
793
        gtk_tree_model_get_iter(GTK_TREE_MODEL(rule_list_window.store),
794
                                &iter, path);
795
        gtk_tree_path_free(path);
796
        gtk_tree_model_get(GTK_TREE_MODEL(rule_list_window.store), &iter,
797
                           COL_FILTER_RULE, &rule, -1);
798
799
        rule->enabled ^= TRUE;
800
801
        gtk_list_store_set(rule_list_window.store, &iter,
802
                           COL_ENABLED, rule->enabled, -1);
803
        rule_list_window.modified = TRUE;
804
}
805
806
static void prefs_filter_row_activated(GtkTreeView *treeview, GtkTreePath *path,
807
                                       GtkTreeViewColumn *column,
808
                                       gpointer data)
809
{
810
        gtk_button_clicked(GTK_BUTTON(rule_list_window.edit_btn));
811
}
812
813
static void prefs_filter_row_reordered(GtkTreeModel *model,
814
                                       GtkTreePath *path, GtkTreeIter *iter,
815
                                       gpointer data, gpointer user_data)
816
{
817
        GtkTreeIter iter_;
818
        GtkTreePath *path_;
819
820
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
821
                                             NULL, &iter_))
822
                return;
823
        path_ = gtk_tree_model_get_path
824
                (GTK_TREE_MODEL(rule_list_window.store), &iter_);
825
        gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(rule_list_window.treeview),
826
                                     path_, NULL, FALSE, 0.0, 0.0);
827
        gtk_tree_path_free(path_);
828
        rule_list_window.modified = TRUE;
829
}
830
831
static gint prefs_filter_deleted(GtkWidget *widget, GdkEventAny *event,
832
                                 gpointer data)
833
{
834
        prefs_filter_close();
835
        return TRUE;
836
}
837
838
static gboolean prefs_filter_key_pressed(GtkWidget *widget, GdkEventKey *event,
839
                                         gpointer data)
840
{
841
        if (rule_list_window.on_init)
842
                return TRUE;
843
844
        if (event && event->keyval == GDK_Escape)
845
                prefs_filter_close();
846
        return FALSE;
847
}
848
849
static void prefs_filter_close(void)
850
{
851
        if (rule_list_window.on_init)
852
                return;
853
854
        prefs_filter_set_msg_header_list(NULL);
855
        if (rule_list_window.modified) {
856
                prefs_filter_set_list();
857
                filter_write_config();
858
        }
859
        gtk_widget_hide(rule_list_window.window);
860
        gtk_list_store_clear(rule_list_window.store);
861
        main_window_popup(main_window_get());
862
        inc_unlock();
863
}