Statistics
| Revision:

root / src / prefs_filter.c @ 542

History | View | Annotate | Download (22.9 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_rename_path(const gchar *old_path, const gchar *new_path)
364
{
365
        GSList *cur;
366
367
        g_return_if_fail(old_path != NULL);
368
        g_return_if_fail(new_path != NULL);
369
370
        for (cur = prefs_common.fltlist; cur != NULL; cur = cur->next) {
371
                FilterRule *rule = (FilterRule *)cur->data;
372
                filter_rule_rename_dest_path(rule, old_path, new_path);
373
        }
374
375
        filter_write_config();
376
}
377
378
void prefs_filter_delete_path(const gchar *path)
379
{
380
        GSList *cur;
381
        GSList *next;
382
383
        g_return_if_fail(path != NULL);
384
385
        for (cur = prefs_common.fltlist; cur != NULL; cur = next) {
386
                FilterRule *rule = (FilterRule *)cur->data;
387
                next = cur->next;
388
389
                filter_rule_delete_action_by_dest_path(rule, path);
390
                if (!rule->action_list) {
391
                        prefs_common.fltlist =
392
                                g_slist_remove(prefs_common.fltlist, rule);
393
                        filter_rule_free(rule);
394
                }
395
        }
396
397
        filter_write_config();
398
}
399
400
static void prefs_filter_set_dialog(void)
401
{
402
        GSList *cur;
403
404
        gtk_list_store_clear(rule_list_window.store);
405
406
        for (cur = prefs_common.fltlist; cur != NULL; cur = cur->next) {
407
                FilterRule *rule = (FilterRule *)cur->data;
408
                prefs_filter_set_list_row(NULL, rule, FALSE);
409
        }
410
}
411
412
static void prefs_filter_set_list_row(GtkTreeIter *iter, FilterRule *rule,
413
                                      gboolean move_view)
414
{
415
        GtkListStore *store = rule_list_window.store;
416
        gchar *rule_name;
417
        GtkTreeIter iter_;
418
419
        g_return_if_fail(rule != NULL);
420
421
        if (rule->name && *rule->name)
422
                rule_name = g_strdup(rule->name);
423
        else
424
                rule_name = filter_get_str(rule);
425
426
        if (!iter) {
427
                gtk_list_store_append(store, &iter_);
428
                gtk_list_store_set(store, &iter_,
429
                                   COL_ENABLED, rule->enabled,
430
                                   COL_NAME, rule_name,
431
                                   COL_FILTER_RULE, rule, -1);
432
        } else {
433
                FilterRule *prev_rule = NULL;
434
435
                iter_ = *iter;
436
                gtk_tree_model_get(GTK_TREE_MODEL(store), &iter_,
437
                                   COL_FILTER_RULE, &prev_rule, -1);
438
                if (!prev_rule) {
439
                        g_warning("rule at the row not found\n");
440
                        gtk_list_store_append(store, &iter_);
441
                }
442
443
                gtk_list_store_set(store, &iter_,
444
                                   COL_ENABLED, rule->enabled,
445
                                   COL_NAME, rule_name,
446
                                   COL_FILTER_RULE, rule, -1);
447
448
                if (prev_rule && prev_rule != rule)
449
                        filter_rule_free(prev_rule);
450
        }
451
452
        g_free(rule_name);
453
454
        if (move_view) {
455
                GtkTreePath *path;
456
457
                path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter_);
458
                gtk_tree_view_scroll_to_cell
459
                        (GTK_TREE_VIEW(rule_list_window.treeview),
460
                         path, NULL, TRUE, 0.5, 0.0);
461
                gtk_tree_path_free(path);
462
        }
463
}
464
465
#define APPEND_HDR_LIST(hdr_list)                                          \
466
        for (cur = hdr_list; cur != NULL; cur = cur->next) {                  \
467
                header = (Header *)cur->data;                                  \
468
                                                                          \
469
                if (!g_hash_table_lookup(table, header->name)) {          \
470
                        g_hash_table_insert(table, header->name, header); \
471
                        list = g_slist_append(list, header);                  \
472
                }                                                          \
473
        }
