3cd5302ead37a48b5b5147b5bd5ae93039ce0a06
[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         N_("or"), N_("and")
118 };
119
120 enum {
121         PREDICATE_CONTAINS = 0,
122         PREDICATE_DOES_NOT_CONTAIN = 1
123 };
124
125 gchar * predicate_text [] = {
126         N_("contains"), N_("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         N_("yes"), N_("no")
136 };
137
138 gchar * criteria_text [] = {
139         N_("All messages"), N_("Subject"),
140         N_("From"), N_("To"), N_("Cc"), N_("To or Cc"),
141         N_("Newsgroups"), N_("In reply to"), N_("References"),
142         N_("Age greater than"), N_("Age lower than"),
143         N_("Header"), N_("Headers part"),
144         N_("Body part"), N_("Whole message"),
145         N_("Unread flag"), N_("New flag"),
146         N_("Marked flag"), N_("Deleted flag"),
147         N_("Replied flag"), N_("Forwarded flag"),
148         N_("Score greater than"), N_("Score lower than"),
149         N_("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 }