e370e4f800703ab98d11c878cdf5561d99de05f7
[claws.git] / src / prefs_filter.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2001 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_common.h"
39 #include "mainwindow.h"
40 #include "foldersel.h"
41 #include "manage_window.h"
42 #include "inc.h"
43 #include "filter.h"
44 #include "utils.h"
45 #include "gtkutils.h"
46 #include "alertpanel.h"
47 #include "folder.h"
48
49 static struct Filter {
50         GtkWidget *window;
51
52         GtkWidget *ok_btn;
53
54         GtkWidget *hdr_combo1;
55         GtkWidget *hdr_combo2;
56         GtkWidget *hdr_entry1;
57         GtkWidget *hdr_entry2;
58         GtkWidget *key_entry1;
59         GtkWidget *key_entry2;
60         GtkWidget *pred_combo1;
61         GtkWidget *pred_combo2;
62         GtkWidget *pred_entry1;
63         GtkWidget *pred_entry2;
64         GtkWidget *op_combo;
65         GtkWidget *op_entry;
66
67         GtkWidget *dest_entry;
68         GtkWidget *regex_chkbtn;
69
70         GtkWidget *destsel_btn;
71         GtkWidget *dest_radiobtn;
72         GtkWidget *notrecv_radiobtn;
73
74         GtkWidget *cond_clist;
75 } filter;
76
77 /*
78    parameter name, default value, pointer to the prefs variable, data type,
79    pointer to the widget pointer,
80    pointer to the function for data setting,
81    pointer to the function for widget setting
82  */
83
84 #define VSPACING                12
85 #define VSPACING_NARROW         4
86 #define DEFAULT_ENTRY_WIDTH     80
87 #define PREFSBUFSIZE            1024
88
89 /* widget creating functions */
90 static void prefs_filter_create         (void);
91
92 static void prefs_filter_set_dialog     (void);
93 static void prefs_filter_set_list       (void);
94 static gint prefs_filter_clist_set_row  (gint    row);
95
96 /* callback functions */
97 static void prefs_filter_select_dest_cb (void);
98 static void prefs_filter_register_cb    (void);
99 static void prefs_filter_substitute_cb  (void);
100 static void prefs_filter_delete_cb      (void);
101 static void prefs_filter_up             (void);
102 static void prefs_filter_down           (void);
103 static void prefs_filter_select         (GtkCList       *clist,
104                                          gint            row,
105                                          gint            column,
106                                          GdkEvent       *event);
107
108 static void prefs_filter_dest_radio_button_toggled      (void);
109 static void prefs_filter_notrecv_radio_button_toggled   (void);
110
111 static gint prefs_filter_deleted        (GtkWidget      *widget,
112                                          GdkEventAny    *event,
113                                          gpointer        data);
114 static void prefs_filter_key_pressed    (GtkWidget      *widget,
115                                          GdkEventKey    *event,
116                                          gpointer        data);
117 static void prefs_filter_cancel         (void);
118 static void prefs_filter_ok             (void);
119
120 void prefs_filter_open(void)
121 {
122         if (prefs_rc_is_readonly(FILTER_RC))
123                 return;
124
125         inc_autocheck_timer_remove();
126
127         if (!filter.window) {
128                 prefs_filter_create();
129         }
130
131         manage_window_set_transient(GTK_WINDOW(filter.window));
132         gtk_widget_grab_focus(filter.ok_btn);
133
134         prefs_filter_set_dialog();
135
136         gtk_widget_show(filter.window);
137 }
138
139 static void prefs_filter_create(void)
140 {
141         GtkWidget *window;
142         GtkWidget *vbox;
143         GtkWidget *ok_btn;
144         GtkWidget *cancel_btn;
145         GtkWidget *confirm_area;
146
147         GtkWidget *vbox1;
148         GtkWidget *table1;
149         GtkWidget *op_label;
150         GtkWidget *op_combo;
151         GtkWidget *op_entry;
152         GtkWidget *hdr_label;
153         GtkWidget *hdr_combo1;
154         GtkWidget *hdr_combo2;
155         GtkWidget *key_label;
156         GtkWidget *key_entry1;
157         GtkWidget *key_entry2;
158         GtkWidget *pred_label;
159         GtkWidget *pred_combo1;
160         GtkWidget *pred_entry1;
161         GtkWidget *pred_combo2;
162         GtkWidget *pred_entry2;
163
164         GtkWidget *vbox2;
165         GtkWidget *dest_hbox;
166         GtkWidget *dest_entry;
167         GtkWidget *destsel_btn;
168         GtkWidget *dest_radiobtn;
169         GtkWidget *notrecv_radiobtn;
170         GSList *recv_group = NULL;
171
172         GtkWidget *regex_chkbtn;
173
174         GtkWidget *reg_hbox;
175         GtkWidget *btn_hbox;
176         GtkWidget *arrow;
177         GtkWidget *reg_btn;
178         GtkWidget *subst_btn;
179         GtkWidget *del_btn;
180
181         GtkWidget *cond_hbox;
182         GtkWidget *cond_scrolledwin;
183         GtkWidget *cond_clist;
184
185         GtkWidget *btn_vbox;
186         GtkWidget *up_btn;
187         GtkWidget *down_btn;
188
189         gchar *title[] = {_("Registered rules")};
190
191         debug_print(_("Creating filter setting window...\n"));
192
193         window = gtk_window_new (GTK_WINDOW_DIALOG);
194         gtk_container_set_border_width (GTK_CONTAINER (window), 8);
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_button_set_create(&confirm_area, &ok_btn, _("OK"),
204                                 &cancel_btn, _("Cancel"), 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 (ok_btn);
208
209         /*
210         gtkut_button_set_create (&confirm_area, &close_btn, _("Close"),
211                                  NULL, NULL, NULL, NULL);
212         gtk_widget_show (confirm_area);
213         gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
214         gtk_widget_grab_default (close_btn);
215         */
216
217         gtk_window_set_title (GTK_WINDOW(window),
218                               _("Filter setting"));
219         gtk_signal_connect (GTK_OBJECT(window), "delete_event",
220                             GTK_SIGNAL_FUNC(prefs_filter_deleted), NULL);
221         gtk_signal_connect (GTK_OBJECT(window), "key_press_event",
222                             GTK_SIGNAL_FUNC(prefs_filter_key_pressed), NULL);
223         gtk_signal_connect (GTK_OBJECT(window), "focus_in_event",
224                             GTK_SIGNAL_FUNC(manage_window_focus_in), NULL);
225         gtk_signal_connect (GTK_OBJECT(window), "focus_out_event",
226                             GTK_SIGNAL_FUNC(manage_window_focus_out), NULL);
227         gtk_signal_connect (GTK_OBJECT(ok_btn), "clicked",
228                             GTK_SIGNAL_FUNC(prefs_filter_ok), NULL);
229         gtk_signal_connect (GTK_OBJECT(cancel_btn), "clicked",
230                             GTK_SIGNAL_FUNC(prefs_filter_cancel), NULL);
231
232         vbox1 = gtk_vbox_new (FALSE, VSPACING);
233         gtk_widget_show (vbox1);
234         gtk_box_pack_start (GTK_BOX (vbox), vbox1, TRUE, TRUE, 0);
235         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
236
237         table1 = gtk_table_new (3, 4, FALSE);
238         gtk_widget_show (table1);
239         gtk_box_pack_start (GTK_BOX (vbox1), table1, FALSE, FALSE, 0);
240         gtk_table_set_row_spacings (GTK_TABLE (table1), 8);
241         gtk_table_set_col_spacings (GTK_TABLE (table1), 8);
242
243         op_label = gtk_label_new (_("Operator"));
244         gtk_widget_show (op_label);
245         gtk_table_attach (GTK_TABLE (table1), op_label, 0, 1, 0, 1,
246                           GTK_FILL, 0, 0, 0);
247         gtk_misc_set_alignment (GTK_MISC (op_label), 0, 0.5);
248
249         op_combo = gtk_combo_new ();
250         gtk_widget_show (op_combo);
251         gtk_table_attach (GTK_TABLE (table1), op_combo, 0, 1, 2, 3,
252                           0, 0, 0, 0);
253         gtk_widget_set_usize (op_combo, 52, -1);
254         gtkut_combo_set_items (GTK_COMBO (op_combo), "and", "or", NULL);
255
256         op_entry = GTK_COMBO (op_combo)->entry;
257         gtk_entry_set_editable (GTK_ENTRY (op_entry), FALSE);
258
259         hdr_label = gtk_label_new (_("Header"));
260         gtk_widget_show (hdr_label);
261         gtk_table_attach (GTK_TABLE (table1), hdr_label, 1, 2, 0, 1,
262                           GTK_FILL, 0, 0, 0);
263         gtk_misc_set_alignment (GTK_MISC (hdr_label), 0, 0.5);
264
265         hdr_combo1 = gtk_combo_new ();
266         gtk_widget_show (hdr_combo1);
267         gtk_table_attach (GTK_TABLE (table1), hdr_combo1, 1, 2, 1, 2,
268                           0, 0, 0, 0);
269         gtk_widget_set_usize (hdr_combo1, 96, -1);
270         gtkut_combo_set_items (GTK_COMBO (hdr_combo1),
271                                "Subject", "From", "To", "Cc", "Reply-To",
272                                "Sender", "X-ML-Name", "X-List", "X-Sequence",
273                                "X-Mailer",
274                                NULL);
275
276         hdr_combo2 = gtk_combo_new ();
277         gtk_widget_show (hdr_combo2);
278         gtk_table_attach (GTK_TABLE (table1), hdr_combo2, 1, 2, 2, 3,
279                           0, 0, 0, 0);
280         gtk_widget_set_usize (hdr_combo2, 96, -1);
281         gtkut_combo_set_items (GTK_COMBO (hdr_combo2), _("(none)"),
282                                "Subject", "From", "To", "Cc", "Reply-To",
283                                "Sender", "X-ML-Name", "X-List", "X-Sequence",
284                                "X-Mailer",
285                                NULL);
286
287         key_label = gtk_label_new (_("Keyword"));
288         gtk_widget_show (key_label);
289         gtk_table_attach (GTK_TABLE (table1), key_label, 2, 3, 0, 1,
290                           GTK_EXPAND | GTK_SHRINK | GTK_FILL,
291                           0, 0, 0);
292         gtk_misc_set_alignment (GTK_MISC (key_label), 0, 0.5);
293
294         key_entry1 = gtk_entry_new ();
295         gtk_widget_show (key_entry1);
296         gtk_widget_set_usize (key_entry1, 128, -1);
297         gtk_table_attach (GTK_TABLE (table1), key_entry1, 2, 3, 1, 2,
298                           GTK_EXPAND | GTK_SHRINK | GTK_FILL,
299                           0, 0, 0);
300
301         key_entry2 = gtk_entry_new ();
302         gtk_widget_show (key_entry2);
303         gtk_widget_set_usize (key_entry2, 128, -1);
304         gtk_table_attach (GTK_TABLE (table1), key_entry2, 2, 3, 2, 3,
305                           GTK_EXPAND | GTK_SHRINK | GTK_FILL,
306                           0, 0, 0);
307
308         pred_label = gtk_label_new (_("Predicate"));
309         gtk_widget_show (pred_label);
310         gtk_table_attach (GTK_TABLE (table1), pred_label, 3, 4, 0, 1,
311                           GTK_FILL, 0, 0, 0);
312         gtk_misc_set_alignment (GTK_MISC (pred_label), 0, 0.5);
313
314         pred_combo1 = gtk_combo_new ();
315         gtk_widget_show (pred_combo1);
316         gtk_table_attach (GTK_TABLE (table1), pred_combo1, 3, 4, 1, 2,
317                           0, 0, 0, 0);
318         gtk_widget_set_usize (pred_combo1, 92, -1);
319         gtkut_combo_set_items (GTK_COMBO (pred_combo1),
320                                _("contains"), _("not contain"), NULL);
321
322         pred_entry1 = GTK_COMBO (pred_combo1)->entry;
323         gtk_entry_set_editable (GTK_ENTRY (pred_entry1), FALSE);
324
325         pred_combo2 = gtk_combo_new ();
326         gtk_widget_show (pred_combo2);
327         gtk_table_attach (GTK_TABLE (table1), pred_combo2, 3, 4, 2, 3,
328                           0, 0, 0, 0);
329         gtk_widget_set_usize (pred_combo2, 92, -1);
330         gtkut_combo_set_items (GTK_COMBO (pred_combo2),
331                                _("contains"), _("not contain"), NULL);
332
333         pred_entry2 = GTK_COMBO (pred_combo2)->entry;
334         gtk_entry_set_editable (GTK_ENTRY (pred_entry2), FALSE);
335
336         /* destination */
337
338         vbox2 = gtk_vbox_new (FALSE, VSPACING_NARROW);
339         gtk_widget_show (vbox2);
340         gtk_box_pack_start (GTK_BOX (vbox1), vbox2, FALSE, TRUE, 0);
341
342         dest_hbox = gtk_hbox_new (FALSE, 8);
343         gtk_widget_show (dest_hbox);
344         gtk_box_pack_start (GTK_BOX (vbox2), dest_hbox, FALSE, TRUE, 0);
345
346         dest_radiobtn =
347                 gtk_radio_button_new_with_label (recv_group, _("Destination"));
348         recv_group = gtk_radio_button_group (GTK_RADIO_BUTTON (dest_radiobtn));
349         gtk_widget_show (dest_radiobtn);
350         gtk_box_pack_start (GTK_BOX (dest_hbox), dest_radiobtn,
351                             FALSE, FALSE, 0);
352         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dest_radiobtn), TRUE);
353         gtk_signal_connect
354                 (GTK_OBJECT (dest_radiobtn), "toggled",
355                  GTK_SIGNAL_FUNC (prefs_filter_dest_radio_button_toggled),
356                  NULL);
357
358         dest_entry = gtk_entry_new ();
359         gtk_widget_show (dest_entry);
360         gtk_widget_set_usize (dest_entry, DEFAULT_ENTRY_WIDTH, -1);
361         gtk_box_pack_start (GTK_BOX (dest_hbox), dest_entry, TRUE, TRUE, 0);
362         gtk_entry_set_editable (GTK_ENTRY (dest_entry), FALSE);
363
364         destsel_btn = gtk_button_new_with_label (_(" Select... "));
365         gtk_widget_show (destsel_btn);
366         gtk_box_pack_start (GTK_BOX (dest_hbox), destsel_btn, FALSE, FALSE, 0);
367         gtk_signal_connect (GTK_OBJECT (destsel_btn), "clicked",
368                             GTK_SIGNAL_FUNC (prefs_filter_select_dest_cb),
369                             NULL);
370
371         PACK_CHECK_BUTTON (dest_hbox, regex_chkbtn, _("Use regex"));
372         gtk_widget_set_sensitive(regex_chkbtn, FALSE);
373
374         notrecv_radiobtn = gtk_radio_button_new_with_label
375                 (recv_group, _("Don't receive"));
376         recv_group = gtk_radio_button_group
377                 (GTK_RADIO_BUTTON (notrecv_radiobtn));
378         gtk_widget_show (notrecv_radiobtn);
379         gtk_box_pack_start (GTK_BOX (vbox2), notrecv_radiobtn, FALSE, FALSE, 0);
380         gtk_signal_connect
381                 (GTK_OBJECT (notrecv_radiobtn), "toggled",
382                  GTK_SIGNAL_FUNC (prefs_filter_notrecv_radio_button_toggled),
383                  NULL);
384
385         /* register / substitute / delete */
386
387         reg_hbox = gtk_hbox_new (FALSE, 4);
388         gtk_widget_show (reg_hbox);
389         gtk_box_pack_start (GTK_BOX (vbox1), reg_hbox, FALSE, FALSE, 0);
390
391         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
392         gtk_widget_show (arrow);
393         gtk_box_pack_start (GTK_BOX (reg_hbox), arrow, FALSE, FALSE, 0);
394         gtk_widget_set_usize (arrow, -1, 16);
395
396         btn_hbox = gtk_hbox_new (TRUE, 4);
397         gtk_widget_show (btn_hbox);
398         gtk_box_pack_start (GTK_BOX (reg_hbox), btn_hbox, FALSE, FALSE, 0);
399
400         reg_btn = gtk_button_new_with_label (_("Register"));
401         gtk_widget_show (reg_btn);
402         gtk_box_pack_start (GTK_BOX (btn_hbox), reg_btn, FALSE, TRUE, 0);
403         gtk_signal_connect (GTK_OBJECT (reg_btn), "clicked",
404                             GTK_SIGNAL_FUNC (prefs_filter_register_cb), NULL);
405
406         subst_btn = gtk_button_new_with_label (_(" Substitute "));
407         gtk_widget_show (subst_btn);
408         gtk_box_pack_start (GTK_BOX (btn_hbox), subst_btn, FALSE, TRUE, 0);
409         gtk_signal_connect (GTK_OBJECT (subst_btn), "clicked",
410                             GTK_SIGNAL_FUNC (prefs_filter_substitute_cb),
411                             NULL);
412
413         del_btn = gtk_button_new_with_label (_("Delete"));
414         gtk_widget_show (del_btn);
415         gtk_box_pack_start (GTK_BOX (btn_hbox), del_btn, FALSE, TRUE, 0);
416         gtk_signal_connect (GTK_OBJECT (del_btn), "clicked",
417                             GTK_SIGNAL_FUNC (prefs_filter_delete_cb), NULL);
418
419         cond_hbox = gtk_hbox_new (FALSE, 8);
420         gtk_widget_show (cond_hbox);
421         gtk_box_pack_start (GTK_BOX (vbox1), cond_hbox, TRUE, TRUE, 0);
422
423         cond_scrolledwin = gtk_scrolled_window_new (NULL, NULL);
424         gtk_widget_show (cond_scrolledwin);
425         gtk_widget_set_usize (cond_scrolledwin, -1, 150);
426         gtk_box_pack_start (GTK_BOX (cond_hbox), cond_scrolledwin,
427                             TRUE, TRUE, 0);
428         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (cond_scrolledwin),
429                                         GTK_POLICY_AUTOMATIC,
430                                         GTK_POLICY_AUTOMATIC);
431
432         cond_clist = gtk_clist_new_with_titles(1, title);
433         gtk_widget_show (cond_clist);
434         gtk_container_add (GTK_CONTAINER (cond_scrolledwin), cond_clist);
435         gtk_clist_set_column_width (GTK_CLIST (cond_clist), 0, 80);
436         gtk_clist_set_selection_mode (GTK_CLIST (cond_clist),
437                                       GTK_SELECTION_BROWSE);
438         GTK_WIDGET_UNSET_FLAGS (GTK_CLIST (cond_clist)->column[0].button,
439                                 GTK_CAN_FOCUS);
440         gtk_signal_connect (GTK_OBJECT (cond_clist), "select_row",
441                             GTK_SIGNAL_FUNC (prefs_filter_select), NULL);
442
443         btn_vbox = gtk_vbox_new (FALSE, 8);
444         gtk_widget_show (btn_vbox);
445         gtk_box_pack_start (GTK_BOX (cond_hbox), btn_vbox, FALSE, FALSE, 0);
446
447         up_btn = gtk_button_new_with_label (_("Up"));
448         gtk_widget_show (up_btn);
449         gtk_box_pack_start (GTK_BOX (btn_vbox), up_btn, FALSE, FALSE, 0);
450         gtk_signal_connect (GTK_OBJECT (up_btn), "clicked",
451                             GTK_SIGNAL_FUNC (prefs_filter_up), NULL);
452
453         down_btn = gtk_button_new_with_label (_("Down"));
454         gtk_widget_show (down_btn);
455         gtk_box_pack_start (GTK_BOX (btn_vbox), down_btn, FALSE, FALSE, 0);
456         gtk_signal_connect (GTK_OBJECT (down_btn), "clicked",
457                             GTK_SIGNAL_FUNC (prefs_filter_down), NULL);
458
459         gtk_widget_show_all(window);
460
461         filter.window    = window;
462         filter.ok_btn = ok_btn;
463
464         filter.hdr_combo1  = hdr_combo1;
465         filter.hdr_combo2  = hdr_combo2;
466         filter.hdr_entry1  = GTK_COMBO (hdr_combo1)->entry;
467         filter.hdr_entry2  = GTK_COMBO (hdr_combo2)->entry;
468         filter.key_entry1  = key_entry1;
469         filter.key_entry2  = key_entry2;
470         filter.pred_combo1 = pred_combo1;
471         filter.pred_combo2 = pred_combo2;
472         filter.pred_entry1 = pred_entry1;
473         filter.pred_entry2 = pred_entry2;
474         filter.op_combo    = op_combo;
475         filter.op_entry    = op_entry;
476
477         filter.dest_entry       = dest_entry;
478         filter.destsel_btn      = destsel_btn;
479         filter.dest_radiobtn    = dest_radiobtn;
480         filter.notrecv_radiobtn = notrecv_radiobtn;
481         filter.regex_chkbtn     = regex_chkbtn;
482
483         filter.cond_clist   = cond_clist;
484 }
485
486 void prefs_filter_read_config(void)
487 {
488         gchar *rcpath;
489         FILE *fp;
490         gchar buf[PREFSBUFSIZE];
491         Filter *flt;
492
493         debug_print(_("Reading filter configuration...\n"));
494
495         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_RC, NULL);
496         if ((fp = fopen(rcpath, "r")) == NULL) {
497                 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
498                 g_free(rcpath);
499                 return;
500         }
501         g_free(rcpath);
502
503         /* remove all previous filter list */
504         while (prefs_common.fltlist != NULL) {
505                 flt = (Filter *)prefs_common.fltlist->data;
506                 filter_free(flt);
507                 prefs_common.fltlist = g_slist_remove(prefs_common.fltlist,
508                                                       flt);
509         }
510
511         while (fgets(buf, sizeof(buf), fp) != NULL) {
512                 g_strchomp(buf);
513                 flt = filter_read_str(buf);
514                 if (flt) {
515                         prefs_common.fltlist =
516                                 g_slist_append(prefs_common.fltlist, flt);
517                 }
518         }
519
520         fclose(fp);
521 }
522
523 void prefs_filter_write_config(void)
524 {
525         gchar *rcpath;
526         PrefFile *pfile;
527         GSList *cur;
528
529         debug_print(_("Writing filter configuration...\n"));
530
531         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_RC, NULL);
532         if ((pfile = prefs_write_open(rcpath)) == NULL) {
533                 g_warning(_("failed to write configuration to file\n"));
534                 g_free(rcpath);
535                 return;
536         }
537
538         for (cur = prefs_common.fltlist; cur != NULL; cur = cur->next) {
539                 Filter *flt = (Filter *)cur->data;
540                 gchar *fstr;
541
542                 fstr = filter_get_str(flt);
543                 if (fputs(fstr, pfile->fp) == EOF ||
544                     fputc('\n', pfile->fp) == EOF) {
545                         FILE_OP_ERROR(rcpath, "fputs || fputc");
546                         prefs_write_close_revert(pfile);
547                         g_free(rcpath);
548                         g_free(fstr);
549                         return;
550                 }
551                 g_free(fstr);
552         }
553
554         g_free(rcpath);
555
556         if (prefs_write_close(pfile) < 0) {
557                 g_warning(_("failed to write configuration to file\n"));
558                 return;
559         }
560 }
561
562 static void prefs_filter_set_dialog(void)
563 {
564         GtkCList *clist = GTK_CLIST(filter.cond_clist);
565         GSList *cur;
566         gchar *cond_str[1];
567         gint row;
568
569         gtk_clist_freeze(clist);
570         gtk_clist_clear(clist);
571
572         cond_str[0] = _("(New)");
573         row = gtk_clist_append(clist, cond_str);
574         gtk_clist_set_row_data(clist, row, NULL);
575
576         for (cur = prefs_common.fltlist; cur != NULL; cur = cur->next) {
577                 Filter *flt = (Filter *)cur->data;
578
579                 cond_str[0] = filter_get_str(flt);
580                 subst_char(cond_str[0], '\t', ':');
581                 row = gtk_clist_append(clist, cond_str);
582                 gtk_clist_set_row_data(clist, row, flt);
583
584                 g_free(cond_str[0]);
585         }
586
587         gtk_clist_thaw(clist);
588 }
589
590 static void prefs_filter_set_list(void)
591 {
592         gint row = 1;
593         Filter *flt;
594
595         g_slist_free(prefs_common.fltlist);
596         prefs_common.fltlist = NULL;
597
598         while ((flt = gtk_clist_get_row_data(GTK_CLIST(filter.cond_clist),
599                 row)) != NULL) {
600                 prefs_common.fltlist = g_slist_append(prefs_common.fltlist,
601                                                       flt);
602                 row++;
603         }
604 }
605
606 #define GET_ENTRY(entry) \
607         entry_text = gtk_entry_get_text(GTK_ENTRY(entry))
608
609 static gint prefs_filter_clist_set_row(gint row)
610 {
611         GtkCList *clist = GTK_CLIST(filter.cond_clist);
612         Filter *flt;
613         gchar *entry_text;
614         gchar *cond_str[1];
615
616         g_return_val_if_fail(row != 0, -1);
617
618         if (GTK_WIDGET_IS_SENSITIVE(filter.dest_entry))
619                 GET_ENTRY(filter.dest_entry);
620         else
621                 entry_text = FILTER_NOT_RECEIVE;
622         if (entry_text[0] == '\0') {
623                 alertpanel_error(_("Destination is not set."));
624                 return -1;
625         }
626         GET_ENTRY(filter.hdr_entry1);
627         if (entry_text[0] == '\0') {
628                 alertpanel_error(_("Header name is not set."));
629                 return -1;
630         }
631
632         flt = g_new0(Filter, 1);
633
634         flt->name1 = g_strdup(entry_text);
635
636         GET_ENTRY(filter.key_entry1);
637         if (entry_text[0] != '\0')
638                 flt->body1 = g_strdup(entry_text);
639
640         GET_ENTRY(filter.hdr_entry2);
641         if (entry_text[0] != '\0' && strcmp(entry_text, _("(none)")) != 0) {
642                 flt->name2 = g_strdup(entry_text);
643
644                 GET_ENTRY(filter.key_entry2);
645                 if (entry_text[0] != '\0')
646                         flt->body2 = g_strdup(entry_text);
647         }
648
649         GET_ENTRY(filter.pred_entry1);
650         if (!strcmp(entry_text, _("contains")))
651                 flt->flag1 = FLT_CONTAIN;
652         GET_ENTRY(filter.pred_entry2);
653         if (!strcmp(entry_text, _("contains")))
654                 flt->flag2 = FLT_CONTAIN;
655
656         GET_ENTRY(filter.op_entry);
657         if (!strcmp(entry_text, "and"))
658                 flt->cond = FLT_AND;
659         else
660                 flt->cond = FLT_OR;
661
662         if (GTK_WIDGET_IS_SENSITIVE(filter.dest_entry)) {
663                 entry_text = gtk_entry_get_text(GTK_ENTRY(filter.dest_entry));
664                 flt->dest = g_strdup(entry_text);
665                 flt->action = FLT_MOVE;
666         } else
667                 flt->action = FLT_NOTRECV;
668
669         cond_str[0] = filter_get_str(flt);
670         subst_char(cond_str[0], '\t', ':');
671
672         if (row < 0)
673                 row = gtk_clist_append(clist, cond_str);
674         else {
675                 Filter *tmpflt;
676
677                 gtk_clist_set_text(clist, row, 0, cond_str[0]);
678                 tmpflt = gtk_clist_get_row_data(clist, row);
679                 if (tmpflt)
680                         filter_free(tmpflt);
681         }
682
683         gtk_clist_set_row_data(clist, row, flt);
684
685         g_free(cond_str[0]);
686
687         prefs_filter_set_list();
688
689         return row;
690 }
691
692 static void prefs_filter_select_dest_cb(void)
693 {
694         FolderItem *dest;
695
696         dest = foldersel_folder_sel(NULL, NULL);
697         if (!dest) return;
698
699         gtk_entry_set_text(GTK_ENTRY(filter.dest_entry), dest->path);
700 }
701
702 static void prefs_filter_register_cb(void)
703 {
704         prefs_filter_clist_set_row(-1);
705 }
706
707 static void prefs_filter_substitute_cb(void)
708 {
709         GtkCList *clist = GTK_CLIST(filter.cond_clist);
710         Filter *flt;
711         gint row;
712
713         if (!clist->selection) return;
714
715         row = GPOINTER_TO_INT(clist->selection->data);
716         if (row == 0) return;
717
718         flt = gtk_clist_get_row_data(clist, row);
719         if (!flt) return;
720
721         prefs_filter_clist_set_row(row);
722 }
723
724 static void prefs_filter_delete_cb(void)
725 {
726         GtkCList *clist = GTK_CLIST(filter.cond_clist);
727         Filter *flt;
728         gint row;
729
730         if (!clist->selection) return;
731         row = GPOINTER_TO_INT(clist->selection->data);
732         if (row == 0) return;
733
734         if (alertpanel(_("Delete rule"),
735                        _("Do you really want to delete this rule?"),
736                        _("Yes"), _("No"), NULL) == G_ALERTALTERNATE)
737                 return;
738
739         flt = gtk_clist_get_row_data(clist, row);
740         filter_free(flt);
741         gtk_clist_remove(clist, row);
742         prefs_common.fltlist = g_slist_remove(prefs_common.fltlist, flt);
743 }
744
745 static void prefs_filter_up(void)
746 {
747         GtkCList *clist = GTK_CLIST(filter.cond_clist);
748         gint row;
749
750         if (!clist->selection) return;
751
752         row = GPOINTER_TO_INT(clist->selection->data);
753         if (row > 1) {
754                 gtk_clist_row_move(clist, row, row - 1);
755                 prefs_filter_set_list();
756         }
757 }
758
759 static void prefs_filter_down(void)
760 {
761         GtkCList *clist = GTK_CLIST(filter.cond_clist);
762         gint row;
763
764         if (!clist->selection) return;
765
766         row = GPOINTER_TO_INT(clist->selection->data);
767         if (row > 0 && row < clist->rows - 1) {
768                 gtk_clist_row_move(clist, row, row + 1);
769                 prefs_filter_set_list();
770         }
771 }
772
773 #define ENTRY_SET_TEXT(entry, str) \
774         gtk_entry_set_text(GTK_ENTRY(entry), str ? str : "")
775
776 static void prefs_filter_select(GtkCList *clist, gint row, gint column,
777                                 GdkEvent *event)
778 {
779         Filter *flt;
780         Filter default_flt = {"Subject", NULL, _("(none)"), NULL,
781                               FLT_CONTAIN, FLT_CONTAIN, FLT_AND,
782                               NULL, FLT_MOVE};
783
784         flt = gtk_clist_get_row_data(clist, row);
785         if (!flt)
786                 flt = &default_flt;
787
788         ENTRY_SET_TEXT(filter.dest_entry, flt->dest);
789         ENTRY_SET_TEXT(filter.hdr_entry1, flt->name1);
790         ENTRY_SET_TEXT(filter.key_entry1, flt->body1);
791         ENTRY_SET_TEXT(filter.hdr_entry2,
792                        flt->name2 ? flt->name2 : _("(none)"));
793         ENTRY_SET_TEXT(filter.key_entry2, flt->body2);
794
795         ENTRY_SET_TEXT(filter.pred_entry1,
796                        FLT_IS_CONTAIN(flt->flag1)
797                        ? _("contains") : _("not contain"));
798         ENTRY_SET_TEXT(filter.pred_entry2,
799                        FLT_IS_CONTAIN(flt->flag2)
800                        ? _("contains") : _("not contain"));
801
802         gtk_entry_set_text(GTK_ENTRY(filter.op_entry),
803                            flt->cond == FLT_OR ? "or" : "and");
804         if (flt->action == FLT_NOTRECV)
805                 gtk_toggle_button_set_active
806                         (GTK_TOGGLE_BUTTON(filter.notrecv_radiobtn), TRUE);
807         else
808                 gtk_toggle_button_set_active
809                         (GTK_TOGGLE_BUTTON(filter.dest_radiobtn), TRUE);
810 }
811
812 static void prefs_filter_dest_radio_button_toggled(void)
813 {
814         gtk_widget_set_sensitive(filter.dest_entry, TRUE);
815         gtk_widget_set_sensitive(filter.destsel_btn, TRUE);
816 }
817
818 static void prefs_filter_notrecv_radio_button_toggled(void)
819 {
820         gtk_widget_set_sensitive(filter.dest_entry, FALSE);
821         gtk_widget_set_sensitive(filter.destsel_btn, FALSE);
822 }
823
824 static gint prefs_filter_deleted(GtkWidget *widget, GdkEventAny *event,
825                                  gpointer data)
826 {
827         prefs_filter_cancel();
828         return TRUE;
829 }
830
831 static void prefs_filter_key_pressed(GtkWidget *widget, GdkEventKey *event,
832                                      gpointer data)
833 {
834         if (event && event->keyval == GDK_Escape)
835                 prefs_filter_cancel();
836 }
837
838 static void prefs_filter_ok(void)
839 {
840         prefs_filter_write_config();
841         gtk_widget_hide(filter.window);
842         inc_autocheck_timer_set();      
843 }
844
845 static void prefs_filter_cancel(void)
846 {
847         prefs_filter_read_config();
848         gtk_widget_hide(filter.window);
849         inc_autocheck_timer_set();      
850 }