prefs_matcher.[ch] added
[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 *close_btn;
53
54         GtkWidget *criteria_entry;
55         GtkWidget *header_entry;
56         GtkWidget *header_label;
57         GtkWidget *value_entry;
58         GtkWidget *value_label;
59         GtkWidget *predicate_label;
60         GtkWidget *predicate_entry;
61         GtkWidget *case_chkbtn;
62         GtkWidget *regexp_chkbtn;
63         GtkWidget *bool_op_entry;
64
65         GtkWidget *cond_clist;
66 } matcher;
67
68 /* choice in the list */
69
70 enum {
71         CRITERIA_ALL = 0,
72         CRITERIA_SUBJECT = 1,
73         CRITERIA_FROM = 2,
74         CRITERIA_TO = 3,
75         CRITERIA_CC = 4,
76         CRITERIA_TO_OR_CC = 5,
77         CRITERIA_NEWSGROUPS = 6,
78         CRITERIA_AGE_GREATER = 7,
79         CRITERIA_AGE_LOWER = 8,
80         CRITERIA_HEADER = 9,
81         CRITERIA_HEADERS_PART = 10,
82         CRITERIA_BODY_PART = 11,
83         CRITERIA_MESSAGE = 12
84 };
85
86 gchar * bool_op_text [] = {
87         "and", "or"
88 };
89
90 gchar * predicate_text [] = {
91         "contains", "does not contain"
92 };
93
94 gchar * criteria_text [] = {
95         "All messages", "Subject",
96         "From", "To", "Cc", "To or Cc",
97         "Newsgroups",
98         "Age greater than", "Age lower than",
99         "Header", "Headers part",
100         "Body part", "Whole message"
101 };
102
103 gint criteria_get_from_string(gchar * text)
104 {
105         gint i;
106         
107         for(i = 0 ; i < (gint) (sizeof(criteria_text) / sizeof(gchar *)) ;
108             i++) {
109                 if (strcmp(_(criteria_text[i]), text) == 0)
110                         return i;
111         }
112         return -1;
113 }
114
115 gint predicate_get_from_string(gchar * text)
116 {
117         gint i;
118         
119         for(i = 0 ; i < (gint) (sizeof(predicate_text) / sizeof(gchar *)) ;
120             i++) {
121                 if (strcmp(_(predicate_text[i]), text) == 0)
122                         return i;
123         }
124         return -1;
125 }
126
127 enum {
128         PREDICATE_CONTAINS = 0,
129         PREDICATE_DOES_NOT_CONTAIN = 1
130 };
131
132 /* static MatcherList * tmp_list; */
133 /* static MatcherProp * tmp_matcher; */
134
135 /*
136    parameter name, default value, pointer to the prefs variable, data type,
137    pointer to the widget pointer,
138    pointer to the function for data setting,
139    pointer to the function for widget setting
140  */
141
142 #define VSPACING                12
143 #define VSPACING_NARROW         4
144 #define DEFAULT_ENTRY_WIDTH     80
145 #define PREFSBUFSIZE            1024
146
147 /* widget creating functions */
148 static void prefs_matcher_create        (void);
149
150 static void prefs_matcher_set_dialog    (void);
151
152 /*
153 static void prefs_matcher_set_list      (void);
154 static gint prefs_matcher_clist_set_row (gint    row);
155 */
156
157 /* callback functions */
158
159 /*
160 static void prefs_matcher_select_dest_cb        (void);
161 */
162 static void prefs_matcher_register_cb   (void);
163 static void prefs_matcher_substitute_cb (void);
164 static void prefs_matcher_delete_cb     (void);
165 static void prefs_matcher_up            (void);
166 static void prefs_matcher_down          (void);
167 /*
168 static void prefs_matcher_select                (GtkCList       *clist,
169                                          gint            row,
170                                          gint            column,
171                                          GdkEvent       *event);
172 */
173
174 /*
175 static void prefs_matcher_dest_radio_button_toggled     (void);
176 static void prefs_matcher_notrecv_radio_button_toggled  (void);
177 */
178
179 static void prefs_matcher_key_pressed   (GtkWidget      *widget,
180                                          GdkEventKey    *event,
181                                          gpointer        data);
182 static void prefs_matcher_close         (void);
183 static gint prefs_matcher_deleted(GtkWidget *widget, GdkEventAny *event,
184                                   gpointer data);
185 static void prefs_matcher_criteria_select(GtkEditable *editable,
186                                           gpointer user_data);
187
188 void prefs_matcher_open(MatcherList * matchers)
189 {
190         inc_autocheck_timer_remove();
191
192         if (!matcher.window) {
193                 prefs_matcher_create();
194         }
195
196         manage_window_set_transient(GTK_WINDOW(matcher.window));
197         gtk_widget_grab_focus(matcher.close_btn);
198
199         /*      tmp_matchers = matchers; */
200         prefs_matcher_set_dialog();
201
202         gtk_widget_show(matcher.window);
203 }
204
205 static void prefs_matcher_create(void)
206 {
207         GtkWidget *window;
208         GtkWidget *vbox;
209         GtkWidget *close_btn;
210         GtkWidget *confirm_area;
211
212         GtkWidget *vbox1;
213         GtkWidget *vbox2;
214         GtkWidget *vbox3;
215         GtkWidget *table1;
216
217         GtkWidget *hbox1;
218
219         GtkWidget *header_combo;
220         GtkWidget *header_entry;
221         GtkWidget *header_label;
222         GtkWidget *criteria_combo;
223         GtkWidget *criteria_entry;
224         GtkWidget *criteria_label;
225         GtkWidget *value_label;
226         GtkWidget *value_entry;
227         GtkWidget *predicate_combo;
228         GtkWidget *predicate_entry;
229         GtkWidget *predicate_label;
230         GtkWidget *bool_op_combo;
231         GtkWidget *bool_op_entry;
232         GtkWidget *bool_op_label;
233
234         GtkWidget *regexp_chkbtn;
235         GtkWidget *case_chkbtn;
236
237         GtkWidget *reg_hbox;
238         GtkWidget *btn_hbox;
239         GtkWidget *arrow;
240         GtkWidget *reg_btn;
241         GtkWidget *subst_btn;
242         GtkWidget *del_btn;
243
244         GtkWidget *cond_hbox;
245         GtkWidget *cond_scrolledwin;
246         GtkWidget *cond_clist;
247
248         GtkWidget *btn_vbox;
249         GtkWidget *up_btn;
250         GtkWidget *down_btn;
251
252         GList *combo_items;
253         gint i;
254
255         gchar *title[] = {_("Registered rules")};
256
257         debug_print(_("Creating matcher setting window...\n"));
258
259         window = gtk_window_new (GTK_WINDOW_DIALOG);
260         gtk_container_set_border_width (GTK_CONTAINER (window), 8);
261         gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
262         gtk_window_set_modal (GTK_WINDOW (window), TRUE);
263         gtk_window_set_policy (GTK_WINDOW (window), FALSE, TRUE, FALSE);
264
265         vbox = gtk_vbox_new (FALSE, 6);
266         gtk_widget_show (vbox);
267         gtk_container_add (GTK_CONTAINER (window), vbox);
268
269         gtkut_button_set_create (&confirm_area, &close_btn, _("Close"),
270                                  NULL, NULL, NULL, NULL);
271         gtk_widget_show (confirm_area);
272         gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
273         gtk_widget_grab_default (close_btn);
274
275         gtk_window_set_title (GTK_WINDOW(window),
276                               _("Condition setting"));
277         gtk_signal_connect (GTK_OBJECT(window), "delete_event",
278                             GTK_SIGNAL_FUNC(prefs_matcher_deleted), NULL);
279         gtk_signal_connect (GTK_OBJECT(window), "key_press_event",
280                             GTK_SIGNAL_FUNC(prefs_matcher_key_pressed), NULL);
281         gtk_signal_connect (GTK_OBJECT(window), "focus_in_event",
282                             GTK_SIGNAL_FUNC(manage_window_focus_in), NULL);
283         gtk_signal_connect (GTK_OBJECT(window), "focus_out_event",
284                             GTK_SIGNAL_FUNC(manage_window_focus_out), NULL);
285         gtk_signal_connect (GTK_OBJECT(close_btn), "clicked",
286                             GTK_SIGNAL_FUNC(prefs_matcher_close), NULL);
287
288         vbox1 = gtk_vbox_new (FALSE, VSPACING);
289         gtk_widget_show (vbox1);
290         gtk_box_pack_start (GTK_BOX (vbox), vbox1, TRUE, TRUE, 0);
291         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
292
293         table1 = gtk_table_new (2, 3, FALSE);
294         gtk_widget_show (table1);
295
296         gtk_box_pack_start (GTK_BOX (vbox1), table1, FALSE, TRUE, 0);
297         gtk_table_set_row_spacings (GTK_TABLE (table1), 8);
298         gtk_table_set_col_spacings (GTK_TABLE (table1), 8);
299
300         /* criteria combo box */
301
302         criteria_label = gtk_label_new (_("Match type"));
303         gtk_widget_show (criteria_label);
304         gtk_misc_set_alignment (GTK_MISC (criteria_label), 0, 0.5);
305         gtk_table_attach (GTK_TABLE (table1), criteria_label, 0, 1, 0, 1,
306                           GTK_FILL, 0, 0, 0);
307
308         criteria_combo = gtk_combo_new ();
309         gtk_widget_show (criteria_combo);
310
311         combo_items = NULL;
312
313         for(i = 0 ; i < (gint) (sizeof(criteria_text) / sizeof(gchar *)) ;
314             i++) {
315                 combo_items = g_list_append(combo_items,
316                                             (gpointer) _(criteria_text[i]));
317         }
318         gtk_combo_set_popdown_strings(GTK_COMBO(criteria_combo), combo_items);
319
320         g_list_free(combo_items);
321
322         gtk_widget_set_usize (criteria_combo, 120, -1);
323         gtk_table_attach (GTK_TABLE (table1), criteria_combo, 0, 1, 1, 2,
324                           0, 0, 0, 0);
325         criteria_entry = GTK_COMBO(criteria_combo)->entry;
326         gtk_signal_connect (GTK_OBJECT (criteria_entry), "changed",
327                             GTK_SIGNAL_FUNC (prefs_matcher_criteria_select),
328                             NULL);
329
330         criteria_entry = GTK_COMBO (criteria_combo)->entry;
331         gtk_entry_set_editable (GTK_ENTRY (criteria_entry), FALSE);
332
333         /* header name */
334
335         header_label = gtk_label_new (_("Header name"));
336         gtk_widget_show (header_label);
337         gtk_misc_set_alignment (GTK_MISC (header_label), 0, 0.5);
338         gtk_table_attach (GTK_TABLE (table1), header_label, 1, 2, 0, 1,
339                           GTK_FILL, 0, 0, 0);
340
341         header_combo = gtk_combo_new ();
342         gtk_widget_show (header_combo);
343         gtk_widget_set_usize (header_combo, 96, -1);
344         gtkut_combo_set_items (GTK_COMBO (header_combo),
345                                "Subject", "From", "To", "Cc", "Reply-To",
346                                "Sender", "X-ML-Name", "X-List", "X-Sequence",
347                                "X-Mailer",
348                                NULL);
349         gtk_table_attach (GTK_TABLE (table1), header_combo, 1, 2, 1, 2,
350                           0, 0, 0, 0);
351         header_entry = GTK_COMBO (header_combo)->entry;
352         gtk_entry_set_editable (GTK_ENTRY (header_entry), TRUE);
353
354         /* value */
355
356         value_label = gtk_label_new (_("Value"));
357         gtk_widget_show (value_label);
358         gtk_misc_set_alignment (GTK_MISC (value_label), 0, 0.5);
359         gtk_table_attach (GTK_TABLE (table1), value_label, 2, 3, 0, 1,
360                           GTK_FILL, 0, 0, 0);
361
362         value_entry = gtk_entry_new ();
363         gtk_widget_show (value_entry);
364         gtk_widget_set_usize (value_entry, 200, -1);
365         gtk_table_attach (GTK_TABLE (table1), value_entry, 2, 3, 1, 2,
366                           0, 0, 0, 0);
367
368
369         /* predicate */
370
371         vbox2 = gtk_vbox_new (FALSE, VSPACING);
372         gtk_widget_show (vbox2);
373         gtk_box_pack_start (GTK_BOX (vbox1), vbox2, TRUE, TRUE, 0);
374
375         hbox1 = gtk_hbox_new (FALSE, 8);
376         gtk_widget_show (hbox1);
377         gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, TRUE, 0);
378
379         predicate_label = gtk_label_new (_("Predicate"));
380         gtk_widget_show (predicate_label);
381         gtk_box_pack_start (GTK_BOX (hbox1), predicate_label,
382                             FALSE, FALSE, 0);
383
384         predicate_combo = gtk_combo_new ();
385         gtk_widget_show (predicate_combo);
386         gtk_widget_set_usize (predicate_combo, 120, -1);
387         predicate_entry = GTK_COMBO(predicate_combo)->entry;
388         gtk_entry_set_editable (GTK_ENTRY (predicate_entry), FALSE);
389
390         combo_items = NULL;
391
392         for(i = 0 ; i < (gint) (sizeof(predicate_text) / sizeof(gchar *)) ;
393             i++) {
394                 combo_items = g_list_append(combo_items,
395                                             (gpointer) _(predicate_text[i]));
396         }
397         gtk_combo_set_popdown_strings(GTK_COMBO(predicate_combo), combo_items);
398
399         g_list_free(combo_items);
400
401         gtk_box_pack_start (GTK_BOX (hbox1), predicate_combo,
402                             FALSE, FALSE, 0);
403
404         vbox3 = gtk_vbox_new (FALSE, 0);
405         gtk_widget_show (vbox3);
406         gtk_box_pack_start (GTK_BOX (hbox1), vbox3, TRUE, TRUE, 0);
407
408         PACK_CHECK_BUTTON (vbox3, case_chkbtn, _("Case sensitive"));
409         PACK_CHECK_BUTTON (vbox3, regexp_chkbtn, _("Use regexp"));
410
411         /* register / substitute / delete */
412
413         reg_hbox = gtk_hbox_new (FALSE, 4);
414         gtk_widget_show (reg_hbox);
415         gtk_box_pack_start (GTK_BOX (vbox1), reg_hbox, FALSE, FALSE, 0);
416
417         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
418         gtk_widget_show (arrow);
419         gtk_box_pack_start (GTK_BOX (reg_hbox), arrow, FALSE, FALSE, 0);
420         gtk_widget_set_usize (arrow, -1, 16);
421
422         btn_hbox = gtk_hbox_new (TRUE, 4);
423         gtk_widget_show (btn_hbox);
424         gtk_box_pack_start (GTK_BOX (reg_hbox), btn_hbox, FALSE, FALSE, 0);
425
426         reg_btn = gtk_button_new_with_label (_("Register"));
427         gtk_widget_show (reg_btn);
428         gtk_box_pack_start (GTK_BOX (btn_hbox), reg_btn, FALSE, TRUE, 0);
429         gtk_signal_connect (GTK_OBJECT (reg_btn), "clicked",
430                             GTK_SIGNAL_FUNC (prefs_matcher_register_cb), NULL);
431
432         subst_btn = gtk_button_new_with_label (_(" Substitute "));
433         gtk_widget_show (subst_btn);
434         gtk_box_pack_start (GTK_BOX (btn_hbox), subst_btn, FALSE, TRUE, 0);
435         gtk_signal_connect (GTK_OBJECT (subst_btn), "clicked",
436                             GTK_SIGNAL_FUNC (prefs_matcher_substitute_cb),
437                             NULL);
438
439         del_btn = gtk_button_new_with_label (_("Delete"));
440         gtk_widget_show (del_btn);
441         gtk_box_pack_start (GTK_BOX (btn_hbox), del_btn, FALSE, TRUE, 0);
442         gtk_signal_connect (GTK_OBJECT (del_btn), "clicked",
443                             GTK_SIGNAL_FUNC (prefs_matcher_delete_cb), NULL);
444
445         /* boolean operation */
446
447         /*
448         hbox1 = gtk_hbox_new (TRUE, 4);
449         gtk_widget_show (btn_hbox);
450         gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
451         */
452
453         bool_op_label = gtk_label_new (_("Boolean Op"));
454         gtk_misc_set_alignment (GTK_MISC (value_label), 0, 0.5);
455         gtk_widget_show (bool_op_label);
456         gtk_box_pack_start (GTK_BOX (btn_hbox), bool_op_label,
457                             FALSE, FALSE, 0);
458
459         bool_op_combo = gtk_combo_new ();
460         gtk_widget_show (bool_op_combo);
461         gtk_widget_set_usize (bool_op_combo, 50, -1);
462         bool_op_entry = GTK_COMBO(bool_op_combo)->entry;
463         gtk_entry_set_editable (GTK_ENTRY (bool_op_entry), FALSE);
464
465         combo_items = NULL;
466
467         for(i = 0 ; i < (gint) (sizeof(bool_op_text) / sizeof(gchar *)) ;
468             i++) {
469                 combo_items = g_list_append(combo_items,
470                                             (gpointer) _(bool_op_text[i]));
471         }
472         gtk_combo_set_popdown_strings(GTK_COMBO(bool_op_combo), combo_items);
473
474         g_list_free(combo_items);
475
476         gtk_box_pack_start (GTK_BOX (btn_hbox), bool_op_combo,
477                             FALSE, TRUE, 0);
478
479         cond_hbox = gtk_hbox_new (FALSE, 8);
480         gtk_widget_show (cond_hbox);
481         gtk_box_pack_start (GTK_BOX (vbox1), cond_hbox, TRUE, TRUE, 0);
482
483         cond_scrolledwin = gtk_scrolled_window_new (NULL, NULL);
484         gtk_widget_show (cond_scrolledwin);
485         gtk_widget_set_usize (cond_scrolledwin, -1, 150);
486         gtk_box_pack_start (GTK_BOX (cond_hbox), cond_scrolledwin,
487                             TRUE, TRUE, 0);
488         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (cond_scrolledwin),
489                                         GTK_POLICY_AUTOMATIC,
490                                         GTK_POLICY_AUTOMATIC);
491
492         cond_clist = gtk_clist_new_with_titles(1, title);
493         gtk_widget_show (cond_clist);
494         gtk_container_add (GTK_CONTAINER (cond_scrolledwin), cond_clist);
495         gtk_clist_set_column_width (GTK_CLIST (cond_clist), 0, 80);
496         gtk_clist_set_selection_mode (GTK_CLIST (cond_clist),
497                                       GTK_SELECTION_BROWSE);
498         GTK_WIDGET_UNSET_FLAGS (GTK_CLIST (cond_clist)->column[0].button,
499                                 GTK_CAN_FOCUS);
500         /*
501         gtk_signal_connect (GTK_OBJECT (cond_clist), "select_row",
502                             GTK_SIGNAL_FUNC (prefs_matcher_select), NULL);
503         */
504
505         btn_vbox = gtk_vbox_new (FALSE, 8);
506         gtk_widget_show (btn_vbox);
507         gtk_box_pack_start (GTK_BOX (cond_hbox), btn_vbox, FALSE, FALSE, 0);
508
509         up_btn = gtk_button_new_with_label (_("Up"));
510         gtk_widget_show (up_btn);
511         gtk_box_pack_start (GTK_BOX (btn_vbox), up_btn, FALSE, FALSE, 0);
512         gtk_signal_connect (GTK_OBJECT (up_btn), "clicked",
513                             GTK_SIGNAL_FUNC (prefs_matcher_up), NULL);
514
515         down_btn = gtk_button_new_with_label (_("Down"));
516         gtk_widget_show (down_btn);
517         gtk_box_pack_start (GTK_BOX (btn_vbox), down_btn, FALSE, FALSE, 0);
518         gtk_signal_connect (GTK_OBJECT (down_btn), "clicked",
519                             GTK_SIGNAL_FUNC (prefs_matcher_down), NULL);
520
521         gtk_widget_show_all(window);
522
523         matcher.window    = window;
524         matcher.close_btn = close_btn;
525
526         matcher.criteria_entry = criteria_entry;
527         matcher.header_entry = header_entry;
528         matcher.header_label = header_label;
529         matcher.value_entry = value_entry;
530         matcher.value_label = value_label;
531         matcher.predicate_label = predicate_label;
532         matcher.predicate_entry = predicate_entry;
533         matcher.case_chkbtn = case_chkbtn;
534         matcher.regexp_chkbtn = regexp_chkbtn;
535
536         matcher.cond_clist   = cond_clist;
537 }
538
539 /*
540 void prefs_matcher_read_config(void)
541 {
542         gchar *rcpath;
543         FILE *fp;
544         gchar buf[PREFSBUFSIZE];
545         Matcher *flt;
546
547         debug_print(_("Reading matcher configuration...\n"));
548
549         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_RC, NULL);
550         if ((fp = fopen(rcpath, "r")) == NULL) {
551                 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
552                 g_free(rcpath);
553                 return;
554         }
555         g_free(rcpath);
556 */
557
558         /* remove all previous matcher list */
559
560 /*
561         while (prefs_common.fltlist != NULL) {
562                 flt = (Matcher *)prefs_common.fltlist->data;
563                 filter_free(flt);
564                 prefs_common.fltlist = g_slist_remove(prefs_common.fltlist,
565                                                       flt);
566         }
567
568         while (fgets(buf, sizeof(buf), fp) != NULL) {
569                 g_strchomp(buf);
570                 flt = filter_read_str(buf);
571                 if (flt) {
572                         prefs_common.fltlist =
573                                 g_slist_append(prefs_common.fltlist, flt);
574                 }
575         }
576
577         fclose(fp);
578 }
579
580 void prefs_filter_write_config(void)
581 {
582         gchar *rcpath;
583         PrefFile *pfile;
584         GSList *cur;
585
586         debug_print(_("Writing filter configuration...\n"));
587
588         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_RC, NULL);
589         if ((pfile = prefs_write_open(rcpath)) == NULL) {
590                 g_warning(_("failed to write configuration to file\n"));
591                 g_free(rcpath);
592                 return;
593         }
594
595         for (cur = prefs_common.fltlist; cur != NULL; cur = cur->next) {
596                 Filter *flt = (Filter *)cur->data;
597                 gchar *fstr;
598
599                 fstr = filter_get_str(flt);
600                 if (fputs(fstr, pfile->fp) == EOF ||
601                     fputc('\n', pfile->fp) == EOF) {
602                         FILE_OP_ERROR(rcpath, "fputs || fputc");
603                         prefs_write_close_revert(pfile);
604                         g_free(rcpath);
605                         g_free(fstr);
606                         return;
607                 }
608                 g_free(fstr);
609         }
610
611         g_free(rcpath);
612
613         if (prefs_write_close(pfile) < 0) {
614                 g_warning(_("failed to write configuration to file\n"));
615                 return;
616         }
617 }
618 */
619
620 static void prefs_matcher_set_dialog(void)
621 {
622         /*
623         GtkCList *clist = GTK_CLIST(filter.cond_clist);
624         GSList *cur;
625         gchar *cond_str[1];
626         gint row;
627
628         gtk_clist_freeze(clist);
629         gtk_clist_clear(clist);
630
631         cond_str[0] = _("(New)");
632         row = gtk_clist_append(clist, cond_str);
633         gtk_clist_set_row_data(clist, row, NULL);
634
635         for (cur = prefs_common.fltlist; cur != NULL; cur = cur->next) {
636                 Filter *flt = (Filter *)cur->data;
637
638                 cond_str[0] = filter_get_str(flt);
639                 subst_char(cond_str[0], '\t', ':');
640                 row = gtk_clist_append(clist, cond_str);
641                 gtk_clist_set_row_data(clist, row, flt);
642
643                 g_free(cond_str[0]);
644         }
645
646         gtk_clist_thaw(clist);
647         */
648
649         gtk_entry_set_text(GTK_ENTRY(matcher.criteria_entry),
650                            _(criteria_text[0]));
651         gtk_entry_set_text(GTK_ENTRY(matcher.predicate_entry),
652                            _(predicate_text[0]));
653         gtk_entry_set_text(GTK_ENTRY(matcher.header_entry), "");
654 }
655 /*
656 static void prefs_filter_set_list(void)
657 {
658         gint row = 1;
659         Filter *flt;
660
661         g_slist_free(prefs_common.fltlist);
662         prefs_common.fltlist = NULL;
663
664         while ((flt = gtk_clist_get_row_data(GTK_CLIST(filter.cond_clist),
665                 row)) != NULL) {
666                 prefs_common.fltlist = g_slist_append(prefs_common.fltlist,
667                                                       flt);
668                 row++;
669         }
670 }
671
672 #define GET_ENTRY(entry) \
673         entry_text = gtk_entry_get_text(GTK_ENTRY(entry))
674
675 static gint prefs_filter_clist_set_row(gint row)
676 {
677         GtkCList *clist = GTK_CLIST(filter.cond_clist);
678         Filter *flt;
679         gchar *entry_text;
680         gchar *cond_str[1];
681
682         g_return_val_if_fail(row != 0, -1);
683
684         if (GTK_WIDGET_IS_SENSITIVE(filter.dest_entry))
685                 GET_ENTRY(filter.dest_entry);
686         else
687                 entry_text = FILTER_NOT_RECEIVE;
688         if (entry_text[0] == '\0') {
689                 alertpanel_error(_("Destination is not set."));
690                 return -1;
691         }
692         GET_ENTRY(filter.hdr_entry1);
693         if (entry_text[0] == '\0') {
694                 alertpanel_error(_("Header name is not set."));
695                 return -1;
696         }
697
698         flt = g_new0(Filter, 1);
699
700         flt->name1 = g_strdup(entry_text);
701
702         GET_ENTRY(filter.key_entry1);
703         if (entry_text[0] != '\0')
704                 flt->body1 = g_strdup(entry_text);
705
706         GET_ENTRY(filter.hdr_entry2);
707         if (entry_text[0] != '\0' && strcmp(entry_text, _("(none)")) != 0) {
708                 flt->name2 = g_strdup(entry_text);
709
710                 GET_ENTRY(filter.key_entry2);
711                 if (entry_text[0] != '\0')
712                         flt->body2 = g_strdup(entry_text);
713         }
714
715         GET_ENTRY(filter.pred_entry1);
716         if (!strcmp(entry_text, _("contains")))
717                 flt->flag1 = FLT_CONTAIN;
718         GET_ENTRY(filter.pred_entry2);
719         if (!strcmp(entry_text, _("contains")))
720                 flt->flag2 = FLT_CONTAIN;
721
722         GET_ENTRY(filter.op_entry);
723         if (!strcmp(entry_text, "and"))
724                 flt->cond = FLT_AND;
725         else
726                 flt->cond = FLT_OR;
727
728         if (GTK_WIDGET_IS_SENSITIVE(filter.dest_entry)) {
729                 entry_text = gtk_entry_get_text(GTK_ENTRY(filter.dest_entry));
730                 flt->dest = g_strdup(entry_text);
731                 flt->action = FLT_MOVE;
732         } else
733                 flt->action = FLT_NOTRECV;
734
735         cond_str[0] = filter_get_str(flt);
736         subst_char(cond_str[0], '\t', ':');
737
738         if (row < 0)
739                 row = gtk_clist_append(clist, cond_str);
740         else {
741                 Filter *tmpflt;
742
743                 gtk_clist_set_text(clist, row, 0, cond_str[0]);
744                 tmpflt = gtk_clist_get_row_data(clist, row);
745                 if (tmpflt)
746                         filter_free(tmpflt);
747         }
748
749         gtk_clist_set_row_data(clist, row, flt);
750
751         g_free(cond_str[0]);
752
753         prefs_filter_set_list();
754
755         return row;
756 }
757 */
758
759 static gint prefs_matcher_get_scoring_from_criteria(gint criteria_id)
760 {
761         switch (criteria_id) {
762         case CRITERIA_ALL:
763                 return MATCHING_ALL;
764         case CRITERIA_SUBJECT:
765                 return MATCHING_SUBJECT;
766         case CRITERIA_FROM:
767                 return MATCHING_FROM;
768         case CRITERIA_TO:
769                 return MATCHING_TO;
770         case CRITERIA_CC:
771                 return MATCHING_CC;
772         case CRITERIA_TO_OR_CC:
773                 return MATCHING_TO_OR_CC;
774         case CRITERIA_NEWSGROUPS:
775                 return MATCHING_NEWSGROUPS;
776         case CRITERIA_AGE_GREATER:
777                 return MATCHING_AGE_GREATER;
778         case CRITERIA_AGE_LOWER:
779                 return MATCHING_AGE_LOWER;
780         case CRITERIA_HEADER:
781                 return MATCHING_HEADER;
782         case CRITERIA_HEADERS_PART:
783                 return MATCHING_HEADERS_PART;
784         case CRITERIA_BODY_PART:
785                 return MATCHING_BODY_PART;
786         case CRITERIA_MESSAGE:
787                 return MATCHING_MESSAGE;
788         default:
789                 return -1;
790         }
791 }
792
793 static gint prefs_matcher_not_criteria(gint matcher_criteria)
794 {
795         switch(matcher_criteria) {
796         case MATCHING_SUBJECT:
797                 return MATCHING_NOT_SUBJECT;
798         case MATCHING_FROM:
799                 return MATCHING_NOT_FROM;
800         case MATCHING_TO:
801                 return MATCHING_NOT_TO;
802         case MATCHING_CC:
803                 return MATCHING_NOT_CC;
804         case MATCHING_TO_OR_CC:
805                 return MATCHING_NOT_TO_AND_NOT_CC;
806         case MATCHING_NEWSGROUPS:
807                 return MATCHING_NOT_NEWSGROUPS;
808         case MATCHING_HEADER:
809                 return MATCHING_NOT_HEADER;
810         case MATCHING_HEADERS_PART:
811                 return MATCHING_NOT_HEADERS_PART;
812         case MATCHING_MESSAGE:
813                 return MATCHING_NOT_MESSAGE;
814         case MATCHING_BODY_PART:
815                 return MATCHING_NOT_BODY_PART;
816         default:
817                 return matcher_criteria;
818         }
819 }
820
821 static MatcherProp * prefs_match_dialog_to_matcher()
822 {
823         MatcherProp * matcherprop;
824         gint criteria;
825         gint matchtype;
826         gint value_pred;
827         gint value_criteria;
828         gboolean use_regexp;
829         gboolean case_sensitive;
830         gchar * header;
831         gchar * expr;
832         gint age;
833
834         value_criteria = criteria_get_from_string(gtk_entry_get_text(GTK_ENTRY(matcher.criteria_entry)));
835         criteria = prefs_matcher_get_scoring_from_criteria(value_criteria);
836
837         value_pred =  predicate_get_from_string(gtk_entry_get_text(GTK_ENTRY(matcher.predicate_entry)));
838
839         use_regexp = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(matcher.regexp_chkbtn));
840         case_sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(matcher.case_chkbtn));
841
842         if (value_pred != PREDICATE_CONTAINS)
843                 criteria = prefs_matcher_not_criteria(criteria);
844
845         if (use_regexp) {
846                 if (case_sensitive)
847                         matchtype = MATCHING_REGEXP;
848                 else
849                         matchtype = MATCHING_REGEXPCASE;
850         }
851         else {
852                 if (case_sensitive)
853                         matchtype = MATCHING_MATCH;
854                 else
855                         matchtype = MATCHING_MATCHCASE;
856         }
857
858         header = NULL;
859         expr = NULL;
860         age = 0;
861
862         switch (value_criteria) {
863         case CRITERIA_ALL:
864                 break;
865
866         case CRITERIA_SUBJECT:
867         case CRITERIA_FROM:
868         case CRITERIA_TO:
869         case CRITERIA_CC:
870         case CRITERIA_TO_OR_CC:
871         case CRITERIA_NEWSGROUPS:
872         case CRITERIA_HEADERS_PART:
873         case CRITERIA_BODY_PART:
874         case CRITERIA_MESSAGE:
875                 expr = gtk_entry_get_text(GTK_ENTRY(matcher.value_entry));
876                 break;
877
878         case CRITERIA_AGE_GREATER:
879         case CRITERIA_AGE_LOWER:
880                 age = atoi(gtk_entry_get_text(GTK_ENTRY(matcher.value_entry)));
881                 break;
882
883         case CRITERIA_HEADER:
884                 header = gtk_entry_get_text(GTK_ENTRY(matcher.header_entry));
885                 expr = gtk_entry_get_text(GTK_ENTRY(matcher.value_entry));
886                 break;
887         }
888
889         matcherprop =  matcherprop_new(criteria, header, matchtype, expr, age);
890         
891         return matcherprop;
892 }
893
894 static void prefs_matcher_register_cb(void)
895 {
896         gchar * matcher_str;
897         MatcherProp * matcherprop;
898         GtkCList *clist = GTK_CLIST(matcher.cond_clist);
899         gchar * cond_str[1];
900         gint row;
901         
902         matcherprop = prefs_match_dialog_to_matcher();
903         matcher_str = matcherprop_to_string(matcherprop);
904         matcherprop_free(matcherprop);
905
906         cond_str[0] = matcher_str;
907         row = gtk_clist_append(clist, cond_str);
908         g_free(matcher_str);
909 }
910
911 static void prefs_matcher_substitute_cb(void)
912 {
913         /*
914         GtkCList *clist = GTK_CLIST(filter.cond_clist);
915         Filter *flt;
916         gint row;
917
918         if (!clist->selection) return;
919
920         row = GPOINTER_TO_INT(clist->selection->data);
921         if (row == 0) return;
922
923         flt = gtk_clist_get_row_data(clist, row);
924         if (!flt) return;
925
926         prefs_filter_clist_set_row(row);
927         */
928 }
929
930 static void prefs_matcher_delete_cb(void)
931 {
932         /*
933         GtkCList *clist = GTK_CLIST(filter.cond_clist);
934         Filter *flt;
935         gint row;
936
937         if (!clist->selection) return;
938         row = GPOINTER_TO_INT(clist->selection->data);
939         if (row == 0) return;
940
941         if (alertpanel(_("Delete rule"),
942                        _("Do you really want to delete this rule?"),
943                        _("Yes"), _("No"), NULL) == G_ALERTALTERNATE)
944                 return;
945
946         flt = gtk_clist_get_row_data(clist, row);
947         filter_free(flt);
948         gtk_clist_remove(clist, row);
949         prefs_common.fltlist = g_slist_remove(prefs_common.fltlist, flt);
950         */
951 }
952
953 static void prefs_matcher_up(void)
954 {
955         /*
956         GtkCList *clist = GTK_CLIST(filter.cond_clist);
957         gint row;
958
959         if (!clist->selection) return;
960
961         row = GPOINTER_TO_INT(clist->selection->data);
962         if (row > 1) {
963                 gtk_clist_row_move(clist, row, row - 1);
964                 prefs_filter_set_list();
965         }
966         */
967 }
968
969 static void prefs_matcher_down(void)
970 {
971         /*
972         GtkCList *clist = GTK_CLIST(filter.cond_clist);
973         gint row;
974
975         if (!clist->selection) return;
976
977         row = GPOINTER_TO_INT(clist->selection->data);
978         if (row > 0 && row < clist->rows - 1) {
979                 gtk_clist_row_move(clist, row, row + 1);
980                 prefs_filter_set_list();
981         }
982         */
983 }
984
985 /*
986 #define ENTRY_SET_TEXT(entry, str) \
987         gtk_entry_set_text(GTK_ENTRY(entry), str ? str : "")
988
989 static void prefs_filter_select(GtkCList *clist, gint row, gint column,
990                                 GdkEvent *event)
991 {
992         Filter *flt;
993         Filter default_flt = {"Subject", NULL, _("(none)"), NULL,
994                               FLT_CONTAIN, FLT_CONTAIN, FLT_AND,
995                               NULL, FLT_MOVE};
996
997         flt = gtk_clist_get_row_data(clist, row);
998         if (!flt)
999                 flt = &default_flt;
1000
1001         ENTRY_SET_TEXT(filter.dest_entry, flt->dest);
1002         ENTRY_SET_TEXT(filter.hdr_entry1, flt->name1);
1003         ENTRY_SET_TEXT(filter.key_entry1, flt->body1);
1004         ENTRY_SET_TEXT(filter.hdr_entry2,
1005                        flt->name2 ? flt->name2 : _("(none)"));
1006         ENTRY_SET_TEXT(filter.key_entry2, flt->body2);
1007
1008         ENTRY_SET_TEXT(filter.pred_entry1,
1009                        FLT_IS_CONTAIN(flt->flag1)
1010                        ? _("contains") : _("not contain"));
1011         ENTRY_SET_TEXT(filter.pred_entry2,
1012                        FLT_IS_CONTAIN(flt->flag2)
1013                        ? _("contains") : _("not contain"));
1014
1015         gtk_entry_set_text(GTK_ENTRY(filter.op_entry),
1016                            flt->cond == FLT_OR ? "or" : "and");
1017         if (flt->action == FLT_NOTRECV)
1018                 gtk_toggle_button_set_active
1019                         (GTK_TOGGLE_BUTTON(filter.notrecv_radiobtn), TRUE);
1020         else
1021                 gtk_toggle_button_set_active
1022                         (GTK_TOGGLE_BUTTON(filter.dest_radiobtn), TRUE);
1023 }
1024
1025 static void prefs_filter_dest_radio_button_toggled(void)
1026 {
1027         gtk_widget_set_sensitive(filter.dest_entry, TRUE);
1028         gtk_widget_set_sensitive(filter.destsel_btn, TRUE);
1029 }
1030
1031 static void prefs_filter_notrecv_radio_button_toggled(void)
1032 {
1033         gtk_widget_set_sensitive(filter.dest_entry, FALSE);
1034         gtk_widget_set_sensitive(filter.destsel_btn, FALSE);
1035 }
1036 */
1037
1038
1039 static void prefs_matcher_criteria_select(GtkEditable *editable,
1040                                           gpointer user_data)
1041 {
1042         gint value;
1043
1044         value = criteria_get_from_string(gtk_entry_get_text(GTK_ENTRY(matcher.criteria_entry)));
1045
1046         switch (value) {
1047         case CRITERIA_ALL:
1048                 gtk_widget_set_sensitive(matcher.header_entry, FALSE);
1049                 gtk_widget_set_sensitive(matcher.header_label, FALSE);
1050                 gtk_widget_set_sensitive(matcher.value_label, FALSE);
1051                 gtk_widget_set_sensitive(matcher.value_entry, FALSE);
1052                 gtk_widget_set_sensitive(matcher.predicate_label, FALSE);
1053                 gtk_widget_set_sensitive(matcher.predicate_entry, FALSE);
1054                 gtk_widget_set_sensitive(matcher.case_chkbtn, FALSE);
1055                 gtk_widget_set_sensitive(matcher.regexp_chkbtn, FALSE);
1056                 break;
1057
1058         case CRITERIA_SUBJECT:
1059         case CRITERIA_FROM:
1060         case CRITERIA_TO:
1061         case CRITERIA_CC:
1062         case CRITERIA_TO_OR_CC:
1063         case CRITERIA_NEWSGROUPS:
1064         case CRITERIA_HEADERS_PART:
1065         case CRITERIA_BODY_PART:
1066         case CRITERIA_MESSAGE:
1067                 gtk_widget_set_sensitive(matcher.header_entry, FALSE);
1068                 gtk_widget_set_sensitive(matcher.header_label, FALSE);
1069                 gtk_widget_set_sensitive(matcher.value_label, TRUE);
1070                 gtk_widget_set_sensitive(matcher.value_entry, TRUE);
1071                 gtk_widget_set_sensitive(matcher.predicate_label, TRUE);
1072                 gtk_widget_set_sensitive(matcher.predicate_entry, TRUE);
1073                 gtk_widget_set_sensitive(matcher.case_chkbtn, TRUE);
1074                 gtk_widget_set_sensitive(matcher.regexp_chkbtn, TRUE);
1075                 break;
1076
1077         case CRITERIA_AGE_GREATER:
1078         case CRITERIA_AGE_LOWER:
1079                 gtk_widget_set_sensitive(matcher.header_entry, FALSE);
1080                 gtk_widget_set_sensitive(matcher.header_label, FALSE);
1081                 gtk_widget_set_sensitive(matcher.value_label, TRUE);
1082                 gtk_widget_set_sensitive(matcher.value_entry, TRUE);
1083                 gtk_widget_set_sensitive(matcher.predicate_label, FALSE);
1084                 gtk_widget_set_sensitive(matcher.predicate_entry, FALSE);
1085                 gtk_widget_set_sensitive(matcher.case_chkbtn, FALSE);
1086                 gtk_widget_set_sensitive(matcher.regexp_chkbtn, FALSE);
1087                 break;
1088
1089         case CRITERIA_HEADER:
1090                 gtk_widget_set_sensitive(matcher.header_entry, TRUE);
1091                 gtk_widget_set_sensitive(matcher.header_label, TRUE);
1092                 gtk_widget_set_sensitive(matcher.value_label, TRUE);
1093                 gtk_widget_set_sensitive(matcher.value_entry, TRUE);
1094                 gtk_widget_set_sensitive(matcher.predicate_label, TRUE);
1095                 gtk_widget_set_sensitive(matcher.predicate_entry, TRUE);
1096                 gtk_widget_set_sensitive(matcher.case_chkbtn, TRUE);
1097                 gtk_widget_set_sensitive(matcher.regexp_chkbtn, TRUE);
1098                 break;
1099         }
1100 }
1101
1102 static void prefs_matcher_key_pressed(GtkWidget *widget, GdkEventKey *event,
1103                                      gpointer data)
1104 {
1105         if (event && event->keyval == GDK_Escape)
1106                 prefs_matcher_close();
1107 }
1108
1109 static void prefs_matcher_close(void)
1110 {
1111         /*      prefs_filter_write_config(); */
1112         gtk_widget_hide(matcher.window);
1113         /*
1114         inc_autocheck_timer_set();      
1115         */
1116 }
1117
1118 static gint prefs_matcher_deleted(GtkWidget *widget, GdkEventAny *event,
1119                                   gpointer data)
1120 {
1121         prefs_matcher_close();
1122         return TRUE;
1123 }