Statistics
| Revision:

root / src / prefs_filter.c @ 703

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