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