Statistics
| Revision:

root / src / prefs_filter.c @ 1

History | View | Annotate | Download (21 KB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2004 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 <gtk/gtk.h>
28
#include <gdk/gdkkeysyms.h>
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include <errno.h>
33

    
34
#include "intl.h"
35
#include "main.h"
36
#include "prefs.h"
37
#include "prefs_filter.h"
38
#include "prefs_filter_edit.h"
39
#include "prefs_common.h"
40
#include "mainwindow.h"
41
#include "foldersel.h"
42
#include "manage_window.h"
43
#include "stock_pixmap.h"
44
#include "inc.h"
45
#include "procheader.h"
46
#include "menu.h"
47
#include "filter.h"
48
#include "utils.h"
49
#include "gtkutils.h"
50
#include "alertpanel.h"
51
#include "xml.h"
52

    
53
static struct FilterRuleListWindow {
54
        GtkWidget *window;
55

    
56
        GtkWidget *clist;
57

    
58
        GtkWidget *add_btn;
59
        GtkWidget *edit_btn;
60
        GtkWidget *copy_btn;
61
        GtkWidget *del_btn;
62

    
63
        GSList *default_hdr_list;
64
        GSList *user_hdr_list;
65
        GSList *msg_hdr_list;
66

    
67
        GHashTable *msg_hdr_table;
68

    
69
        GtkWidget *close_btn;
70
} rule_list_window;
71

    
72
static GdkPixmap *markxpm;
73
static GdkBitmap *markxpmmask;
74

    
75
static void prefs_filter_create                        (void);
76

    
77
//static void prefs_filter_read_old_config        (void);
78

    
79
static void prefs_filter_set_dialog                (void);
80
static void prefs_filter_set_list_row                (gint                 row,
81
                                                 FilterRule        *rule,
82
                                                 gboolean         move_view);
83

    
84
static void prefs_filter_set_header_list        (MsgInfo        *msginfo);
85

    
86
static void prefs_filter_write_user_header_list        (void);
87

    
88
static void prefs_filter_set_list                (void);
89

    
90
/* callback functions */
91
static void prefs_filter_add_cb                (void);
92
static void prefs_filter_edit_cb        (void);
93
static void prefs_filter_copy_cb        (void);
94
static void prefs_filter_delete_cb        (void);
95
static void prefs_filter_top                (void);
96
static void prefs_filter_up                (void);
97
static void prefs_filter_down                (void);
98
static void prefs_filter_bottom                (void);
99

    
100
static void prefs_filter_select                (GtkCList        *clist,
101
                                         gint                 row,
102
                                         gint                 column,
103
                                         GdkEvent        *event);
104
static void prefs_filter_row_move        (GtkCList        *clist,
105
                                         gint                 source_row,
106
                                         gint                 dest_row);
107

    
108
static gint prefs_filter_deleted        (GtkWidget        *widget,
109
                                         GdkEventAny        *event,
110
                                         gpointer         data);
111
static gboolean prefs_filter_key_pressed(GtkWidget        *widget,
112
                                         GdkEventKey        *event,
113
                                         gpointer         data);
114
static void prefs_filter_close                (void);
115

    
116

    
117
void prefs_filter_open(MsgInfo *msginfo, const gchar *header)
118
{
119
        inc_lock();
120

    
121
        if (!rule_list_window.window)
122
                prefs_filter_create();
123

    
124
        prefs_filter_set_header_list(msginfo);
125

    
126
        manage_window_set_transient(GTK_WINDOW(rule_list_window.window));
127
        gtk_widget_grab_focus(rule_list_window.close_btn);
128

    
129
        prefs_filter_set_dialog();
130

    
131
        gtk_widget_show(rule_list_window.window);
132

    
133
        if (msginfo) {
134
                FilterRule *rule;
135

    
136
                rule = prefs_filter_edit_open(NULL, header);
137

    
138
                if (rule) {
139
                        prefs_filter_set_list_row(-1, rule, TRUE);
140
                        prefs_filter_set_list();
141
                }
142
        }
143
}
144

    
145
static void prefs_filter_create(void)
146
{
147
        GtkWidget *window;
148
        GtkWidget *vbox;
149
        GtkWidget *close_btn;
150
        GtkWidget *confirm_area;
151

    
152
        GtkWidget *hbox;
153
        GtkWidget *scrolledwin;
154
        GtkWidget *clist;
155

    
156
        GtkWidget *btn_vbox;
157
        GtkWidget *spc_vbox;
158
        GtkWidget *top_btn;
159
        GtkWidget *up_btn;
160
        GtkWidget *down_btn;
161
        GtkWidget *bottom_btn;
162

    
163
        GtkWidget *btn_hbox;
164
        GtkWidget *add_btn;
165
        GtkWidget *edit_btn;
166
        GtkWidget *copy_btn;
167
        GtkWidget *del_btn;
168

    
169
        gchar *title[2];
170

    
171
        debug_print("Creating filter setting window...\n");
172

    
173
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
174
        gtk_container_set_border_width(GTK_CONTAINER(window), 8);
175
        gtk_widget_set_usize(window, 540, 360);
176
        gtk_window_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
177
        gtk_window_set_modal(GTK_WINDOW(window), TRUE);
178
        gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, FALSE);
179

    
180
        vbox = gtk_vbox_new(FALSE, 6);
181
        gtk_widget_show(vbox);
182
        gtk_container_add(GTK_CONTAINER(window), vbox);
183

    
184
        gtkut_button_set_create(&confirm_area, &close_btn, _("Close"),
185
                                NULL, NULL, NULL, NULL);
186
        gtk_widget_show(confirm_area);
187
        gtk_box_pack_end(GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
188
        gtk_widget_grab_default(close_btn);
189

    
190
        gtk_window_set_title(GTK_WINDOW(window),
191
                             _("Filter setting"));
192
        g_signal_connect(G_OBJECT(window), "delete_event",
193
                         G_CALLBACK(prefs_filter_deleted), NULL);
194
        g_signal_connect(G_OBJECT(window), "key_press_event",
195
                         G_CALLBACK(prefs_filter_key_pressed), NULL);
196
        MANAGE_WINDOW_SIGNALS_CONNECT (window);
197
        g_signal_connect(G_OBJECT(close_btn), "clicked",
198
                         G_CALLBACK(prefs_filter_close), NULL);
199

    
200
        /* Rule list */
201

    
202
        hbox = gtk_hbox_new(FALSE, 8);
203
        gtk_widget_show(hbox);
204
        gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
205

    
206
        scrolledwin = gtk_scrolled_window_new(NULL, NULL);
207
        gtk_widget_show(scrolledwin);
208
        gtk_widget_set_usize(scrolledwin, -1, 150);
209
        gtk_box_pack_start(GTK_BOX(hbox), scrolledwin, TRUE, TRUE, 0);
210
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
211
                                       GTK_POLICY_AUTOMATIC,
212
                                       GTK_POLICY_AUTOMATIC);
213

    
214
        title[0] = _("Enabled");
215
        title[1] = _("Name");
216
        clist = gtk_clist_new_with_titles(2, title);
217
        gtk_widget_show(clist);
218
        gtk_container_add (GTK_CONTAINER(scrolledwin), clist);
219
        gtk_clist_set_column_width(GTK_CLIST(clist), 0, 64);
220
        gtk_clist_set_column_justification(GTK_CLIST(clist), 0,
221
                                           GTK_JUSTIFY_CENTER);
222
        gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_BROWSE);
