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