474
475
GSList *prefs_filter_get_header_list(void)
476
{
477
        GSList *list = NULL;
478
        GSList *cur;
479
        GHashTable *table;
480
        Header *header;
481
482
        table = g_hash_table_new(str_case_hash, str_case_equal);
483
484
        APPEND_HDR_LIST(rule_list_window.default_hdr_list)
485
        APPEND_HDR_LIST(rule_list_window.user_hdr_list);
486
        APPEND_HDR_LIST(rule_list_window.msg_hdr_list);
487
488
        g_hash_table_destroy(table);
489
490
        return list;
491
}
492
493
#undef APPEND_HDR_LIST
494
495
GSList *prefs_filter_get_user_header_list(void)
496
{
497
        return rule_list_window.user_hdr_list;
498
}
499
500
gchar *prefs_filter_get_msg_header_field(const gchar *header_name)
501
{
502
        if (!rule_list_window.msg_hdr_table)
503
                return NULL;
504
505
        return (gchar *)g_hash_table_lookup
506
                (rule_list_window.msg_hdr_table, header_name);
507
}
508
509
void prefs_filter_set_user_header_list(GSList *list)
510
{
511
        procheader_header_list_destroy(rule_list_window.user_hdr_list);
512
        rule_list_window.user_hdr_list = list;
513
}
514
515
void prefs_filter_set_msg_header_list(MsgInfo *msginfo)
516
{
517
        gchar *file;
518
        GSList *cur;
519
        GSList *next;
520
        Header *header;
521
522
        if (rule_list_window.msg_hdr_table) {
523
                g_hash_table_destroy(rule_list_window.msg_hdr_table);
524
                rule_list_window.msg_hdr_table = NULL;
525
        }
526
        if (rule_list_window.msg_hdr_list) {
527
                procheader_header_list_destroy(rule_list_window.msg_hdr_list);
528
                rule_list_window.msg_hdr_list = NULL;
529
        }
530
531
        if (!msginfo)
532
                return;
533
534
        file = procmsg_get_message_file(msginfo);
535
        g_return_if_fail(file != NULL);
536
537
        rule_list_window.msg_hdr_list =
538
                procheader_get_header_list_from_file(file);
539
540
        g_free(file);
541
542
        rule_list_window.msg_hdr_table =
543
                g_hash_table_new(str_case_hash, str_case_equal);
544
545
        for (cur = rule_list_window.msg_hdr_list; cur != NULL;
546
             cur = next) {
547
                next = cur->next;
548
                header = (Header *)cur->data;
549
                if (!g_ascii_strcasecmp(header->name, "Received") ||
550
                    !g_ascii_strcasecmp(header->name, "Mime-Version") ||
551
                    !g_ascii_strcasecmp(header->name, "X-UIDL")) {
552
                        procheader_header_free(header);
553
                        rule_list_window.msg_hdr_list =
554
                                g_slist_remove(rule_list_window.msg_hdr_list,
555
                                               header);
556
                        continue;
557
                }
558
                if (!g_hash_table_lookup(rule_list_window.msg_hdr_table,
559
                                         header->name)) {
560
                        g_hash_table_insert(rule_list_window.msg_hdr_table,
561
                                            header->name, header->body);
562
                }
563
        }
564
}
565
566
static void prefs_filter_set_header_list(MsgInfo *msginfo)
567
{
568
        GSList *list = NULL;
569
        gchar *path;
570
        FILE *fp;
571
572
        list = procheader_add_header_list(list, "From", NULL);
573
        list = procheader_add_header_list(list, "To", NULL);
574
        list = procheader_add_header_list(list, "Cc", NULL);
575
        list = procheader_add_header_list(list, "Subject", NULL);
576
        list = procheader_add_header_list(list, "Reply-To", NULL);
577
        list = procheader_add_header_list(list, "List-Id", NULL);
578
        list = procheader_add_header_list(list, "X-ML-Name", NULL);
579
580
        procheader_header_list_destroy(rule_list_window.default_hdr_list);
581
        rule_list_window.default_hdr_list = list;
582
583
        list = NULL;
584
        path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_HEADER_RC,
585
                           NULL);
586
        if ((fp = g_fopen(path, "rb")) != NULL) {
587
                gchar buf[PREFSBUFSIZE];
588
589
                while (fgets(buf, sizeof(buf), fp) != NULL) {
590
                        g_strstrip(buf);
591
                        if (buf[0] == '\0') continue;
592
                        list = procheader_add_header_list(list, buf, NULL);
593
                }
594
595
                fclose(fp);
596
        } else
597
                if (ENOENT != errno) FILE_OP_ERROR(path, "fopen");
598
        g_free(path);
599
600
        prefs_filter_set_user_header_list(list);
601
602
        prefs_filter_set_msg_header_list(msginfo);