223
        GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[0].button,
224
                               GTK_CAN_FOCUS);
225
        GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[1].button,
226
                               GTK_CAN_FOCUS);
227
        g_signal_connect(G_OBJECT(clist), "select_row",
228
                         G_CALLBACK(prefs_filter_select), NULL);
229
        g_signal_connect_after(G_OBJECT(clist), "row_move",
230
                               G_CALLBACK(prefs_filter_row_move), NULL);
231

    
232
        /* Up / Down */
233

    
234
        btn_vbox = gtk_vbox_new (FALSE, 8);
235
        gtk_widget_show(btn_vbox);
236
        gtk_box_pack_start(GTK_BOX(hbox), btn_vbox, FALSE, FALSE, 0);
237

    
238
        top_btn = gtk_button_new_with_label(_("Top"));
239
        gtk_widget_show(top_btn);
240
        gtk_box_pack_start(GTK_BOX(btn_vbox), top_btn, FALSE, FALSE, 0);
241
        g_signal_connect(G_OBJECT(top_btn), "clicked",
242
                         G_CALLBACK(prefs_filter_top), NULL);
243

    
244
        PACK_VSPACER(btn_vbox, spc_vbox, VSPACING_NARROW_2);
245

    
246
        up_btn = gtk_button_new_with_label(_("Up"));
