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