Statistics
| Revision:

root / src / prefs_filter.c @ 478

History | View | Annotate | Download (23.7 kB)

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