247
        gtk_widget_show(up_btn);
248
        gtk_box_pack_start(GTK_BOX(btn_vbox), up_btn, FALSE, FALSE, 0);
249
        g_signal_connect(G_OBJECT(up_btn), "clicked",
250
                         G_CALLBACK(prefs_filter_up), NULL);
251

    
252
        down_btn = gtk_button_new_with_label(_("Down"));
253
        gtk_widget_show(down_btn);
254
        gtk_box_pack_start(GTK_BOX(btn_vbox), down_btn, FALSE, FALSE, 0);
255
        g_signal_connect(G_OBJECT(down_btn), "clicked",
256
                         G_CALLBACK(prefs_filter_down), NULL);
257

    
258
        PACK_VSPACER(btn_vbox, spc_vbox, VSPACING_NARROW_2);
259

    
260
        bottom_btn = gtk_button_new_with_label(_("Bottom"));
261
        gtk_widget_show(bottom_btn);
262
        gtk_box_pack_start(GTK_BOX(btn_vbox), bottom_btn, FALSE, FALSE, 0);
263
        g_signal_connect(G_OBJECT(bottom_btn), "clicked",
264
                         G_CALLBACK(prefs_filter_bottom), NULL);
265

    
266
        /* add / edit / copy / delete */
267

    
268
        hbox = gtk_hbox_new(FALSE, 4);
269
        gtk_widget_show(hbox);
270
        gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
271

    
272
        btn_hbox = gtk_hbox_new(TRUE, 4);
273
        gtk_widget_show(btn_hbox);
274
        gtk_box_pack_start(GTK_BOX(hbox), btn_hbox, FALSE, FALSE, 0);
275

    
276
        add_btn = gtk_button_new_with_label(_("Add"));
277
        gtk_widget_show(add_btn);
278
        gtk_box_pack_start(GTK_BOX(btn_hbox), add_btn, FALSE, TRUE, 0);
279
        g_signal_connect(G_OBJECT(add_btn), "clicked",
280
                         G_CALLBACK(prefs_filter_add_cb), NULL);
281

    
282
        edit_btn = gtk_button_new_with_label(_("Edit"));
283
        gtk_widget_show(edit_btn);
284
        gtk_box_pack_start(GTK_BOX(btn_hbox), edit_btn, FALSE, TRUE, 0);
285
        g_signal_connect(G_OBJECT(edit_btn), "clicked",
286
                         G_CALLBACK(prefs_filter_edit_cb), NULL);
287

    
288
        copy_btn = gtk_button_new_with_label(_("Copy"));
289
        gtk_widget_show(copy_btn);
290
        gtk_box_pack_start(GTK_BOX(btn_hbox), copy_btn, FALSE, TRUE, 0);
291
        g_signal_connect(G_OBJECT(copy_btn), "clicked",
292
                         G_CALLBACK(prefs_filter_copy_cb), NULL);
293

    
294
        del_btn = gtk_button_new_with_label(_(" Delete "));