603
}
604
605
static void prefs_filter_write_user_header_list(void)
606
{
607
        gchar *path;
608
        PrefFile *pfile;
609
        GSList *cur;
610
611
        path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_HEADER_RC,
612
                           NULL);
613
614
        if ((pfile = prefs_file_open(path)) == NULL) {
615
                g_warning("failed to write filter user header list\n");
616
                g_free(path);
617
                return;
618
        }
619
        g_free(path);
620
621
        for (cur = rule_list_window.user_hdr_list; cur != NULL;
622
             cur = cur->next) {
623
                Header *header = (Header *)cur->data;
624
                fputs(header->name, pfile->fp);
625
                fputc('\n', pfile->fp);
626
        }
627
628
        if (prefs_file_close(pfile) < 0)
629
                g_warning("failed to write filter user header list\n");
630
}
631
632
static void prefs_filter_set_list(void)
633
{
634
        FilterRule *rule;
635
        GtkTreeIter iter;
636
        GtkTreeModel *model = GTK_TREE_MODEL(rule_list_window.store);
637
638
        g_slist_free(prefs_common.fltlist);
639
        prefs_common.fltlist = NULL;
640
641
        if (!gtk_tree_model_get_iter_first(model, &iter))
642
                return;
643
644
        do {
645
                gtk_tree_model_get(model, &iter, COL_FILTER_RULE, &rule, -1);
646
                if (rule)
647
                        prefs_common.fltlist =
648
                                g_slist_append(prefs_common.fltlist, rule);
649
        } while (gtk_tree_model_iter_next(model, &iter));
650
}
651
652
static void prefs_filter_add_cb(void)
653
{
654
        FilterRule *rule;
655
656
        rule = prefs_filter_edit_open(NULL, NULL);
657
658
        if (rule) {
659
                prefs_filter_set_list_row(NULL, rule, TRUE);
660
                prefs_filter_set_list();
661
        }
662
}
663
664
static void prefs_filter_edit_cb(void)
665
{
666
        GtkTreeIter iter;
667
        FilterRule *rule, *new_rule;
668
669
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
670
                                             NULL, &iter))
671
                return;
672
673
        gtk_tree_model_get(GTK_TREE_MODEL(rule_list_window.store), &iter,
674
                           COL_FILTER_RULE, &rule, -1);
675
        g_return_if_fail(rule != NULL);
676
677
        new_rule = prefs_filter_edit_open(rule, NULL);
678
679
        if (new_rule) {
680
                prefs_filter_set_list_row(&iter, new_rule, TRUE);
681
                prefs_filter_set_list();
682
        }
683
}
684
685
static void prefs_filter_copy_cb(void)
686
{
687
        GtkTreeIter iter;
688
        FilterRule *rule, *new_rule;
689
690
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
691
                                             NULL, &iter))
692
                return;
693
694
        gtk_tree_model_get(GTK_TREE_MODEL(rule_list_window.store), &iter,
695
                           COL_FILTER_RULE, &rule, -1);
696
        g_return_if_fail(rule != NULL);
697
698
        new_rule = prefs_filter_edit_open(rule, NULL);
699
700
        if (new_rule) {
701
                prefs_filter_set_list_row(NULL, new_rule, TRUE);
702
                prefs_filter_set_list();
703
        }
704
}
705
706
static void prefs_filter_delete_cb(void)
707
{
708
        GtkTreeIter iter;
709
        FilterRule *rule;
710
        gchar buf[BUFFSIZE];
711
        gboolean valid;
712
713
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
714
                                             NULL, &iter))
715
                return;
716
717
        gtk_tree_model_get(GTK_TREE_MODEL(rule_list_window.store), &iter,
718
                           COL_FILTER_RULE, &rule, -1);
719
        g_return_if_fail(rule != NULL);
720
721
        g_snprintf(buf, sizeof(buf),
722
                   _("Do you really want to delete the rule '%s'?"),
723
                   rule->name ? rule->name : _("(Untitled)"));
724
        if (alertpanel(_("Delete rule"), buf,
725
                       GTK_STOCK_YES, GTK_STOCK_NO, NULL) != G_ALERTDEFAULT)
726
                return;
727
728
        valid = gtk_list_store_remove(rule_list_window.store, &iter);
729
        if (valid)
730
                gtk_tree_selection_select_iter(rule_list_window.selection,
731
                                               &iter);
732
733
        prefs_common.fltlist = g_slist_remove(prefs_common.fltlist, rule);
734
        filter_rule_free(rule);
