added additionnal matching criteria
[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 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_matching_from_criteria(gint criteria_id)
680 {
681         switch (criteria_id) {
682         case CRITERIA_ALL:
683                 return MATCHING_ALL;
684         case CRITERIA_UNREAD:
685                 return MATCHING_UNREAD;
686         case CRITERIA_NEW:
687                 return MATCHING_NEW;
688         case CRITERIA_MARKED:
689                 return MATCHING_MARKED;
690         case CRITERIA_DELETED:
691                 return MATCHING_DELETED;
692         case CRITERIA_REPLIED:
693                 return MATCHING_REPLIED;
694         case CRITERIA_FORWARDED:
695                 return MATCHING_FORWARDED;
696         case CRITERIA_SUBJECT:
697                 return MATCHING_SUBJECT;
698         case CRITERIA_FROM:
699                 return MATCHING_FROM;
700         case CRITERIA_TO:
701                 return MATCHING_TO;
702         case CRITERIA_CC:
703                 return MATCHING_CC;
704         case CRITERIA_TO_OR_CC:
705                 return MATCHING_TO_OR_CC;
706         case CRITERIA_NEWSGROUPS:
707                 return MATCHING_NEWSGROUPS;
708         case CRITERIA_INREPLYTO:
709                 return MATCHING_INREPLYTO;
710         case CRITERIA_REFERENCES:
711                 return MATCHING_REFERENCES;
712         case CRITERIA_AGE_GREATER:
713                 return MATCHING_AGE_GREATER;
714         case CRITERIA_AGE_LOWER:
715                 return MATCHING_AGE_LOWER;
716         case CRITERIA_SCORE_GREATER:
717                 return MATCHING_SCORE_GREATER;
718         case CRITERIA_SCORE_LOWER:
719                 return MATCHING_SCORE_LOWER;
720         case CRITERIA_HEADER:
721                 return MATCHING_HEADER;
722         case CRITERIA_HEADERS_PART:
723                 return MATCHING_HEADERS_PART;
724         case CRITERIA_BODY_PART:
725                 return MATCHING_BODY_PART;
726         case CRITERIA_MESSAGE:
727                 return MATCHING_MESSAGE;
728         default:
729                 return -1;
730         }
731 }
732
733 static gint prefs_matcher_not_criteria(gint matcher_criteria)
734 {
735         switch(matcher_criteria) {
736         case MATCHING_UNREAD:
737                 return MATCHING_NOT_UNREAD;
738         case MATCHING_NEW:
739                 return MATCHING_NOT_NEW;
740         case MATCHING_MARKED:
741                 return MATCHING_NOT_MARKED;
742         case MATCHING_DELETED:
743                 return MATCHING_NOT_DELETED;
744         case MATCHING_REPLIED:
745                 return MATCHING_NOT_REPLIED;
746         case MATCHING_FORWARDED:
747                 return MATCHING_NOT_FORWARDED;
748         case MATCHING_SUBJECT:
749                 return MATCHING_NOT_SUBJECT;
750         case MATCHING_FROM:
751                 return MATCHING_NOT_FROM;
752         case MATCHING_TO:
753                 return MATCHING_NOT_TO;
754         case MATCHING_CC:
755                 return MATCHING_NOT_CC;
756         case MATCHING_TO_OR_CC:
757                 return MATCHING_NOT_TO_AND_NOT_CC;
758         case MATCHING_NEWSGROUPS:
759                 return MATCHING_NOT_NEWSGROUPS;
760         case MATCHING_INREPLYTO:
761                 return MATCHING_NOT_INREPLYTO;
762         case MATCHING_REFERENCES:
763                 return MATCHING_NOT_REFERENCES;
764         case MATCHING_HEADER:
765                 return MATCHING_NOT_HEADER;
766         case MATCHING_HEADERS_PART:
767                 return MATCHING_NOT_HEADERS_PART;
768         case MATCHING_MESSAGE:
769                 return MATCHING_NOT_MESSAGE;
770         case MATCHING_BODY_PART:
771                 return MATCHING_NOT_BODY_PART;
772         default:
773                 return matcher_criteria;
774         }
775 }
776
777 static MatcherProp * prefs_matcher_dialog_to_matcher()
778 {
779         MatcherProp * matcherprop;
780         gint criteria;
781         gint matchtype;
782         gint value_pred;
783         gint value_pred_flag;
784         gint value_criteria;
785         gboolean use_regexp;
786         gboolean case_sensitive;
787         gchar * header;
788         gchar * expr;
789         gint value;
790         gchar * value_str;
791
792         value_criteria = get_sel_from_list(GTK_LIST(matcher.criteria_list));
793
794         criteria = prefs_matcher_get_matching_from_criteria(value_criteria);
795
796         value_pred = get_sel_from_list(GTK_LIST(matcher.predicate_list));
797         value_pred_flag = get_sel_from_list(GTK_LIST(matcher.predicate_flag_list));
798
799         use_regexp = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(matcher.regexp_chkbtn));
800         case_sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(matcher.case_chkbtn));
801
802         switch (value_criteria) {
803         case CRITERIA_UNREAD:
804         case CRITERIA_NEW:
805         case CRITERIA_MARKED:
806         case CRITERIA_DELETED:
807         case CRITERIA_REPLIED:
808         case CRITERIA_FORWARDED:
809                 if (value_pred_flag == PREDICATE_FLAG_DISABLED)
810                         criteria = prefs_matcher_not_criteria(criteria);
811                 break;
812         case CRITERIA_SUBJECT:
813         case CRITERIA_FROM:
814         case CRITERIA_TO:
815         case CRITERIA_CC:
816         case CRITERIA_TO_OR_CC:
817         case CRITERIA_NEWSGROUPS:
818         case CRITERIA_INREPLYTO:
819         case CRITERIA_REFERENCES:
820         case CRITERIA_HEADERS_PART:
821         case CRITERIA_BODY_PART:
822         case CRITERIA_MESSAGE:
823         case CRITERIA_AGE_GREATER:
824         case CRITERIA_AGE_LOWER:
825         case CRITERIA_HEADER:
826                 if (value_pred == PREDICATE_DOES_NOT_CONTAIN)
827                         criteria = prefs_matcher_not_criteria(criteria);
828                 break;
829         }
830
831         if (use_regexp) {
832                 if (case_sensitive)
833                         matchtype = MATCHING_REGEXP;
834                 else
835                         matchtype = MATCHING_REGEXPCASE;
836         }
837         else {
838                 if (case_sensitive)
839                         matchtype = MATCHING_MATCH;
840                 else
841                         matchtype = MATCHING_MATCHCASE;
842         }
843
844         header = NULL;
845         expr = NULL;
846         value = 0;
847
848         switch (value_criteria) {
849         case CRITERIA_ALL:
850         case CRITERIA_UNREAD:
851         case CRITERIA_NEW:
852         case CRITERIA_MARKED:
853         case CRITERIA_DELETED:
854         case CRITERIA_REPLIED:
855         case CRITERIA_FORWARDED:
856                 break;
857
858         case CRITERIA_SUBJECT:
859         case CRITERIA_FROM:
860         case CRITERIA_TO:
861         case CRITERIA_CC:
862         case CRITERIA_TO_OR_CC:
863         case CRITERIA_NEWSGROUPS:
864         case CRITERIA_INREPLYTO:
865         case CRITERIA_REFERENCES:
866         case CRITERIA_HEADERS_PART:
867         case CRITERIA_BODY_PART:
868         case CRITERIA_MESSAGE:
869                 expr = gtk_entry_get_text(GTK_ENTRY(matcher.value_entry));
870
871                 /*
872                 if (*expr == '\0') {
873                     alertpanel_error(_("Match string is not set."));
874                     return NULL;
875                 }
876                 */
877                 break;
878
879         case CRITERIA_AGE_GREATER:
880         case CRITERIA_AGE_LOWER:
881         case CRITERIA_SCORE_GREATER:
882         case CRITERIA_SCORE_LOWER:
883                 value_str = gtk_entry_get_text(GTK_ENTRY(matcher.value_entry));
884
885                 if (*value_str == '\0') {
886                     alertpanel_error(_("Value is not set."));
887                     return NULL;
888                 }
889
890                 value = atoi(value_str);
891
892                 break;
893
894         case CRITERIA_HEADER:
895
896                 header = gtk_entry_get_text(GTK_ENTRY(matcher.header_entry));
897                 expr = gtk_entry_get_text(GTK_ENTRY(matcher.value_entry));
898
899                 if (*header == '\0') {
900                     alertpanel_error(_("Header name is not set."));
901                     return NULL;
902                 }
903                 /*
904                 if (*expr == '\0') {
905                     alertpanel_error(_("Match string is not set."));
906                     return NULL;
907                 }
908                 */
909                 break;
910         }
911
912         matcherprop =  matcherprop_new(criteria, header, matchtype,
913                                        expr, value);
914
915         return matcherprop;
916 }
917
918 static void prefs_matcher_register_cb(void)
919 {
920         MatcherProp * matcherprop;
921         
922         matcherprop = prefs_matcher_dialog_to_matcher();
923         if (matcherprop == NULL)
924                 return;
925
926         prefs_matcher_clist_set_row(-1, matcherprop);
927
928         matcherprop_free(matcherprop);
929
930         prefs_matcher_reset_condition();
931 }
932
933 static void prefs_matcher_substitute_cb(void)
934 {
935         GtkCList *clist = GTK_CLIST(matcher.cond_clist);
936         gint row;
937         MatcherProp * matcherprop;
938
939         row = GPOINTER_TO_INT(clist->selection->data);
940         if (row == 0)
941                 return;
942         
943         matcherprop = prefs_matcher_dialog_to_matcher();
944         if (matcherprop == NULL)
945                 return;
946
947         prefs_matcher_clist_set_row(row, matcherprop);
948
949         matcherprop_free(matcherprop);
950
951         prefs_matcher_reset_condition();
952 }
953
954 static void prefs_matcher_delete_cb(void)
955 {
956         GtkCList *clist = GTK_CLIST(matcher.cond_clist);
957         gint row;
958
959         if (!clist->selection) return;
960         row = GPOINTER_TO_INT(clist->selection->data);
961         if (row == 0)
962                 return;
963
964         gtk_clist_remove(clist, row);
965 }
966
967 static void prefs_matcher_up(void)
968 {
969         GtkCList *clist = GTK_CLIST(matcher.cond_clist);
970         gint row;
971
972         if (!clist->selection) return;
973
974         row = GPOINTER_TO_INT(clist->selection->data);
975         if (row > 1)
976                 gtk_clist_row_move(clist, row, row - 1);
977 }
978
979 static void prefs_matcher_down(void)
980 {
981         GtkCList *clist = GTK_CLIST(matcher.cond_clist);
982         gint row;
983
984         if (!clist->selection) return;
985
986         row = GPOINTER_TO_INT(clist->selection->data);
987         if (row >= 1 && row < clist->rows - 1)
988                 gtk_clist_row_move(clist, row, row + 1);
989 }
990
991 static void prefs_matcher_select(GtkCList *clist, gint row, gint column,
992                                  GdkEvent *event)
993 {
994         gchar * matcher_str;
995         gchar * tmp;
996         MatcherProp * prop;
997         gboolean negative_cond;
998
999         if (!gtk_clist_get_text(GTK_CLIST(matcher.cond_clist),
1000                                 row, 0, &matcher_str))
1001                 return;
1002
1003         negative_cond = FALSE;
1004
1005         if (row == 0) {
1006                 prefs_matcher_reset_condition();
1007                 return;
1008         }
1009
1010         tmp = matcher_str;
1011         prop = matcherprop_parse(&tmp);
1012         if (tmp == NULL)
1013                 return;
1014
1015         switch(prop->criteria) {
1016         case MATCHING_ALL:
1017                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1018                                      CRITERIA_ALL);
1019                 break;
1020
1021         case MATCHING_NOT_UNREAD:
1022                 negative_cond = TRUE;
1023         case MATCHING_UNREAD:
1024                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1025                                      CRITERIA_UNREAD);
1026                 break;
1027
1028         case MATCHING_NOT_NEW:
1029                 negative_cond = TRUE;
1030         case MATCHING_NEW:
1031                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1032                                      CRITERIA_NEW);
1033                 break;
1034
1035         case MATCHING_NOT_MARKED:
1036                 negative_cond = TRUE;
1037         case MATCHING_MARKED:
1038                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1039                                      CRITERIA_MARKED);
1040                 break;
1041
1042         case MATCHING_NOT_DELETED:
1043                 negative_cond = TRUE;
1044         case MATCHING_DELETED:
1045                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1046                                      CRITERIA_DELETED);
1047                 break;
1048
1049         case MATCHING_NOT_REPLIED:
1050                 negative_cond = TRUE;
1051         case MATCHING_REPLIED:
1052                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1053                                      CRITERIA_REPLIED);
1054                 break;
1055
1056         case MATCHING_NOT_FORWARDED:
1057                 negative_cond = TRUE;
1058         case MATCHING_FORWARDED:
1059                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1060                                      CRITERIA_FORWARDED);
1061                 break;
1062
1063         case MATCHING_NOT_SUBJECT:
1064                 negative_cond = TRUE;
1065         case MATCHING_SUBJECT:
1066                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1067                                      CRITERIA_SUBJECT);
1068                 break;
1069
1070         case MATCHING_NOT_FROM:
1071                 negative_cond = TRUE;
1072         case MATCHING_FROM:
1073                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1074                                      CRITERIA_FROM);
1075                 break;
1076
1077         case MATCHING_NOT_TO:
1078                 negative_cond = TRUE;
1079         case MATCHING_TO:
1080                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1081                                      CRITERIA_TO);
1082                 break;
1083
1084         case MATCHING_NOT_CC:
1085                 negative_cond = TRUE;
1086         case MATCHING_CC:
1087                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1088                                      CRITERIA_CC);
1089                 break;
1090
1091         case MATCHING_NOT_NEWSGROUPS:
1092                 negative_cond = TRUE;
1093         case MATCHING_NEWSGROUPS:
1094                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1095                                      CRITERIA_NEWSGROUPS);
1096                 break;
1097
1098         case MATCHING_NOT_INREPLYTO:
1099                 negative_cond = TRUE;
1100         case MATCHING_INREPLYTO:
1101                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1102                                      CRITERIA_INREPLYTO);
1103                 break;
1104
1105         case MATCHING_NOT_REFERENCES:
1106                 negative_cond = TRUE;
1107         case MATCHING_REFERENCES:
1108                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1109                                      CRITERIA_REFERENCES);
1110                 break;
1111
1112         case MATCHING_NOT_TO_AND_NOT_CC:
1113                 negative_cond = TRUE;
1114         case MATCHING_TO_OR_CC:
1115                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1116                                      CRITERIA_TO_OR_CC);
1117                 break;
1118
1119         case MATCHING_NOT_BODY_PART:
1120                 negative_cond = TRUE;
1121         case MATCHING_BODY_PART:
1122                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1123                                      CRITERIA_BODY_PART);
1124                 break;
1125
1126         case MATCHING_NOT_MESSAGE:
1127                 negative_cond = TRUE;
1128         case MATCHING_MESSAGE:
1129                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1130                                      CRITERIA_MESSAGE);
1131                 break;
1132
1133         case MATCHING_NOT_HEADERS_PART:
1134                 negative_cond = TRUE;
1135         case MATCHING_HEADERS_PART:
1136                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1137                                      CRITERIA_HEADERS_PART);
1138                 break;
1139
1140         case MATCHING_NOT_HEADER:
1141                 negative_cond = TRUE;
1142         case MATCHING_HEADER:
1143                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1144                                      CRITERIA_HEADER);
1145                 break;
1146
1147         case MATCHING_AGE_GREATER:
1148                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1149                                      CRITERIA_AGE_GREATER);
1150                 break;
1151
1152         case MATCHING_AGE_LOWER:
1153                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1154                                      CRITERIA_AGE_LOWER);
1155                 break;
1156
1157         case MATCHING_SCORE_GREATER:
1158                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1159                                      CRITERIA_SCORE_GREATER);
1160                 break;
1161
1162         case MATCHING_SCORE_LOWER:
1163                 gtk_list_select_item(GTK_LIST(matcher.criteria_list),
1164                                      CRITERIA_SCORE_LOWER);
1165                 break;
1166         }
1167         
1168         switch(prop->criteria) {
1169         case MATCHING_ALL:
1170                 break;
1171
1172         case MATCHING_NOT_SUBJECT:
1173         case MATCHING_NOT_FROM:
1174         case MATCHING_NOT_TO:
1175         case MATCHING_NOT_CC:
1176         case MATCHING_NOT_TO_AND_NOT_CC:
1177         case MATCHING_NOT_NEWSGROUPS:
1178         case MATCHING_NOT_INREPLYTO:
1179         case MATCHING_NOT_REFERENCES:
1180         case MATCHING_NOT_HEADERS_PART:
1181         case MATCHING_NOT_BODY_PART:
1182         case MATCHING_NOT_MESSAGE:
1183         case MATCHING_SUBJECT:
1184         case MATCHING_FROM:
1185         case MATCHING_TO:
1186         case MATCHING_CC:
1187         case MATCHING_TO_OR_CC:
1188         case MATCHING_NEWSGROUPS:
1189         case MATCHING_INREPLYTO:
1190         case MATCHING_REFERENCES:
1191         case MATCHING_HEADERS_PART:
1192         case MATCHING_BODY_PART:
1193         case MATCHING_MESSAGE:
1194                 gtk_entry_set_text(GTK_ENTRY(matcher.value_entry), prop->expr);
1195                 break;
1196
1197         case MATCHING_AGE_GREATER:
1198         case MATCHING_AGE_LOWER:
1199         case MATCHING_SCORE_GREATER:
1200         case MATCHING_SCORE_LOWER:
1201                 gtk_entry_set_text(GTK_ENTRY(matcher.value_entry), itos(prop->value));
1202                 break;
1203
1204         case MATCHING_NOT_HEADER:
1205         case MATCHING_HEADER:
1206                 gtk_entry_set_text(GTK_ENTRY(matcher.header_entry), prop->header);
1207                 gtk_entry_set_text(GTK_ENTRY(matcher.value_entry), prop->expr);
1208                 break;
1209         }
1210
1211         if (negative_cond)
1212                 gtk_list_select_item(GTK_LIST(matcher.predicate_list), 1);
1213         else
1214                 gtk_list_select_item(GTK_LIST(matcher.predicate_list), 0);
1215
1216         switch(prop->matchtype) {
1217         case MATCHING_MATCH:
1218                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.regexp_chkbtn), FALSE);
1219                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.case_chkbtn), TRUE);
1220                 break;
1221
1222         case MATCHING_MATCHCASE:
1223                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.regexp_chkbtn), FALSE);
1224                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.case_chkbtn), FALSE);
1225                 break;
1226
1227         case MATCHING_REGEXP:
1228                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.regexp_chkbtn), TRUE);
1229                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.case_chkbtn), TRUE);
1230                 break;
1231
1232         case MATCHING_REGEXPCASE:
1233                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.regexp_chkbtn), TRUE);
1234                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(matcher.case_chkbtn), FALSE);
1235                 break;
1236         }
1237 }
1238
1239 static void prefs_matcher_criteria_select(GtkList *list,
1240                                           GtkWidget *widget,
1241                                           gpointer user_data)
1242 {
1243         gint value;
1244
1245         value = get_sel_from_list(GTK_LIST(matcher.criteria_list));
1246
1247         switch (value) {
1248         case CRITERIA_ALL:
1249                 gtk_widget_set_sensitive(matcher.header_combo, FALSE);
1250                 gtk_widget_set_sensitive(matcher.header_label, FALSE);
1251                 gtk_widget_set_sensitive(matcher.value_label, FALSE);
1252                 gtk_widget_set_sensitive(matcher.value_entry, FALSE);
1253                 gtk_widget_set_sensitive(matcher.predicate_label, FALSE);
1254                 gtk_widget_set_sensitive(matcher.predicate_combo, FALSE);
1255                 gtk_widget_set_sensitive(matcher.predicate_flag_combo, FALSE);
1256                 gtk_widget_hide(matcher.predicate_combo);
1257                 gtk_widget_show(matcher.predicate_flag_combo);
1258                 gtk_widget_set_sensitive(matcher.case_chkbtn, FALSE);
1259                 gtk_widget_set_sensitive(matcher.regexp_chkbtn, FALSE);
1260                 break;
1261
1262         case CRITERIA_UNREAD:
1263         case CRITERIA_NEW:
1264         case CRITERIA_MARKED:
1265         case CRITERIA_DELETED:
1266         case CRITERIA_REPLIED:
1267         case CRITERIA_FORWARDED:
1268                 gtk_widget_set_sensitive(matcher.header_combo, FALSE);
1269                 gtk_widget_set_sensitive(matcher.header_label, FALSE);
1270                 gtk_widget_set_sensitive(matcher.value_label, FALSE);
1271                 gtk_widget_set_sensitive(matcher.value_entry, FALSE);
1272                 gtk_widget_set_sensitive(matcher.predicate_label, TRUE);
1273                 gtk_widget_set_sensitive(matcher.predicate_combo, FALSE);
1274                 gtk_widget_set_sensitive(matcher.predicate_flag_combo, TRUE);
1275                 gtk_widget_hide(matcher.predicate_combo);
1276                 gtk_widget_show(matcher.predicate_flag_combo);
1277                 gtk_widget_set_sensitive(matcher.case_chkbtn, FALSE);
1278                 gtk_widget_set_sensitive(matcher.regexp_chkbtn, FALSE);
1279                 break;
1280
1281         case CRITERIA_SUBJECT:
1282         case CRITERIA_FROM:
1283         case CRITERIA_TO:
1284         case CRITERIA_CC:
1285         case CRITERIA_TO_OR_CC:
1286         case CRITERIA_NEWSGROUPS:
1287         case CRITERIA_INREPLYTO:
1288         case CRITERIA_REFERENCES:
1289         case CRITERIA_HEADERS_PART:
1290         case CRITERIA_BODY_PART:
1291         case CRITERIA_MESSAGE:
1292                 gtk_widget_set_sensitive(matcher.header_combo, FALSE);
1293                 gtk_widget_set_sensitive(matcher.header_label, FALSE);
1294                 gtk_widget_set_sensitive(matcher.value_label, TRUE);
1295                 gtk_widget_set_sensitive(matcher.value_entry, TRUE);
1296                 gtk_widget_set_sensitive(matcher.predicate_label, TRUE);
1297                 gtk_widget_set_sensitive(matcher.predicate_combo, TRUE);
1298                 gtk_widget_set_sensitive(matcher.predicate_flag_combo, FALSE);
1299                 gtk_widget_show(matcher.predicate_combo);
1300                 gtk_widget_hide(matcher.predicate_flag_combo);
1301                 gtk_widget_set_sensitive(matcher.case_chkbtn, TRUE);
1302                 gtk_widget_set_sensitive(matcher.regexp_chkbtn, TRUE);
1303                 break;
1304
1305         case CRITERIA_AGE_GREATER:
1306         case CRITERIA_AGE_LOWER:
1307         case CRITERIA_SCORE_GREATER:
1308         case CRITERIA_SCORE_LOWER:
1309                 gtk_widget_set_sensitive(matcher.header_combo, FALSE);
1310                 gtk_widget_set_sensitive(matcher.header_label, FALSE);
1311                 gtk_widget_set_sensitive(matcher.value_label, TRUE);
1312                 gtk_widget_set_sensitive(matcher.value_entry, TRUE);
1313                 gtk_widget_set_sensitive(matcher.predicate_label, FALSE);
1314                 gtk_widget_set_sensitive(matcher.predicate_combo, FALSE);
1315                 gtk_widget_set_sensitive(matcher.predicate_flag_combo, FALSE);
1316                 gtk_widget_show(matcher.predicate_combo);
1317                 gtk_widget_hide(matcher.predicate_flag_combo);
1318                 gtk_widget_set_sensitive(matcher.case_chkbtn, FALSE);
1319                 gtk_widget_set_sensitive(matcher.regexp_chkbtn, FALSE);
1320                 break;
1321
1322         case CRITERIA_HEADER:
1323                 gtk_widget_set_sensitive(matcher.header_combo, TRUE);
1324                 gtk_widget_set_sensitive(matcher.header_label, TRUE);
1325                 gtk_widget_set_sensitive(matcher.value_label, TRUE);
1326                 gtk_widget_set_sensitive(matcher.value_entry, TRUE);
1327                 gtk_widget_set_sensitive(matcher.predicate_label, TRUE);
1328                 gtk_widget_set_sensitive(matcher.predicate_combo, TRUE);
1329                 gtk_widget_set_sensitive(matcher.predicate_flag_combo, FALSE);
1330                 gtk_widget_show(matcher.predicate_combo);
1331                 gtk_widget_hide(matcher.predicate_flag_combo);
1332                 gtk_widget_set_sensitive(matcher.case_chkbtn, TRUE);
1333                 gtk_widget_set_sensitive(matcher.regexp_chkbtn, TRUE);
1334                 break;
1335         }
1336 }
1337
1338 static void prefs_matcher_key_pressed(GtkWidget *widget, GdkEventKey *event,
1339                                      gpointer data)
1340 {
1341         if (event && event->keyval == GDK_Escape)
1342                 prefs_matcher_cancel();
1343 }
1344
1345 static void prefs_matcher_cancel(void)
1346 {
1347         gtk_widget_hide(matcher.window);
1348 }
1349
1350 static void prefs_matcher_ok(void)
1351 {
1352         MatcherList * matchers;
1353
1354         matchers = prefs_matcher_get_list();
1355         if (matchers != NULL) {
1356                 gtk_widget_hide(matcher.window);
1357                 if (matchers_callback != NULL)
1358                         matchers_callback(matchers);
1359                 matcherlist_free(matchers);
1360         }
1361         else {
1362                 gtk_widget_hide(matcher.window);
1363         }
1364 }
1365
1366 static gint prefs_matcher_deleted(GtkWidget *widget, GdkEventAny *event,
1367                                   gpointer data)
1368 {
1369         prefs_matcher_cancel();
1370         return TRUE;
1371 }