295
        gtk_widget_show(del_btn);
296
        gtk_box_pack_start(GTK_BOX(btn_hbox), del_btn, FALSE, TRUE, 0);
297
        g_signal_connect(G_OBJECT(del_btn), "clicked",
298
                         G_CALLBACK(prefs_filter_delete_cb), NULL);
299

    
300
        gtk_widget_show_all(window);
301

    
302
        stock_pixmap_gdk(clist, STOCK_PIXMAP_MARK, &markxpm, &markxpmmask);
303

    
304
        rule_list_window.window = window;
305
        rule_list_window.close_btn = close_btn;
306

    
307
        rule_list_window.clist = clist;
308

    
309
        rule_list_window.default_hdr_list  = NULL;
310
        rule_list_window.user_hdr_list  = NULL;
311
        rule_list_window.msg_hdr_list  = NULL;
312
        rule_list_window.msg_hdr_table = NULL;
313
}
314

    
315
void prefs_filter_read_config(void)
316
{
317
        gchar *rcpath;
318
        GNode *node;
319
        FilterRule *rule;
320

    
321
        debug_print("Reading filter configuration...\n");
322

    
323
        /* remove all previous filter list */
324
        while (prefs_common.fltlist != NULL) {
325
                rule = (FilterRule *)prefs_common.fltlist->data;
326
                filter_rule_free(rule);
327
                prefs_common.fltlist = g_slist_remove(prefs_common.fltlist,
328
                                                      rule);
329
        }
330

    
331
#warning FIXME_GTK2
332
        rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_LIST,
333
                             NULL);
334
        if (!is_file_exist(rcpath)) {
335
                //prefs_filter_read_old_config();
336
                g_free(rcpath);
337
                return;
338
        }
339

    
340
        node = xml_parse_file(rcpath);
341
        if (!node) {
342
                g_warning("Can't parse %s\n", rcpath);
343
                g_free(rcpath);
344
                return;
345
        }
346
        g_free(rcpath);
347

    
348
        prefs_common.fltlist = filter_xml_node_to_filter_list(node);
349

    
350
        xml_free_tree(node);
351
}
352

    
353
#if 0
354
static void prefs_filter_read_old_config(void)
355
{
356
        gchar *rcpath;
357
        FILE *fp;
358
        gchar buf[PREFSBUFSIZE];
359
        FilterRule *rule;
360

361
        debug_print("Reading old filter configuration...\n");
362

363
        rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_RC, NULL);
364
        if ((fp = fopen(rcpath, "rb")) == NULL) {
365
                if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
366
                g_free(rcpath);
367
                return;
368
        }
369
        g_free(rcpath);
370

371
        while (fgets(buf, sizeof(buf), fp) != NULL) {
372
                g_strchomp(buf);
373
                rule = filter_read_str(buf);
374
                if (rule) {
375
                        prefs_common.fltlist =
376
                                g_slist_append(prefs_common.fltlist, rule);
377
                }
378
        }
379

380
        fclose(fp);
