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