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