381
}
382
#endif
383

    
384
void prefs_filter_write_config(void)
385
{
386
        filter_write_config(prefs_common.fltlist);
387
}
388

    
389
void prefs_filter_rename_path(const gchar *old_path, const gchar *new_path)
390
{
391
        GSList *cur;
392

    
393
        g_return_if_fail(old_path != NULL);
394
        g_return_if_fail(new_path != NULL);
395

    
396
        for (cur = prefs_common.fltlist; cur != NULL; cur = cur->next) {
397
                FilterRule *rule = (FilterRule *)cur->data;
398
                filter_rule_rename_dest_path(rule, old_path, new_path);
399
        }
400

    
401
        filter_write_config(prefs_common.fltlist);
402
}
403

    
404
void prefs_filter_delete_path(const gchar *path)
405
{
406
        GSList *cur;
407
        GSList *next;
408

    
409
        g_return_if_fail(path != NULL);
410

    
411
        for (cur = prefs_common.fltlist; cur != NULL; cur = next) {
412
                FilterRule *rule = (FilterRule *)cur->data;
413
                next = cur->next;
414

    
415
                filter_rule_delete_action_by_dest_path(rule, path);
416
                if (!rule->action_list) {
417
                        prefs_common.fltlist =
418
                                g_slist_remove(prefs_common.fltlist, rule);
419
                        filter_rule_free(rule);
420
                }
421
        }
422

    
423
        filter_write_config(prefs_common.fltlist);
424
}
425

    
426
static void prefs_filter_set_dialog(void)
427
{
428
        GtkCList *clist = GTK_CLIST(rule_list_window.clist);
429
        GSList *cur;
430

    
431
        gtk_clist_freeze(clist);
432
        gtk_clist_clear(clist);
433

    
434
        for (cur = prefs_common.fltlist; cur != NULL; cur = cur->next) {
435
                FilterRule *rule = (FilterRule *)cur->data;
436
                prefs_filter_set_list_row(-1, rule, FALSE);
437
        }
438

    
439
        gtk_clist_thaw(clist);
440
}
441

    
442
static void prefs_filter_set_list_row(gint row, FilterRule *rule,
443
                                      gboolean move_view)
444
{
445
        GtkCList *clist = GTK_CLIST(rule_list_window.clist);
446
        gchar *cond_str[2] = {"", NULL};
447

    
448
        if (!rule)
449
                rule = gtk_clist_get_row_data(clist, row);
450

    
451
        g_return_if_fail(rule != NULL);
452

    
453
        if (rule->name && *rule->name)
454
                cond_str[1] = g_strdup(rule->name);
455
        else {
456
                cond_str[1] = filter_get_str(rule);
457
        }
458

    
459
        if (row < 0)
460
                row = gtk_clist_append(clist, cond_str);
461
        else {
462
                FilterRule *prev_rule;
463

    
464
                prev_rule = gtk_clist_get_row_data(clist, row);
465
                if (rule == prev_rule)
466
                        gtk_clist_set_text(clist, row, 1, cond_str[1]);
467
                else if (prev_rule) {
468
                        gtk_clist_set_text(clist, row, 1, cond_str[1]);
469
                        filter_rule_free(prev_rule);
470
                } else
471
                        row = gtk_clist_append(clist, cond_str);
472
        }
473

    
474
        if (rule->enabled)
475
                gtk_clist_set_pixmap(clist, row, 0, markxpm, markxpmmask);
476
        else
477
                gtk_clist_set_text(clist, row, 0, "");
478

    
479
        gtk_clist_set_row_data(clist, row, rule);
480
        g_free(cond_str[1]);
481

    
482
        if (move_view &&
483
            gtk_clist_row_is_visible(clist, row) != GTK_VISIBILITY_FULL)
484
                gtk_clist_moveto(clist, row, -1, 0.5, 0.0);
485
}
486

    
487
#define APPEND_HDR_LIST(hdr_list)                                          \
488
        for (cur = hdr_list; cur != NULL; cur = cur->next) {                  \
489
                header = (Header *)cur->data;                                  \
490
                                                                          \
491
                if (!g_hash_table_lookup(table, header->name)) {          \
492
                        g_hash_table_insert(table, header->name, header); \
493
                        list = g_slist_append(list, header);                  \
494
                }                                                          \
495
        }
