Statistics
| Revision:

root / src / prefs_filter.c @ 527

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