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