496

    
497
GSList *prefs_filter_get_header_list(void)
498
{
499
        GSList *list = NULL;
500
        GSList *cur;
501
        GHashTable *table;
502
        Header *header;
503

    
504
        table = g_hash_table_new(str_case_hash, str_case_equal);
505

    
506
        APPEND_HDR_LIST(rule_list_window.default_hdr_list)
507
        APPEND_HDR_LIST(rule_list_window.user_hdr_list);
508
        APPEND_HDR_LIST(rule_list_window.msg_hdr_list);
509

    
510
        g_hash_table_destroy(table);
511

    
512
        return list;
513
}
514

    
515
#undef APPEND_HDR_LIST
516

    
517
GSList *prefs_filter_get_user_header_list(void)
518
{
519
        return rule_list_window.user_hdr_list;
520
}
521

    
522
gchar *prefs_filter_get_msg_header_field(const gchar *header_name)
523
{
524
        if (!rule_list_window.msg_hdr_table)
525
                return NULL;
526

    
527
        return (gchar *)g_hash_table_lookup
528
                (rule_list_window.msg_hdr_table, header_name);
529
}
530

    
531
void prefs_filter_set_user_header_list(GSList *list)
532
{
533
        procheader_header_list_destroy(rule_list_window.user_hdr_list);
534
        rule_list_window.user_hdr_list = list;
535
}
536

    
537
void prefs_filter_set_msg_header_list(MsgInfo *msginfo)
538
{
539
        gchar *file;
540
        GSList *cur;
541
        GSList *next;
542
        Header *header;
543

    
544
        if (rule_list_window.msg_hdr_table) {
545
                g_hash_table_destroy(rule_list_window.msg_hdr_table);
546
                rule_list_window.msg_hdr_table = NULL;
547
        }
548
        if (rule_list_window.msg_hdr_list) {
549
                procheader_header_list_destroy(rule_list_window.msg_hdr_list);
550
                rule_list_window.msg_hdr_list = NULL;
551
        }
552

    
553
        if (!msginfo)
554
                return;
555

    
556
        file = procmsg_get_message_file(msginfo);
557
        g_return_if_fail(file != NULL);
558

    
559
        rule_list_window.msg_hdr_list =
560
                procheader_get_header_list_from_file(file);
561

    
562
        g_free(file);
563

    
564
        rule_list_window.msg_hdr_table =
565
                g_hash_table_new(str_case_hash, str_case_equal);
566

    
567
        for (cur = rule_list_window.msg_hdr_list; cur != NULL;
568
             cur = next) {
569
                next = cur->next;
570
                header = (Header *)cur->data;
571
                if (!g_strcasecmp(header->name, "Received") ||
572
                    !g_strcasecmp(header->name, "Mime-Version") ||
573
                    !g_strcasecmp(header->name, "X-UIDL")) {
574
                        procheader_header_free(header);
575
                        rule_list_window.msg_hdr_list =
576
                                g_slist_remove(rule_list_window.msg_hdr_list,
577
                                               header);
578
                        continue;
579
                }
580
                if (!g_hash_table_lookup(rule_list_window.msg_hdr_table,
581
                                         header->name)) {
582
                        g_hash_table_insert(rule_list_window.msg_hdr_table,
583
                                            header->name, header->body);
584
                }
585
        }
586
}
587

    
588
static void prefs_filter_set_header_list(MsgInfo *msginfo)
589
{
590
        GSList *list = NULL;
591
        gchar *path;
592
        FILE *fp;
593

    
594
        list = procheader_add_header_list(list, "From", NULL);
595
        list = procheader_add_header_list(list, "To", NULL);
596
        list = procheader_add_header_list(list, "Cc", NULL);
597
        list = procheader_add_header_list(list, "Subject", NULL);
598
        list = procheader_add_header_list(list, "Reply-To", NULL);
599
        list = procheader_add_header_list(list, "List-Id", NULL);
600
        list = procheader_add_header_list(list, "X-ML-Name", NULL);
601

    
602
        procheader_header_list_destroy(rule_list_window.default_hdr_list);
603
        rule_list_window.default_hdr_list = list;
604

    
605
        list = NULL;
606
        path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_HEADER_RC,
607
                           NULL);
608
        if ((fp = fopen(path, "rb")) != NULL) {
609
                gchar buf[PREFSBUFSIZE];
610

    
611
                while (fgets(buf, sizeof(buf), fp) != NULL) {
612
                        g_strstrip(buf);
613
                        if (buf[0] == '\0') continue;
614
                        list = procheader_add_header_list(list, buf, NULL);
615
                }
616

    
617
                fclose(fp);
618
        } else
