62e94149c3ff0db1c91f47a349c7041c23226688
[claws.git] / src / prefs_matcher.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_matcher.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 "matcher.h"
44 #include "utils.h"
45 #include "gtkutils.h"
46 #include "alertpanel.h"
47 #include "folder.h"
48
49 static struct Matcher {
50         GtkWidget *window;
51
52         GtkWidget *ok_btn;
53
54         GtkWidget *predicate_combo;
55         GtkWidget *predicate_flag_combo;
56         GtkWidget *header_combo;
57
58         GtkWidget *criteria_list;
59
60         GtkWidget *predicate_list;
61         GtkWidget *predicate_label;
62         GtkWidget *predicate_flag_list;
63
64         GtkWidget *bool_op_list;
65
66         GtkWidget *header_entry;
67         GtkWidget *header_label;
68         GtkWidget *value_entry;
69         GtkWidget *value_label;
70         GtkWidget *case_chkbtn;
71         GtkWidget *regexp_chkbtn;
72
73         GtkWidget *cond_clist;
74 } matcher;
75
76 /* choice in the list */
77
78 enum {
79         CRITERIA_ALL = 0,
80
81         CRITERIA_SUBJECT = 1,
82         CRITERIA_FROM = 2,
83         CRITERIA_TO = 3,
84         CRITERIA_CC = 4,
85         CRITERIA_TO_OR_CC = 5,
86         CRITERIA_NEWSGROUPS = 6,
87         CRITERIA_AGE_GREATER = 7,
88         CRITERIA_AGE_LOWER = 8,
89         CRITERIA_HEADER = 9,
90         CRITERIA_HEADERS_PART = 10,
91         CRITERIA_BODY_PART = 11,
92         CRITERIA_MESSAGE = 12,
93
94         CRITERIA_UNREAD = 13,
95         CRITERIA_NEW = 14,
96         CRITERIA_MARKED = 15,
97         CRITERIA_DELETED = 16,
98         CRITERIA_REPLIED = 17,
99         CRITERIA_FORWARDED = 18
100 };
101
102 enum {
103         BOOL_OP_OR = 0,
104         BOOL_OP_AND = 1
105 };
106
107 gchar * bool_op_text [] = {
108         "or", "and"
109 };
110
111 enum {
112         PREDICATE_CONTAINS = 0,
113         PREDICATE_DOES_NOT_CONTAIN = 1
114 };
115
116 gchar * predicate_text [] = {
117         "contains", "does not contain"
118 };
119
120 enum {
121         PREDICATE_FLAG_ENABLED = 0,
122         PREDICATE_FLAG_DISABLED = 1
123 };
124
125 gchar * predicate_flag_text [] = {
126         "flag enabled", "flag disabled"
127 };
128
129 gchar * criteria_text [] = {
130         "All messages", "Subject",
131         "From", "To", "Cc", "To or Cc",
132         "Newsgroups",
133         "Age greater than", "Age lower than",
134         "Header", "Headers part",
135         "Body part", "Whole message",
136         "Unread flag", "New flag",
137         "Marked flag", "Deleted flag",
138         "Replied flag", "Forwarded flag"
139 };
140
141 gint get_sel_from_list(GtkList * list)
142 {
143         gint row = 0;
144         void * sel;
145         GList * child;
146
147         sel = list->selection->data;
148         for(child = list->children ; child != NULL ;
149             child = g_list_next(child)) {
150                 if (child->data == sel)
151                         return row;
152                 row ++;
153         }
154         
155         return row;
156 }
157
158 static PrefsMatcherSignal * matchers_callback;
159
160 #define VSPACING                12
161 #define VSPACING_NARROW         4
162 #define DEFAULT_ENTRY_WIDTH     80
163 #define PREFSBUFSIZE            1024
164
165 /* widget creating functions */
166 static void prefs_matcher_create        (void);
167
168 static void prefs_matcher_set_dialog    (MatcherList * matchers);
169
170 /*
171 static void prefs_matcher_set_list      (void);
172 static gint prefs_matcher_clist_set_row (gint    row);
173 */
174
175 /* callback functions */
176
177 /*
178 static void prefs_matcher_select_dest_cb        (void);
179 */
180 static void prefs_matcher_register_cb   (void);
181 static void prefs_matcher_substitute_cb (void);
182 static void prefs_matcher_delete_cb     (void);
183 static void prefs_matcher_up            (void);
184 static void prefs_matcher_down          (void);
185 static void prefs_matcher_select        (GtkCList       *clist,
186                                          gint            row,
187                                          gint            column,
188                                          GdkEvent       *event);
189
190 static void prefs_matcher_key_pressed   (GtkWidget      *widget,
191                                          GdkEventKey    *event,
192                                          gpointer        data);
193 static void prefs_matcher_ok            (void);
194 static void prefs_matcher_cancel                (void);
195 static gint prefs_matcher_deleted(GtkWidget *widget, GdkEventAny *event,
196                                   gpointer data);
197 static void prefs_matcher_criteria_select(GtkList *list,
198                                           GtkWidget *widget,
199                                           gpointer user_data);
200 static MatcherList * prefs_matcher_get_list(void);
201
202 void prefs_matcher_open(MatcherList * matchers, PrefsMatcherSignal * cb)
203 {
204         inc_autocheck_timer_remove();
205
206         if (!matcher.window) {
207                 prefs_matcher_create();
208         }
209
210         manage_window_set_transient(GTK_WINDOW(matcher.window));
211         gtk_widget_grab_focus(matcher.ok_btn);
212
213         matchers_callback = cb;
214
215         prefs_matcher_set_dialog(matchers);
216
217         gtk_widget_show(matcher.window);
218 }
219
220 static void prefs_matcher_create(void)
221 {
222         GtkWidget *window;
223         GtkWidget *vbox;
224         GtkWidget *ok_btn;
225         GtkWidget *cancel_btn;
226         GtkWidget *confirm_area;
227
228         GtkWidget *vbox1;
229         GtkWidget *vbox2;
230         GtkWidget *vbox3;
231         GtkWidget *table1;
232
233         GtkWidget *hbox1;
234
235         GtkWidget *header_combo;
236         GtkWidget *header_entry;
237         GtkWidget *header_label;
238         GtkWidget *criteria_combo;
239         GtkWidget *criteria_list;
240         GtkWidget *criteria_label;
241         GtkWidget *value_label;
242         GtkWidget *value_entry;
243         GtkWidget *predicate_combo;
244         GtkWidget *predicate_list;
245         GtkWidget *predicate_flag_combo;
246         GtkWidget *predicate_flag_list;
247         GtkWidget *predicate_label;
248         GtkWidget *bool_op_combo;
249         GtkWidget *bool_op_list;
250         GtkWidget *bool_op_label;
251
252         GtkWidget *regexp_chkbtn;
253         GtkWidget *case_chkbtn;
254
255         GtkWidget *reg_hbox;
256         GtkWidget *btn_hbox;
257         GtkWidget *arrow;
258         GtkWidget *reg_btn;
259         GtkWidget *subst_btn;
260         GtkWidget *del_btn;
261
262         GtkWidget *cond_hbox;
263         GtkWidget *cond_scrolledwin;
264         GtkWidget *cond_clist;
265
266         GtkWidget *btn_vbox;
267         GtkWidget *up_btn;
268         GtkWidget *down_btn;
269
270         GList *combo_items;
271         gint i;
272
273         gchar *title[] = {_("Registered rules")};
274
275         debug_print(_("Creating matcher setting window...\n"));
276
277         window = gtk_window_new (GTK_WINDOW_DIALOG);
278         gtk_container_set_border_width (GTK_CONTAINER (window), 8);
279         gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
280         gtk_window_set_modal (GTK_WINDOW (window), TRUE);
281         gtk_window_set_policy (GTK_WINDOW (window), FALSE, TRUE, FALSE);
282
283         vbox = gtk_vbox_new (FALSE, 6);
284         gtk_widget_show (vbox);
285         gtk_container_add (GTK_CONTAINER (window), vbox);
286
287         gtkut_button_set_create(&confirm_area, &ok_btn, _("OK"),
288                                 &cancel_btn, _("Cancel"), NULL, NULL);
289         gtk_widget_show (confirm_area);
290         gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
291         gtk_widget_grab_default (ok_btn);
292
293         gtk_window_set_title (GTK_WINDOW(window),
294                               _("Condition setting"));
295         gtk_signal_connect (GTK_OBJECT(window), "delete_event",
296                             GTK_SIGNAL_FUNC(prefs_matcher_deleted), NULL);
297         gtk_signal_connect (GTK_OBJECT(window), "key_press_event",
298                             GTK_SIGNAL_FUNC(prefs_matcher_key_pressed), NULL);
299         gtk_signal_connect (GTK_OBJECT(window), "focus_in_event",
300                             GTK_SIGNAL_FUNC(manage_window_focus_in), NULL);
301         gtk_signal_connect (GTK_OBJECT(window), "focus_out_event",
302                             GTK_SIGNAL_FUNC(manage_window_focus_out), NULL);
303         gtk_signal_connect (GTK_OBJECT(ok_btn), "clicked",
304                             GTK_SIGNAL_FUNC(prefs_matcher_ok), NULL);
305         gtk_signal_connect (GTK_OBJECT(cancel_btn), "clicked",
306                             GTK_SIGNAL_FUNC(prefs_matcher_cancel), NULL);
307
308         vbox1 = gtk_vbox_new (FALSE, VSPACING);
309         gtk_widget_show (vbox1);
310         gtk_box_pack_start (GTK_BOX (vbox), vbox1, TRUE, TRUE, 0);
311         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
312
313         table1 = gtk_table_new (2, 3, FALSE);
314         gtk_widget_show (table1);
315
316         gtk_box_pack_start (GTK_BOX (vbox1), table1, FALSE, FALSE, 0);
317         gtk_table_set_row_spacings (GTK_TABLE (table1), 8);
318         gtk_table_set_col_spacings (GTK_TABLE (table1), 8);
319
320         /* criteria combo box */
321
322         criteria_label = gtk_label_new (_("Match type"));
323         gtk_widget_show (criteria_label);
324         gtk_misc_set_alignment (GTK_MISC (criteria_label), 0, 0.5);
325         gtk_table_attach (GTK_TABLE (table1), criteria_label, 0, 1, 0, 1,
326                           GTK_FILL, 0, 0, 0);
327
328         criteria_combo = gtk_combo_new ();
329         gtk_widget_show (criteria_combo);
330
331         combo_items = NULL;
332
333         for(i = 0 ; i < (gint) (sizeof(criteria_text) / sizeof(gchar *)) ;
334             i++) {
335                 combo_items = g_list_append(combo_items,
336                                             (gpointer) _(criteria_text[i]));
337         }
338         gtk_combo_set_popdown_strings(GTK_COMBO(criteria_combo), combo_items);
339
340         g_list_free(combo_items);
341
342         gtk_widget_set_usize (criteria_combo, 120, -1);
343         gtk_table_attach (GTK_TABLE (table1), criteria_combo, 0, 1, 1, 2,
344                           0, 0, 0, 0);
345         criteria_list = GTK_COMBO(criteria_combo)->list;
346         gtk_signal_connect (GTK_OBJECT (criteria_list), "select-child",
347                             GTK_SIGNAL_FUNC (prefs_matcher_criteria_select),
348                             NULL);
349
350         gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(criteria_combo)->entry),
351                                FALSE);
352
353         /* header name */
354
355         header_label = gtk_label_new (_("Header name"));
356         gtk_widget_show (header_label);
357         gtk_misc_set_alignment (GTK_MISC (header_label), 0, 0.5);
358         gtk_table_attach (GTK_TABLE (table1), header_label, 1, 2, 0, 1,
359                           GTK_FILL, 0, 0, 0);
360
361         header_combo = gtk_combo_new ();
362         gtk_widget_show (header_combo);
363         gtk_widget_set_usize (header_combo, 96, -1);
364         gtkut_combo_set_items (GTK_COMBO (header_combo),
365                                "Subject", "From", "To", "Cc", "Reply-To",
366                                "Sender", "X-ML-Name", "X-List", "X-Sequence",
367                                "X-Mailer",
368                                NULL);
369         gtk_table_attach (GTK_TABLE (table1), header_combo, 1, 2, 1, 2,
370                           0, 0, 0, 0);
371         header_entry = GTK_COMBO (header_combo)->entry;
372         gtk_entry_set_editable (GTK_ENTRY (header_entry), TRUE);
373
374         /* value */
375
376         value_label = gtk_label_new (_("Value"));
377         gtk_widget_show (value_label);
378         gtk_misc_set_alignment (GTK_MISC (value_label), 0, 0.5);
379         gtk_table_attach (GTK_TABLE (table1), value_label, 2, 3, 0, 1,
380                           GTK_FILL | GTK_SHRINK | GTK_EXPAND, 0, 0, 0);
381
382         value_entry = gtk_entry_new ();
383         gtk_widget_show (value_entry);
384         gtk_widget_set_usize (value_entry, 200, -1);
385         gtk_table_attach (GTK_TABLE (table1), value_entry, 2, 3, 1, 2,
386                           GTK_FILL | GTK_SHRINK | GTK_EXPAND, 0, 0, 0);
387
388
389         /* predicate */
390
391         vbox2 = gtk_vbox_new (FALSE, VSPACING);
392         gtk_widget_show (vbox2);
393         gtk_box_pack_start (GTK_BOX (vbox1), vbox2, FALSE, FALSE, 0);
394
395         hbox1 = gtk_hbox_new (FALSE, 8);
396         gtk_widget_show (hbox1);
397         gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, FALSE, 0);
398
399         predicate_label = gtk_label_new (_("Predicate"));
400         gtk_widget_show (predicate_label);
401         gtk_box_pack_start (GTK_BOX (hbox1), predicate_label,
402                             FALSE, FALSE, 0);
403
404         predicate_combo = gtk_combo_new ();
405         gtk_widget_show (predicate_combo);
406         gtk_widget_set_usize (predicate_combo, 120, -1);
407         predicate_list = GTK_COMBO(predicate_combo)->list;
408         gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(predicate_combo)->entry),
409                                FALSE);
410
411         combo_items = NULL;
412
413         for(i = 0 ; i < (gint) (sizeof(predicate_text) / sizeof(gchar *)) ;
414             i++) {
415                 combo_items = g_list_append(combo_items,
416                                             (gpointer) _(predicate_text[i]));
417         }
418         gtk_combo_set_popdown_strings(GTK_COMBO(predicate_combo), combo_items);
419
420         g_list_free(combo_items);
421
422         gtk_box_pack_start (GTK_BOX (hbox1), predicate_combo,
423                             FALSE, FALSE, 0);
424
425         /* predicate flag */
426
427         predicate_flag_combo = gtk_combo_new ();
428         gtk_widget_hide (predicate_flag_combo);
429         gtk_widget_set_usize (predicate_flag_combo, 120, -1);
430         predicate_flag_list = GTK_COMBO(predicate_flag_combo)->list;
431         gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(predicate_flag_combo)->entry), FALSE);
432
433         combo_items = NULL;
434
435         for(i = 0 ; i < (gint) (sizeof(predicate_text) / sizeof(gchar *)) ;
436             i++) {
437                 combo_items = g_list_append(combo_items, (gpointer) _(predicate_flag_text[i]));
438         }
439         gtk_combo_set_popdown_strings(GTK_COMBO(predicate_flag_combo),
440                                       combo_items);
441
442         g_list_free(combo_items);
443
444         gtk_box_pack_start (GTK_BOX (hbox1), predicate_flag_combo,
445                             FALSE, FALSE, 0);
446
447         vbox3 = gtk_vbox_new (FALSE, 0);
448         gtk_widget_show (vbox3);
449         gtk_box_pack_start (GTK_BOX (hbox1), vbox3, FALSE, FALSE, 0);
450
451         PACK_CHECK_BUTTON (vbox3, case_chkbtn, _("Case sensitive"));
452         PACK_CHECK_BUTTON (vbox3, regexp_chkbtn, _("Use regexp"));
453
454         /* register / substitute / delete */
455
456         reg_hbox = gtk_hbox_new (FALSE, 4);
457         gtk_widget_show (reg_hbox);
458         gtk_box_pack_start (GTK_BOX (vbox1), reg_hbox, FALSE, FALSE, 0);
459
460         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
461         gtk_widget_show (arrow);
462         gtk_box_pack_start (GTK_BOX (reg_hbox), arrow, FALSE, FALSE, 0);
463         gtk_widget_set_usize (arrow, -1, 16);
464
465         btn_hbox = gtk_hbox_new (TRUE, 4);
466         gtk_widget_show (btn_hbox);
467         gtk_box_pack_start (GTK_BOX (reg_hbox), btn_hbox, FALSE, FALSE, 0);
468
469         reg_btn = gtk_button_new_with_label (_("Register"));
470         gtk_widget_show (reg_btn);
471         gtk_box_pack_start (GTK_BOX (btn_hbox), reg_btn, FALSE, TRUE, 0);
472         gtk_signal_connect (GTK_OBJECT (reg_btn), "clicked",
473                             GTK_SIGNAL_FUNC (prefs_matcher_register_cb), NULL);
474
475         subst_btn = gtk_button_new_with_label (_(" Substitute "));
476         gtk_widget_show (subst_btn);
477         gtk_box_pack_start (GTK_BOX (btn_hbox), subst_btn, FALSE, TRUE, 0);
478         gtk_signal_connect (GTK_OBJECT (subst_btn), "clicked",
479                             GTK_SIGNAL_FUNC (prefs_matcher_substitute_cb),
480                             NULL);
481
482         del_btn = gtk_button_new_with_label (_("Delete"));
483         gtk_widget_show (del_btn);
484         gtk_box_pack_start (GTK_BOX (btn_hbox), del_btn, FALSE, TRUE, 0);
485         gtk_signal_connect (GTK_OBJECT (del_btn), "clicked",
486                             GTK_SIGNAL_FUNC (prefs_matcher_delete_cb), NULL);
487
488         /* boolean operation */
489
490         bool_op_label = gtk_label_new (_("Boolean Op"));
491         gtk_misc_set_alignment (GTK_MISC (value_label), 0, 0.5);
492         gtk_widget_show (bool_op_label);
493         gtk_box_pack_start (GTK_BOX (btn_hbox), bool_op_label,
494                             FALSE, FALSE, 0);
495
496         bool_op_combo = gtk_combo_new ();
497         gtk_widget_show (bool_op_combo);
498         gtk_widget_set_usize (bool_op_combo, 50, -1);
499         bool_op_list = GTK_COMBO(bool_op_combo)->list;
500         gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(bool_op_combo)->entry),
501                                FALSE);
502
503         combo_items = NULL;
504
505         for(i = 0 ; i < (gint) (sizeof(bool_op_text) / sizeof(gchar *)) ;
506             i++) {
507                 combo_items = g_list_append(combo_items,
508                                             (gpointer) _(bool_op_text[i]));
509         }
510         gtk_combo_set_popdown_strings(GTK_COMBO(bool_op_combo), combo_items);
511
512         g_list_free(combo_items);
513
514         gtk_box_pack_start (GTK_BOX (btn_hbox), bool_op_combo,
515                             FALSE, FALSE, 0);
516
517         cond_hbox = gtk_hbox_new (FALSE, 8);
518         gtk_widget_show (cond_hbox);
519         gtk_box_pack_start (GTK_BOX (vbox1), cond_hbox, TRUE, TRUE, 0);
520
521         cond_scrolledwin = gtk_scrolled_window_new (NULL, NULL);
522         gtk_widget_show (cond_scrolledwin);
523         gtk_widget_set_usize (cond_scrolledwin, -1, 150);
524         gtk_box_pack_start (GTK_BOX (cond_hbox), cond_scrolledwin,
525                             TRUE, TRUE, 0);
526         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (cond_scrolledwin),
527                                         GTK_POLICY_AUTOMATIC,
528                                         GTK_POLICY_AUTOMATIC);
529
530         cond_clist = gtk_clist_new_with_titles(1, title);
531         gtk_widget_show (cond_clist);
532         gtk_container_add (GTK_CONTAINER (cond_scrolledwin), cond_clist);
533         gtk_clist_set_column_width (GTK_CLIST (cond_clist), 0, 80);
534         gtk_clist_set_selection_mode (GTK_CLIST (cond_clist),
535                                       GTK_SELECTION_BROWSE);
536         GTK_WIDGET_UNSET_FLAGS (GTK_CLIST (cond_clist)->column[0].button,
537                                 GTK_CAN_FOCUS);
538         gtk_signal_connect (GTK_OBJECT (cond_clist), "select_row",
539                             GTK_SIGNAL_FUNC (prefs_matcher_select), NULL);
540
541         btn_vbox = gtk_vbox_new (FALSE, 8);
542         gtk_widget_show (btn_vbox);
543         gtk_box_pack_start (GTK_BOX (cond_hbox), btn_vbox, FALSE, FALSE, 0);
544
545         up_btn = gtk_button_new_with_label (_("Up"));
546         gtk_widget_show (up_btn);
547         gtk_box_pack_start (GTK_BOX (btn_vbox), up_btn, FALSE, FALSE, 0);
548         gtk_signal_connect (GTK_OBJECT (up_btn), "clicked",
549                             GTK_SIGNAL_FUNC (prefs_matcher_up), NULL);
550
551         down_btn = gtk_button_new_with_label (_("Down"));
552         gtk_widget_show (down_btn);
553         gtk_box_pack_start (GTK_BOX (btn_vbox), down_btn, FALSE, FALSE, 0);
554         gtk_signal_connect (GTK_OBJECT (down_btn), "clicked",
555                             GTK_SIGNAL_FUNC (prefs_matcher_down), NULL);
556
557         gtk_widget_show_all(window);
558
559         matcher.window    = window;
560
561         matcher.ok_btn = ok_btn;
562
563         matcher.criteria_list = criteria_list;
564         matcher.header_combo = header_combo;
565         matcher.header_entry = header_entry;
566         matcher.header_label = header_label;
567         matcher.value_entry = value_entry;
568         matcher.value_label = value_label;
569         matcher.predicate_label = predicate_label;
570         matcher.predicate_list = predicate_list;
571         matcher.predicate_combo = predicate_combo;
572         matcher.predicate_flag_list = predicate_flag_list;
573         matcher.predicate_flag_combo = predicate_flag_combo;
574         matcher.case_chkbtn = case_chkbtn;
575         matcher.regexp_chkbtn = regexp_chkbtn;
576         matcher.bool_op_list = bool_op_list;
577
578         matcher.cond_clist   = cond_clist;
579 }
580
581 static gint prefs_matcher_clist_set_row(gint row, MatcherProp * prop)
582 {
583         GtkCList *clist = GTK_CLIST(matcher.cond_clist);
584         gchar * cond_str[1];
585         gchar * matcher_str;
586
587         if (prop == NULL) {
588                 cond_str[0] = _("(New)");
589                 return gtk_clist_append(clist, cond_str);
590         }
591
592         matcher_str = matcherprop_to_string(prop);
593         cond_str[0] = matcher_str;
594         if (row < 0)
595                 row = gtk_clist_append(clist, cond_str);
596         else
597                 gtk_clist_set_text(clist, row, 0, cond_str[0]);
598         g_free(matcher_str);
599
600         return row;
601 }
602
603 static void prefs_matcher_reset_condition(void)
604 {
605         gtk_list_select_item(GTK_LIST(matcher.criteria_list), 0);
606         gtk_list_select_item(GTK_LIST(matcher.predicate_list), 0);
607         gtk_entry_set_text(GTK_ENTRY(matcher.header_entry), "");
608         gtk_entry_set_text(GTK_ENTRY(matcher.value_entry), "");
609 }
610
611 static void prefs_matcher_set_dialog(MatcherList * matchers)
612 {
613         GtkCList *clist = GTK_CLIST(matcher.cond_clist);
614         GSList * cur;
615         gboolean bool_op = 0;
616
617         gtk_clist_freeze(clist);
618         gtk_clist_clear(clist);
619
620         prefs_matcher_clist_set_row(-1, NULL);
621         if (matchers != NULL) {
622                 for (cur = matchers->matchers ; cur != NULL ;
623                      cur = g_slist_next(cur)) {
624                         MatcherProp * prop;
625                         prop = (MatcherProp *) cur->data;
626                         prefs_matcher_clist_set_row(-1, prop);
627                 }
628
629                 bool_op = matchers->bool_and;
630         }
631
632         gtk_clist_thaw(clist);
633
634         gtk_list_select_item(GTK_LIST(matcher.bool_op_list), bool_op);
635
636         prefs_matcher_reset_condition();
637 }
638
639 static MatcherList * prefs_matcher_get_list(void)
640 {
641         gchar * matcher_str;
642         MatcherProp * prop;
643         gint row = 1;
644         gchar * tmp;
645         gboolean bool_and;
646         GSList * matcher_list;
647         MatcherList * matchers;
648
649         matcher_list = NULL;
650
651         while (gtk_clist_get_text(GTK_CLIST(matcher.cond_clist),
652                                   row, 0, &matcher_str)) {
653
654                 if (strcmp(matcher_str, _("(New)")) != 0) {
655                         tmp = matcher_str;
656                         prop = matcherprop_parse(&tmp);
657                         
658                         if (tmp == NULL)
659                                 break;
660                         
661                         matcher_list = g_slist_append(matcher_list, prop);
662                 }
663                 row ++;
664         }
665
666         bool_and = get_sel_from_list(GTK_LIST(matcher.bool_op_list));
667
668         matchers = matcherlist_new(matcher_list, bool_and);
669
670         return matchers;
671 }
672
673 static gint prefs_matcher_get_matching_from_criteria(gint criteria_id)
674 {
675         switch (criteria_id) {
676         case CRITERIA_ALL:
677                 return MATCHING_ALL;
678         case CRITERIA_UNREAD:
679                 return MATCHING_UNREAD;
680         case CRITERIA_NEW:
681                 return MATCHING_NEW;
682         case CRITERIA_MARKED:
683                 return MATCHING_MARKED;
684         case CRITERIA_DELETED:
685                 return MATCHING_DELETED;
686         case CRITERIA_REPLIED:
687                 return MATCHING_REPLIED;
688         case CRITERIA_FORWARDED:
689                 return MATCHING_FORWARDED;
690         case CRITERIA_SUBJECT:
691                 return MATCHING_SUBJECT;
692         case CRITERIA_FROM:
693                 return MATCHING_FROM;
694         case CRITERIA_TO:
695                 return MATCHING_TO;
696         case CRITERIA_CC:
697                 return MATCHING_CC;
698         case CRITERIA_TO_OR_CC:
699                 return MATCHING_TO_OR_CC;
700         case CRITERIA_NEWSGROUPS:
701                 return MATCHING_NEWSGROUPS;
702         case CRITERIA_AGE_GREATER:
703                 return MATCHING_AGE_GREATER;
704         case CRITERIA_AGE_LOWER:
705                 return MATCHING_AGE_LOWER;
706         case CRITERIA_HEADER:
707                 return MATCHING_HEADER;
708         case CRITERIA_HEADERS_PART:
709                 return MATCHING_HEADERS_PART;
710         case CRITERIA_BODY_PART:
711                 return MATCHING_BODY_PART;
712         case CRITERIA_MESSAGE:
713                 return MATCHING_MESSAGE;
714         default:
715                 return -1;
716         }
717 }
718
719 static gint prefs_matcher_not_criteria(gint matcher_criteria)
720 {
721         switch(matcher_criteria) {
722         case MATCHING_UNREAD:
723                 return MATCHING_NOT_UNREAD;
724         case MATCHING_NEW:
725                 return MATCHING_NOT_NEW;
726         case MATCHING_MARKED:
727                 return MATCHING_NOT_MARKED;
728         case MATCHING_DELETED:
729                 return MATCHING_NOT_DELETED;
730         case MATCHING_REPLIED:
731                 return MATCHING_NOT_REPLIED;
732         case MATCHING_FORWARDED:
733                 return MATCHING_NOT_FORWARDED;
734         case MATCHING_SUBJECT:
735                 return MATCHING_NOT_SUBJECT;
736         case MATCHING_FROM:
737                 return MATCHING_NOT_FROM;
738         case MATCHING_TO:
739                 return MATCHING_NOT_TO;
740         case MATCHING_CC:
741                 return MATCHING_NOT_CC;
742         case MATCHING_TO_OR_CC:
743                 return MATCHING_NOT_TO_AND_NOT_CC;
744         case MATCHING_NEWSGROUPS:
745                 return MATCHING_NOT_NEWSGROUPS;
746         case MATCHING_HEADER:
747                 return MATCHING_NOT_HEADER;
748         case MATCHING_HEADERS_PART:
749                 return MATCHING_NOT_HEADERS_PART;
750         case MATCHING_MESSAGE:
751                 return MATCHING_NOT_MESSAGE;
752         case MATCHING_BODY_PART:
753                 return MATCHING_NOT_BODY_PART;
754         default:
755                 return matcher_criteria;
756         }
757 }
758
759 static MatcherProp * prefs_matcher_dialog_to_matcher()
760 {
761         MatcherProp * matcherprop;
762         gint criteria;
763         gint matchtype;
764         gint value_pred;
765         gint value_pred_flag;
766         gint value_criteria;
767         gboolean use_regexp;
768         gboolean case_sensitive;
769         gchar * header;
770         gchar * expr;
771         gint age;
772         gchar * age_str;
773
774         value_criteria = get_sel_from_list(GTK_LIST(matcher.criteria_list));
775
776         criteria = prefs_matcher_get_matching_from_criteria(value_criteria);
777
778         value_pred = get_sel_from_list(GTK_LIST(matcher.predicate_list));
779         value_pred_flag = get_sel_from_list(GTK_LIST(matcher.predicate_flag_list));
780
781         use_regexp = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(matcher.regexp_chkbtn));
782         case_sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(matcher.case_chkbtn));
783
784         switch (value_criteria) {
785         case CRITERIA_UNREAD:
786         case CRITERIA_NEW:
787         case CRITERIA_MARKED:
788         case CRITERIA_DELETED:
789         case CRITERIA_REPLIED:
790         case CRITERIA_FORWARDED:
791                 if (value_pred_flag == PREDICATE_FLAG_DISABLED)
792                         criteria = prefs_matcher_not_criteria(criteria);
793                 break;
794         case CRITERIA_SUBJECT:
795         case CRITERIA_FROM:
796         case CRITERIA_TO:
797         case CRITERIA_CC:
798         case CRITERIA_TO_OR_CC:
799         case CRITERIA_NEWSGROUPS:
800         case CRITERIA_HEADERS_PART:
801         case CRITERIA_BODY_PART:
802         case CRITERIA_MESSAGE:
803         case CRITERIA_AGE_GREATER:
804         case CRITERIA_AGE_LOWER:
805         case CRITERIA_HEADER:
806                 if (value_pred == PREDICATE_DOES_NOT_CONTAIN)
807                         criteria = prefs_matcher_not_criteria(criteria);
808                 break;
809         }
810
811         if (use_regexp) {
812                 if (case_sensitive)
813                         matchtype = MATCHING_REGEXP;
814                 else
815                         matchtype = MATCHING_REGEXPCASE;
816         }
817         else {
818                 if (case_sensitive)
819                         matchtype = MATCHING_MATCH;
820                 else
821                         matchtype = MATCHING_MATCHCASE;
822         }
823
824         header = NULL;
825         expr = NULL;
826         age = 0;
827
828         switch (value_criteria) {
829         case CRITERIA_ALL:
830         case CRITERIA_UNREAD:
831         case CRITERIA_NEW:
832         case CRITERIA_MARKED:
833         case CRITERIA_DELETED:
834         case CRITERIA_REPLIED:
835         case CRITERIA_FORWARDED:
836                 break;
837
838         case CRITERIA_SUBJECT:
839         case CRITERIA_FROM:
840         case CRITERIA_TO:
841         case CRITERIA_CC:
842         case CRITERIA_TO_OR_CC:
843         case CRITERIA_NEWSGROUPS:
844         case CRITERIA_HEADERS_PART:
845         case CRITERIA_BODY_PART:
846         case CRITERIA_MESSAGE:
847                 expr = gtk_entry_get_text(GTK_ENTRY(matcher.value_entry));
848
849                 /*
850                 if (*expr == '\0') {
851                     alertpanel_error(_("Match string is not set."));
852                     return NULL;
853                 }
854                 */
855                 break;
856
857         case CRITERIA_AGE_GREATER:
858         case CRITERIA_AGE_LOWER:
859                 age_str = gtk_entry_get_text(GTK_ENTRY(matcher.value_entry));
860
861                 if (*age_str == '\0') {
862                     alertpanel_error(_("Age is not set."));
863                     return NULL;
864                 }
865
866                 age = atoi(age_str);
867
868                 break;
869
870         case CRITERIA_HEADER:
871
872                 header = gtk_entry_get_text(GTK_ENTRY(matcher.header_entry));
873                 expr = gtk_entry_get_text(GTK_ENTRY(matcher.value_entry));
874
875                 if (*header == '\0') {
876                     alertpanel_error(_("Header name is not set."));
877                     return NULL;
878                 }
879                 /*
880                 if (*expr == '\0') {
881                     alertpanel_error(_("Match string is not set."));
882                     return NULL;
883                 }
884                 */
885                 break;
886         }
887
888         matcherprop =  matcherprop_new(criteria, header, matchtype, expr, age);
889
890         return matcherprop;
891 }
892
893 static void prefs_matcher_register_cb(void)
894 {
895         MatcherProp * matcherprop;
896         
897         matcherprop = prefs_matcher_dialog_to_matcher();
898         if (matcherprop == NULL)
899                 return;
900
901         prefs_matcher_clist_set_row(-1, matcherprop);
902
903         matcherprop_free(matcherprop);
904
905         prefs_matcher_reset_condition();
906 }
907
908 static void prefs_matcher_substitute_cb(void)
909 {
910         GtkCList *clist = GTK_CLIST(matcher.cond_clist);
911         gint row;
912         MatcherProp * matcherprop;
913
914         row = GPOINTER_TO_INT(clist->selection->data);
915         if (row == 0)
916                 return;
917         
918         matcherprop = prefs_matcher_dialog_to_matcher();
919         if (matcherprop == NULL)
920                 return;
921
922         prefs_matcher_clist_set_row(row, matcherprop);
923
924         matcherprop_free(matcherprop);
925
926         prefs_matcher_reset_condition();
927 }
928
929 static void prefs_matcher_delete_cb(void)
930 {
931         GtkCList *clist = GTK_CLIST(matcher.cond_clist);
932         gint row;
933
934         if (!clist->selection) return;
935         row = GPOINTER_TO_INT(clist->selection->data);
936         if (row == 0)
937                 return;
938
939         gtk_clist_remove(clist, row);
940 }
941
942 static void prefs_matcher_up(void)
943 {
944         GtkCList *clist = GTK_CLIST(matcher.cond_clist);
945         gint row;
946
947         if (!clist->selection) return;
948
949         row = GPOINTER_TO_INT(clist->selection->data);
950         if (row > 1)
951                 gtk_clist_row_move(clist, row, row - 1);
952 }
953
954 static void prefs_matcher_down(void)
955 {
956         GtkCList *clist = GTK_CLIST(matcher.cond_clist);
957         gint row;
958
959         if (!clist->selection) return;
960
961         row = GPOINTER_TO_INT(clist->selection->data);
962         if (row >= 1 && row < clist->rows - 1)
963                 gtk_clist_row_move(clist, row, row + 1);
964 }
965
966 static void prefs_matcher_select(GtkCList *clist, gint row, gint column,
967                                  GdkEvent *event)
968 {
969         gchar * matcher_str;
970         gchar * tmp;
971         MatcherProp * prop;
972         gboolean negative_cond;
973
974         if (!gtk_clist_get_text(GTK_CLIST(matcher.cond_clist),
975                                 row, 0, &matcher_str))
976                 return;
977
978         negative_cond = FALSE;
979
980         if (row == 0) {
981                 prefs_matcher_reset_condition();
982                 return;
983         }
984
985         tmp = matcher_str;
986         prop = matcherprop_parse(&tmp);
987         if (tmp == NULL)
988                 return;
989
990         switch(prop->criteria) {
991         case MATCHING_ALL:
992                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
993                                      CRITERIA_ALL);
994                 break;
995
996         case MATCHING_NOT_UNREAD:
997                 negative_cond = TRUE;
998         case MATCHING_UNREAD:
999                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1000                                      CRITERIA_UNREAD);
1001                 break;
1002
1003         case MATCHING_NOT_NEW:
1004                 negative_cond = TRUE;
1005         case MATCHING_NEW:
1006                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1007                                      CRITERIA_NEW);
1008                 break;
1009
1010         case MATCHING_NOT_MARKED:
1011                 negative_cond = TRUE;
1012         case MATCHING_MARKED:
1013                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1014                                      CRITERIA_MARKED);
1015                 break;
1016
1017         case MATCHING_NOT_DELETED:
1018                 negative_cond = TRUE;
1019         case MATCHING_DELETED:
1020                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1021                                      CRITERIA_DELETED);
1022                 break;
1023
1024         case MATCHING_NOT_REPLIED:
1025                 negative_cond = TRUE;
1026         case MATCHING_REPLIED:
1027                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1028                                      CRITERIA_REPLIED);
1029                 break;
1030
1031         case MATCHING_NOT_FORWARDED:
1032                 negative_cond = TRUE;
1033         case MATCHING_FORWARDED:
1034                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1035                                      CRITERIA_FORWARDED);
1036                 break;
1037
1038         case MATCHING_NOT_SUBJECT:
1039                 negative_cond = TRUE;
1040         case MATCHING_SUBJECT:
1041                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1042                                      CRITERIA_SUBJECT);
1043                 break;
1044
1045         case MATCHING_NOT_FROM:
1046                 negative_cond = TRUE;
1047         case MATCHING_FROM:
1048                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1049                                      CRITERIA_FROM);
1050                 break;
1051
1052         case MATCHING_NOT_TO:
1053                 negative_cond = TRUE;
1054         case MATCHING_TO:
1055                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1056                                      CRITERIA_TO);
1057                 break;
1058
1059         case MATCHING_NOT_CC:
1060                 negative_cond = TRUE;
1061         case MATCHING_CC:
1062                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1063                                      CRITERIA_CC);
1064                 break;
1065
1066         case MATCHING_NOT_NEWSGROUPS:
1067                 negative_cond = TRUE;
1068         case MATCHING_NEWSGROUPS:
1069                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1070                                      CRITERIA_NEWSGROUPS);
1071                 break;
1072
1073         case MATCHING_NOT_TO_AND_NOT_CC:
1074                 negative_cond = TRUE;
1075         case MATCHING_TO_OR_CC:
1076                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1077                                      CRITERIA_TO_OR_CC);
1078                 break;
1079
1080         case MATCHING_NOT_BODY_PART:
1081                 negative_cond = TRUE;
1082         case MATCHING_BODY_PART:
1083                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1084                                      CRITERIA_BODY_PART);
1085                 break;
1086
1087         case MATCHING_NOT_MESSAGE:
1088                 negative_cond = TRUE;
1089         case MATCHING_MESSAGE:
1090                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1091                                      CRITERIA_MESSAGE);
1092                 break;
1093
1094         case MATCHING_NOT_HEADERS_PART:
1095                 negative_cond = TRUE;
1096         case MATCHING_HEADERS_PART:
1097                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1098                                      CRITERIA_HEADERS_PART);
1099                 break;
1100
1101         case MATCHING_NOT_HEADER:
1102                 negative_cond = TRUE;
1103         case MATCHING_HEADER:
1104                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1105                                      CRITERIA_HEADER);
1106                 break;
1107
1108         case MATCHING_AGE_GREATER:
1109                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1110                                      CRITERIA_AGE_GREATER);
1111                 break;
1112
1113         case MATCHING_AGE_LOWER:
1114                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1115                                      CRITERIA_AGE_LOWER);
1116                 break;
1117         }
1118         
1119         switch(prop->criteria) {
1120         case MATCHING_ALL:
1121                 break;
1122
1123         case MATCHING_NOT_SUBJECT:
1124         case MATCHING_NOT_FROM:
1125         case MATCHING_NOT_TO:
1126         case MATCHING_NOT_CC:
1127         case MATCHING_NOT_TO_AND_NOT_CC:
1128         case MATCHING_NOT_NEWSGROUPS:
1129         case MATCHING_NOT_HEADERS_PART:
1130         case MATCHING_NOT_BODY_PART:
1131         case MATCHING_NOT_MESSAGE:
1132         case MATCHING_SUBJECT:
1133         case MATCHING_FROM:
1134         case MATCHING_TO:
1135         case MATCHING_CC:
1136         case MATCHING_TO_OR_CC:
1137         case MATCHING_NEWSGROUPS:
1138         case MATCHING_HEADERS_PART:
1139         case MATCHING_BODY_PART:
1140         case MATCHING_MESSAGE:
1141                 gtk_entry_set_text(GTK_ENTRY(matcher.value_entry), prop->expr);
1142                 break;
1143
1144         case MATCHING_AGE_GREATER:
1145         case MATCHING_AGE_LOWER:
1146                 gtk_entry_set_text(GTK_ENTRY(matcher.value_entry), itos(prop->age));
1147                 break;
1148
1149         case MATCHING_NOT_HEADER:
1150         case MATCHING_HEADER:
1151                 gtk_entry_set_text(GTK_ENTRY(matcher.header_entry), prop->header);
1152                 gtk_entry_set_text(GTK_ENTRY(matcher.value_entry), prop->expr);
1153                 break;
1154         }
1155
1156         if (negative_cond)
1157                 gtk_list_select_item(GTK_LIST(matcher.predicate_list), 1);
1158         else
1159                 gtk_list_select_item(GTK_LIST(matcher.predicate_list), 0);
1160
1161         switch(prop->matchtype) {
1162         case MATCHING_MATCH:
1163                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.regexp_chkbtn), FALSE);
1164                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.case_chkbtn), TRUE);
1165                 break;
1166
1167         case MATCHING_MATCHCASE:
1168                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.regexp_chkbtn), FALSE);
1169                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.case_chkbtn), FALSE);
1170                 break;
1171
1172         case MATCHING_REGEXP:
1173                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.regexp_chkbtn), TRUE);
1174                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.case_chkbtn), TRUE);
1175                 break;
1176
1177         case MATCHING_REGEXPCASE:
1178                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.regexp_chkbtn), TRUE);
1179                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.case_chkbtn), FALSE);
1180                 break;
1181         }
1182 }
1183
1184 static void prefs_matcher_criteria_select(GtkList *list,
1185                                           GtkWidget *widget,
1186                                           gpointer user_data)
1187 {
1188         gint value;
1189
1190         value = get_sel_from_list(GTK_LIST(matcher.criteria_list));
1191
1192         switch (value) {
1193         case CRITERIA_ALL:
1194                 gtk_widget_set_sensitive(matcher.header_combo, FALSE);
1195                 gtk_widget_set_sensitive(matcher.header_label, FALSE);
1196                 gtk_widget_set_sensitive(matcher.value_label, FALSE);
1197                 gtk_widget_set_sensitive(matcher.value_entry, FALSE);
1198                 gtk_widget_set_sensitive(matcher.predicate_label, FALSE);
1199                 gtk_widget_set_sensitive(matcher.predicate_combo, FALSE);
1200                 gtk_widget_set_sensitive(matcher.predicate_flag_combo, FALSE);
1201                 gtk_widget_hide(matcher.predicate_combo);
1202                 gtk_widget_show(matcher.predicate_flag_combo);
1203                 gtk_widget_set_sensitive(matcher.case_chkbtn, FALSE);
1204                 gtk_widget_set_sensitive(matcher.regexp_chkbtn, FALSE);
1205                 break;
1206
1207         case CRITERIA_UNREAD:
1208         case CRITERIA_NEW:
1209         case CRITERIA_MARKED:
1210         case CRITERIA_DELETED:
1211         case CRITERIA_REPLIED:
1212         case CRITERIA_FORWARDED:
1213                 gtk_widget_set_sensitive(matcher.header_combo, FALSE);
1214                 gtk_widget_set_sensitive(matcher.header_label, FALSE);
1215                 gtk_widget_set_sensitive(matcher.value_label, FALSE);
1216                 gtk_widget_set_sensitive(matcher.value_entry, FALSE);
1217                 gtk_widget_set_sensitive(matcher.predicate_label, TRUE);
1218                 gtk_widget_set_sensitive(matcher.predicate_combo, FALSE);
1219                 gtk_widget_set_sensitive(matcher.predicate_flag_combo, TRUE);
1220                 gtk_widget_hide(matcher.predicate_combo);
1221                 gtk_widget_show(matcher.predicate_flag_combo);
1222                 gtk_widget_set_sensitive(matcher.case_chkbtn, FALSE);
1223                 gtk_widget_set_sensitive(matcher.regexp_chkbtn, FALSE);
1224                 break;
1225
1226         case CRITERIA_SUBJECT:
1227         case CRITERIA_FROM:
1228         case CRITERIA_TO:
1229         case CRITERIA_CC:
1230         case CRITERIA_TO_OR_CC:
1231         case CRITERIA_NEWSGROUPS:
1232         case CRITERIA_HEADERS_PART:
1233         case CRITERIA_BODY_PART:
1234         case CRITERIA_MESSAGE:
1235                 gtk_widget_set_sensitive(matcher.header_combo, FALSE);
1236                 gtk_widget_set_sensitive(matcher.header_label, FALSE);
1237                 gtk_widget_set_sensitive(matcher.value_label, TRUE);
1238                 gtk_widget_set_sensitive(matcher.value_entry, TRUE);
1239                 gtk_widget_set_sensitive(matcher.predicate_label, TRUE);
1240                 gtk_widget_set_sensitive(matcher.predicate_combo, TRUE);
1241                 gtk_widget_set_sensitive(matcher.predicate_flag_combo, FALSE);
1242                 gtk_widget_show(matcher.predicate_combo);
1243                 gtk_widget_hide(matcher.predicate_flag_combo);
1244                 gtk_widget_set_sensitive(matcher.case_chkbtn, TRUE);
1245                 gtk_widget_set_sensitive(matcher.regexp_chkbtn, TRUE);
1246                 break;
1247
1248         case CRITERIA_AGE_GREATER:
1249         case CRITERIA_AGE_LOWER:
1250                 gtk_widget_set_sensitive(matcher.header_combo, FALSE);
1251                 gtk_widget_set_sensitive(matcher.header_label, FALSE);
1252                 gtk_widget_set_sensitive(matcher.value_label, TRUE);
1253                 gtk_widget_set_sensitive(matcher.value_entry, TRUE);
1254                 gtk_widget_set_sensitive(matcher.predicate_label, FALSE);
1255                 gtk_widget_set_sensitive(matcher.predicate_combo, FALSE);
1256                 gtk_widget_set_sensitive(matcher.predicate_flag_combo, FALSE);
1257                 gtk_widget_show(matcher.predicate_combo);
1258                 gtk_widget_hide(matcher.predicate_flag_combo);
1259                 gtk_widget_set_sensitive(matcher.case_chkbtn, FALSE);
1260                 gtk_widget_set_sensitive(matcher.regexp_chkbtn, FALSE);
1261                 break;
1262
1263         case CRITERIA_HEADER:
1264                 gtk_widget_set_sensitive(matcher.header_combo, TRUE);
1265                 gtk_widget_set_sensitive(matcher.header_label, TRUE);
1266                 gtk_widget_set_sensitive(matcher.value_label, TRUE);
1267                 gtk_widget_set_sensitive(matcher.value_entry, TRUE);
1268                 gtk_widget_set_sensitive(matcher.predicate_label, TRUE);
1269                 gtk_widget_set_sensitive(matcher.predicate_combo, TRUE);
1270                 gtk_widget_set_sensitive(matcher.predicate_flag_combo, FALSE);
1271                 gtk_widget_show(matcher.predicate_combo);
1272                 gtk_widget_hide(matcher.predicate_flag_combo);
1273                 gtk_widget_set_sensitive(matcher.case_chkbtn, TRUE);
1274                 gtk_widget_set_sensitive(matcher.regexp_chkbtn, TRUE);
1275                 break;
1276         }
1277 }
1278
1279 static void prefs_matcher_key_pressed(GtkWidget *widget, GdkEventKey *event,
1280                                      gpointer data)
1281 {
1282         if (event && event->keyval == GDK_Escape)
1283                 prefs_matcher_cancel();
1284 }
1285
1286 static void prefs_matcher_cancel(void)
1287 {
1288         gtk_widget_hide(matcher.window);
1289 }
1290
1291 static void prefs_matcher_ok(void)
1292 {
1293         MatcherList * matchers;
1294
1295         matchers = prefs_matcher_get_list();
1296         if (matchers != NULL) {
1297                 gtk_widget_hide(matcher.window);
1298                 if (matchers_callback != NULL)
1299                         matchers_callback(matchers);
1300                 matcherlist_free(matchers);
1301         }
1302         else {
1303                 gtk_widget_hide(matcher.window);
1304         }
1305 }
1306
1307 static gint prefs_matcher_deleted(GtkWidget *widget, GdkEventAny *event,
1308                                   gpointer data)
1309 {
1310         prefs_matcher_cancel();
1311         return TRUE;
1312 }