735
}
736
737
static void prefs_filter_top(void)
738
{
739
        GtkTreeIter iter;
740
741
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
742
                                             NULL, &iter))
743
                return;
744
745
        gtk_list_store_move_after(rule_list_window.store, &iter, NULL);
746
}
747
748
static void prefs_filter_up(void)
749
{
750
        GtkTreeModel *model = GTK_TREE_MODEL(rule_list_window.store);
751
        GtkTreeIter iter, prev;
752
        GtkTreePath *path;
753
754
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
755
                                             NULL, &iter))
756
                return;
757
758
        path = gtk_tree_model_get_path(model, &iter);
759
        if (gtk_tree_path_prev(path)) {
760
                gtk_tree_model_get_iter(model, &prev, path);
761
                gtk_list_store_swap(rule_list_window.store, &iter, &prev);
762
        }
763
        gtk_tree_path_free(path);
764
}
765
766
static void prefs_filter_down(void)
767
{
768
        GtkTreeIter iter, next;
769
770
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
771
                                             NULL, &iter))
772
                return;
773
774
        next = iter;
775
        if (gtk_tree_model_iter_next(GTK_TREE_MODEL(rule_list_window.store),
776
                                     &next))
777
                gtk_list_store_swap(rule_list_window.store, &iter, &next);
778
}
779
780
static void prefs_filter_bottom(void)
781
{
782
        GtkTreeIter iter;
783
784
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
785
                                             NULL, &iter))
786
                return;
787
788
        gtk_list_store_move_before(rule_list_window.store, &iter, NULL);
789
}
790
791
static gboolean prefs_filter_select(GtkTreeSelection *selection,
792
                                    GtkTreeModel *model, GtkTreePath *path,
793
                                    gboolean cur_selected, gpointer data)
794
{
795
        return TRUE;
796
}
797
798
static void prefs_filter_enable_toggled(GtkCellRenderer *cell, gchar *path_str,
799
                                        gpointer data)
800
{
801
        FilterRule *rule;
802
        GtkTreeIter iter;
803
        GtkTreePath *path;
804
805
        path = gtk_tree_path_new_from_string(path_str);
806
        gtk_tree_model_get_iter(GTK_TREE_MODEL(rule_list_window.store),
807
                                &iter, path);
808
        gtk_tree_path_free(path);
809
        gtk_tree_model_get(GTK_TREE_MODEL(rule_list_window.store), &iter,
810
                           COL_FILTER_RULE, &rule, -1);
811
812
        rule->enabled ^= TRUE;
813
814
        gtk_list_store_set(rule_list_window.store, &iter,
815
                           COL_ENABLED, rule->enabled, -1);
816
}
817
818
static void prefs_filter_row_activated(GtkTreeView *treeview, GtkTreePath *path,
819
                                       GtkTreeViewColumn *column,
820
                                       gpointer data)
821
{
822
        gtk_button_clicked(GTK_BUTTON(rule_list_window.edit_btn));
823
}
824
825
static void prefs_filter_row_reordered(GtkTreeModel *model,
826
                                       GtkTreePath *path, GtkTreeIter *iter,
827
                                       gpointer data, gpointer user_data)
828
{
829
        GtkTreeIter iter_;
830
        GtkTreePath *path_;
831
832
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
833
                                             NULL, &iter_))
834
                return;
835
        path_ = gtk_tree_model_get_path
836
                (GTK_TREE_MODEL(rule_list_window.store), &iter_);
837
        gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(rule_list_window.treeview),
838
                                     path_, NULL, FALSE, 0.0, 0.0);
839
        gtk_tree_path_free(path_);
840
}
841
842
static gint prefs_filter_deleted(GtkWidget *widget, GdkEventAny *event,
843
                                 gpointer data)
844
{
845
        prefs_filter_close();
846
        return TRUE;
847
}
848
849
static gboolean prefs_filter_key_pressed(GtkWidget *widget, GdkEventKey *event,
850
                                         gpointer data)
851
{
852
        if (event && event->keyval == GDK_Escape)
853
                prefs_filter_close();
854
        return FALSE;
855
}
856
857
static void prefs_filter_close(void)
858
{
859
        prefs_filter_set_msg_header_list(NULL);
860
        prefs_filter_write_user_header_list();
861
        prefs_filter_set_list();
862
        filter_write_config();
863
        gtk_widget_hide(rule_list_window.window);
864
        gtk_list_store_clear(rule_list_window.store);
865
        inc_unlock();
866
}