619
                if (ENOENT != errno) FILE_OP_ERROR(path, "fopen");
620
        g_free(path);
621

    
622
        prefs_filter_set_user_header_list(list);
623

    
624
        prefs_filter_set_msg_header_list(msginfo);
625
}
626

    
627
static void prefs_filter_write_user_header_list(void)
628
{
629
        gchar *path;
630
        PrefFile *pfile;
631
        GSList *cur;
632

    
633
        path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_HEADER_RC,
634
                           NULL);
635

    
636
        if ((pfile = prefs_file_open(path)) == NULL) {
637
                g_warning("failed to write filter user header list\n");
638
                g_free(path);
639
                return;
640
        }
641
        g_free(path);
642

    
643
        for (cur = rule_list_window.user_hdr_list; cur != NULL;
644
             cur = cur->next) {
645
                Header *header = (Header *)cur->data;
646
                fputs(header->name, pfile->fp);
647
                fputc('\n', pfile->fp);
648
        }
649

    
650
        if (prefs_file_close(pfile) < 0)
651
                g_warning("failed to write filter user header list\n");
652
}
653

    
654
static void prefs_filter_set_list(void)
655
{
656
        gint row = 0;
657
        FilterRule *rule;
658

    
659
        g_slist_free(prefs_common.fltlist);
660
        prefs_common.fltlist = NULL;
661

    
662
        while ((rule = gtk_clist_get_row_data
663
                (GTK_CLIST(rule_list_window.clist), row)) != NULL) {
664
                prefs_common.fltlist = g_slist_append(prefs_common.fltlist,
665
                                                      rule);
666
                row++;
667
        }
668
}
669

    
670
static void prefs_filter_add_cb(void)
671
{
672
        FilterRule *rule;
673

    
674
        rule = prefs_filter_edit_open(NULL, NULL);
675

    
676
        if (rule) {
677
                prefs_filter_set_list_row(-1, rule, TRUE);
678
                prefs_filter_set_list();
679
        }
680
}
681

    
682
static void prefs_filter_edit_cb(void)
683
{
684
        GtkCList *clist = GTK_CLIST(rule_list_window.clist);
685
        FilterRule *rule, *new_rule;
686
        gint row;
687

    
688
        if (!clist->selection) return;
689

    
690
        row = GPOINTER_TO_INT(clist->selection->data);
691

    
692
        rule = gtk_clist_get_row_data(clist, row);
693
        g_return_if_fail(rule != NULL);
694

    
695
        new_rule = prefs_filter_edit_open(rule, NULL);
696

    
697
        if (new_rule) {
698
                prefs_filter_set_list_row(row, new_rule, TRUE);
699
                prefs_filter_set_list();
700
        }
701
}
702

    
703
static void prefs_filter_copy_cb(void)
704
{
705
        GtkCList *clist = GTK_CLIST(rule_list_window.clist);
706
        FilterRule *rule, *new_rule;
707
        gint row;
708

    
709
        if (!clist->selection) return;
710

    
711
        row = GPOINTER_TO_INT(clist->selection->data);
712

    
713
        rule = gtk_clist_get_row_data(clist, row);
714
        g_return_if_fail(rule != NULL);
715

    
716
        new_rule = prefs_filter_edit_open(rule, NULL);
717

    
718
        if (new_rule) {
719
                prefs_filter_set_list_row(-1, new_rule, TRUE);
720
                prefs_filter_set_list();
721
        }
722
}
723

    
724
static void prefs_filter_delete_cb(void)
725
{
726
        GtkCList *clist = GTK_CLIST(rule_list_window.clist);
727
        FilterRule *rule;
728
        gint row;
729

    
730
        if (!clist->selection) return;
731
        row = GPOINTER_TO_INT(clist->selection->data);
732

    
733
        if (alertpanel(_("Delete rule"),
734
                       _("Do you really want to delete this rule?"),
735
                       _("Yes"), _("No"), NULL) != G_ALERTDEFAULT)
736
                return;
737

    
738
        rule = gtk_clist_get_row_data(clist, row);
739
        filter_rule_free(rule);
740
        gtk_clist_remove(clist, row);
741
        prefs_common.fltlist = g_slist_remove(prefs_common.fltlist, rule);
742
        if (!clist->selection)
743
                gtk_clist_select_row(clist, row - 1, -1);
744
}
745

    
746
static void prefs_filter_top(void)
747
{
748
        GtkCList *clist = GTK_CLIST(rule_list_window.clist);
749
        gint row;
750

    
751
        if (!clist->selection) return;
752

    
753
        row = GPOINTER_TO_INT(clist->selection->data);
754
        if (row > 0)
755
                gtk_clist_row_move(clist, row, 0);
756
}
757

    
758
static void prefs_filter_up(void)
759
{
760
        GtkCList *clist = GTK_CLIST(rule_list_window.clist);
761
        gint row;
762

    
763
        if (!clist->selection) return;
764

    
765
        row = GPOINTER_TO_INT(clist->selection->data);
766
        if (row > 0)
767
                gtk_clist_row_move(clist, row, row - 1);
768
}
769

    
770
static void prefs_filter_down(void)
771
{
772
        GtkCList *clist = GTK_CLIST(rule_list_window.clist);
773
        gint row;
774

    
775
        if (!clist->selection) return;
776

    
777
        row = GPOINTER_TO_INT(clist->selection->data);
778
        if (row < clist->rows - 1)
779
                gtk_clist_row_move(clist, row, row + 1);
780
}
781

    
782
static void prefs_filter_bottom(void)
783
{
784
        GtkCList *clist = GTK_CLIST(rule_list_window.clist);
785
        gint row;
786

    
787
        if (!clist->selection) return;
788

    
789
        row = GPOINTER_TO_INT(clist->selection->data);
790
        if (row < clist->rows - 1)
791
                gtk_clist_row_move(clist, row, clist->rows - 1);
792
}
793

    
794
static void prefs_filter_select(GtkCList *clist, gint row, gint column,
795
                                GdkEvent *event)
