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