796
{
797
        if (event && event->type == GDK_2BUTTON_PRESS) {
798
                prefs_filter_edit_cb();
799
                return;
800
        }
801

    
802
        if (column == 0) {
803
                FilterRule *rule;
804
                rule = gtk_clist_get_row_data(clist, row);
805
                rule->enabled ^= TRUE;
806
                prefs_filter_set_list_row(row, rule, FALSE);
807
        }
808
}
809

    
810
static void prefs_filter_row_move(GtkCList *clist, gint source_row,
811
                                  gint dest_row)
812
{
813
        prefs_filter_set_list();
814
        if (gtk_clist_row_is_visible(clist, dest_row) != GTK_VISIBILITY_FULL)
815
                gtk_clist_moveto(clist, dest_row, -1, 0.5, 0.0);
816
}
817

    
818
static gint prefs_filter_deleted(GtkWidget *widget, GdkEventAny *event,
819
                                 gpointer data)
820
{
821
        prefs_filter_close();
822
        return TRUE;
823
}
824

    
825
static gboolean prefs_filter_key_pressed(GtkWidget *widget, GdkEventKey *event,
826
                                         gpointer data)
827
{
828
        if (event && event->keyval == GDK_Escape)
829
                prefs_filter_close();
830
        return FALSE;
831
}
832

    
833
static void prefs_filter_close(void)
834
{
835
        prefs_filter_set_msg_header_list(NULL);
836
        prefs_filter_write_user_header_list();
837
        filter_write_config(prefs_common.fltlist);
838
        gtk_widget_hide(rule_list_window.window);
839
        gtk_clist_clear(GTK_CLIST(rule_list_window.clist));
840
        inc_unlock();
841
}