queue notification / run a command when filtering and match with a command
[claws.git] / src / prefs_scoring.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_scoring.h"
39 #include "prefs_common.h"
40 #include "mainwindow.h"
41 #include "foldersel.h"
42 #include "manage_window.h"
43 #include "inc.h"
44 #include "utils.h"
45 #include "gtkutils.h"
46 #include "alertpanel.h"
47 #include "folder.h"
48 #include "scoring.h"
49
50 static struct Scoring {
51         GtkWidget *window;
52
53         GtkWidget *ok_btn;
54         GtkWidget *cond_entry;
55         GtkWidget *score_entry;
56         GtkWidget *kill_score_label;
57         GtkWidget *kill_score_entry;
58         GtkWidget *important_score_entry;
59
60         GtkWidget *cond_clist;
61 } scoring;
62
63 /*
64    parameter name, default value, pointer to the prefs variable, data type,
65    pointer to the widget pointer,
66    pointer to the function for data setting,
67    pointer to the function for widget setting
68  */
69
70 #define VSPACING                12
71 #define VSPACING_NARROW         4
72 #define DEFAULT_ENTRY_WIDTH     80
73 #define PREFSBUFSIZE            1024
74
75 /* widget creating functions */
76 static void prefs_scoring_create                (void);
77
78 static void prefs_scoring_set_dialog    (ScoringProp * prop);
79 static void prefs_scoring_set_list      (void);
80
81 /* callback functions */
82 /* static void prefs_scoring_select_dest_cb     (void); */
83 static void prefs_scoring_register_cb   (void);
84 static void prefs_scoring_substitute_cb (void);
85 static void prefs_scoring_delete_cb     (void);
86 static void prefs_scoring_up            (void);
87 static void prefs_scoring_down          (void);
88 static void prefs_scoring_select                (GtkCList       *clist,
89                                          gint            row,
90                                          gint            column,
91                                          GdkEvent       *event);
92
93 static gint prefs_scoring_deleted       (GtkWidget      *widget,
94                                          GdkEventAny    *event,
95                                          gpointer        data);
96 static void prefs_scoring_key_pressed   (GtkWidget      *widget,
97                                          GdkEventKey    *event,
98                                          gpointer        data);
99 static void prefs_scoring_cancel                (void);
100 static void prefs_scoring_ok            (void);
101
102 static void prefs_scoring_condition_define      (void);
103 static gint prefs_scoring_clist_set_row(gint row, ScoringProp * prop);
104 static void prefs_scoring_select_set_dialog(ScoringProp * prop);
105 static void prefs_scoring_reset_dialog(void);
106
107
108 static FolderItem * cur_item = NULL;
109 static gint cur_important_score;
110 static gint cur_kill_score;
111
112 void prefs_scoring_open(FolderItem * item)
113 {
114         inc_autocheck_timer_remove();
115
116         if (!scoring.window) {
117                 prefs_scoring_create();
118         }
119
120         manage_window_set_transient(GTK_WINDOW(scoring.window));
121         gtk_widget_grab_focus(scoring.ok_btn);
122
123         cur_item = item;
124
125         prefs_scoring_set_dialog(NULL);
126
127         gtk_widget_show(scoring.window);
128 }
129
130 void prefs_scoring_open_with_scoring(ScoringProp * prop)
131 {
132         inc_autocheck_timer_remove();
133
134         if (!scoring.window) {
135                 prefs_scoring_create();
136         }
137
138         manage_window_set_transient(GTK_WINDOW(scoring.window));
139         gtk_widget_grab_focus(scoring.ok_btn);
140
141         prefs_scoring_set_dialog(prop);
142
143         gtk_widget_show(scoring.window);
144 }
145
146 static void prefs_scoring_create(void)
147 {
148         GtkWidget *window;
149         GtkWidget *vbox;
150         GtkWidget *ok_btn;
151         GtkWidget *cancel_btn;
152         GtkWidget *confirm_area;
153
154         GtkWidget *vbox1;
155         GtkWidget *hbox1;
156         GtkWidget *reg_hbox;
157         GtkWidget *arrow;
158         GtkWidget *btn_hbox;
159
160         GtkWidget *cond_label;
161         GtkWidget *cond_entry;
162         GtkWidget *cond_btn;
163         GtkWidget *score_label;
164         GtkWidget *score_entry;
165
166         GtkWidget *reg_btn;
167         GtkWidget *subst_btn;
168         GtkWidget *del_btn;
169
170         GtkWidget *cond_hbox;
171         GtkWidget *cond_scrolledwin;
172         GtkWidget *cond_clist;
173
174         GtkWidget *btn_vbox;
175         GtkWidget *up_btn;
176         GtkWidget *down_btn;
177
178         GtkWidget *important_score_entry;
179         GtkWidget *kill_score_entry;
180         GtkWidget *kill_score_label;
181
182         gchar *title[] = {_("Registered rules")};
183
184         debug_print(_("Creating scoring setting window...\n"));
185
186         window = gtk_window_new (GTK_WINDOW_DIALOG);
187         gtk_container_set_border_width (GTK_CONTAINER (window), 8);
188         gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
189         gtk_window_set_modal (GTK_WINDOW (window), TRUE);
190         gtk_window_set_policy (GTK_WINDOW (window), FALSE, TRUE, FALSE);
191
192         vbox = gtk_vbox_new (FALSE, 6);
193         gtk_widget_show (vbox);
194         gtk_container_add (GTK_CONTAINER (window), vbox);
195
196         gtkut_button_set_create(&confirm_area, &ok_btn, _("OK"),
197                                 &cancel_btn, _("Cancel"), NULL, NULL);
198         gtk_widget_show (confirm_area);
199         gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
200         gtk_widget_grab_default (ok_btn);
201
202         gtk_window_set_title (GTK_WINDOW(window),
203                               _("Scoring setting"));
204         gtk_signal_connect (GTK_OBJECT(window), "delete_event",
205                             GTK_SIGNAL_FUNC(prefs_scoring_deleted), NULL);
206         gtk_signal_connect (GTK_OBJECT(window), "key_press_event",
207                             GTK_SIGNAL_FUNC(prefs_scoring_key_pressed), NULL);
208         gtk_signal_connect (GTK_OBJECT(window), "focus_in_event",
209                             GTK_SIGNAL_FUNC(manage_window_focus_in), NULL);
210         gtk_signal_connect (GTK_OBJECT(window), "focus_out_event",
211                             GTK_SIGNAL_FUNC(manage_window_focus_out), NULL);
212         gtk_signal_connect (GTK_OBJECT(ok_btn), "clicked",
213                             GTK_SIGNAL_FUNC(prefs_scoring_ok), NULL);
214         gtk_signal_connect (GTK_OBJECT(cancel_btn), "clicked",
215                             GTK_SIGNAL_FUNC(prefs_scoring_cancel), NULL);
216
217         vbox1 = gtk_vbox_new (FALSE, VSPACING);
218         gtk_widget_show (vbox1);
219         gtk_box_pack_start (GTK_BOX (vbox), vbox1, TRUE, TRUE, 0);
220         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
221
222         cond_label = gtk_label_new (_("Condition"));
223         gtk_widget_show (cond_label);
224         gtk_misc_set_alignment (GTK_MISC (cond_label), 0, 0.5);
225         gtk_box_pack_start (GTK_BOX (vbox1), cond_label, FALSE, FALSE, 0);
226
227         hbox1 = gtk_hbox_new (FALSE, VSPACING);
228         gtk_widget_show (vbox1);
229         gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
230         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
231
232         cond_entry = gtk_entry_new ();
233         gtk_widget_show (cond_entry);
234         gtk_widget_set_usize (cond_entry, 300, -1);
235         gtk_box_pack_start (GTK_BOX (hbox1), cond_entry, TRUE, TRUE, 0);
236
237         cond_btn = gtk_button_new_with_label (_("Define ..."));
238         gtk_widget_show (cond_btn);
239         gtk_box_pack_start (GTK_BOX (hbox1), cond_btn, FALSE, FALSE, 0);
240         gtk_signal_connect (GTK_OBJECT (cond_btn), "clicked",
241                             GTK_SIGNAL_FUNC (prefs_scoring_condition_define),
242                             NULL);
243
244         hbox1 = gtk_hbox_new (FALSE, VSPACING);
245         gtk_widget_show (vbox1);
246         gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
247         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
248
249         score_label = gtk_label_new (_("Score"));
250         gtk_widget_show (score_label);
251         gtk_misc_set_alignment (GTK_MISC (score_label), 0, 0.5);
252         gtk_box_pack_start (GTK_BOX (hbox1), score_label, FALSE, FALSE, 0);
253
254         score_entry = gtk_entry_new ();
255         gtk_widget_show (score_entry);
256         gtk_widget_set_usize (score_entry, 50, -1);
257         gtk_box_pack_start (GTK_BOX (hbox1), score_entry, FALSE, FALSE, 0);
258
259         /* register / substitute / delete */
260
261         reg_hbox = gtk_hbox_new (FALSE, 4);
262         gtk_widget_show (reg_hbox);
263         gtk_box_pack_start (GTK_BOX (vbox1), reg_hbox, FALSE, FALSE, 0);
264
265         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
266         gtk_widget_show (arrow);
267         gtk_box_pack_start (GTK_BOX (reg_hbox), arrow, FALSE, FALSE, 0);
268         gtk_widget_set_usize (arrow, -1, 16);
269
270         btn_hbox = gtk_hbox_new (TRUE, 4);
271         gtk_widget_show (btn_hbox);
272         gtk_box_pack_start (GTK_BOX (reg_hbox), btn_hbox, FALSE, FALSE, 0);
273
274         reg_btn = gtk_button_new_with_label (_("Register"));
275         gtk_widget_show (reg_btn);
276         gtk_box_pack_start (GTK_BOX (btn_hbox), reg_btn, FALSE, TRUE, 0);
277         gtk_signal_connect (GTK_OBJECT (reg_btn), "clicked",
278                             GTK_SIGNAL_FUNC (prefs_scoring_register_cb), NULL);
279
280         subst_btn = gtk_button_new_with_label (_(" Substitute "));
281         gtk_widget_show (subst_btn);
282         gtk_box_pack_start (GTK_BOX (btn_hbox), subst_btn, FALSE, TRUE, 0);
283         gtk_signal_connect (GTK_OBJECT (subst_btn), "clicked",
284                             GTK_SIGNAL_FUNC (prefs_scoring_substitute_cb),
285                             NULL);
286
287         del_btn = gtk_button_new_with_label (_("Delete"));
288         gtk_widget_show (del_btn);
289         gtk_box_pack_start (GTK_BOX (btn_hbox), del_btn, FALSE, TRUE, 0);
290         gtk_signal_connect (GTK_OBJECT (del_btn), "clicked",
291                             GTK_SIGNAL_FUNC (prefs_scoring_delete_cb), NULL);
292
293         cond_hbox = gtk_hbox_new (FALSE, 8);
294         gtk_widget_show (cond_hbox);
295         gtk_box_pack_start (GTK_BOX (vbox1), cond_hbox, TRUE, TRUE, 0);
296
297         cond_scrolledwin = gtk_scrolled_window_new (NULL, NULL);
298         gtk_widget_show (cond_scrolledwin);
299         gtk_widget_set_usize (cond_scrolledwin, -1, 150);
300         gtk_box_pack_start (GTK_BOX (cond_hbox), cond_scrolledwin,
301                             TRUE, TRUE, 0);
302         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (cond_scrolledwin),
303                                         GTK_POLICY_AUTOMATIC,
304                                         GTK_POLICY_AUTOMATIC);
305
306         cond_clist = gtk_clist_new_with_titles(1, title);
307         gtk_widget_show (cond_clist);
308         gtk_container_add (GTK_CONTAINER (cond_scrolledwin), cond_clist);
309         gtk_clist_set_column_width (GTK_CLIST (cond_clist), 0, 80);
310         gtk_clist_set_selection_mode (GTK_CLIST (cond_clist),
311                                       GTK_SELECTION_BROWSE);
312         GTK_WIDGET_UNSET_FLAGS (GTK_CLIST (cond_clist)->column[0].button,
313                                 GTK_CAN_FOCUS);
314         gtk_signal_connect (GTK_OBJECT (cond_clist), "select_row",
315                             GTK_SIGNAL_FUNC (prefs_scoring_select), NULL);
316
317         btn_vbox = gtk_vbox_new (FALSE, 8);
318         gtk_widget_show (btn_vbox);
319         gtk_box_pack_start (GTK_BOX (cond_hbox), btn_vbox, FALSE, FALSE, 0);
320
321         up_btn = gtk_button_new_with_label (_("Up"));
322         gtk_widget_show (up_btn);
323         gtk_box_pack_start (GTK_BOX (btn_vbox), up_btn, FALSE, FALSE, 0);
324         gtk_signal_connect (GTK_OBJECT (up_btn), "clicked",
325                             GTK_SIGNAL_FUNC (prefs_scoring_up), NULL);
326
327         down_btn = gtk_button_new_with_label (_("Down"));
328         gtk_widget_show (down_btn);
329         gtk_box_pack_start (GTK_BOX (btn_vbox), down_btn, FALSE, FALSE, 0);
330         gtk_signal_connect (GTK_OBJECT (down_btn), "clicked",
331                             GTK_SIGNAL_FUNC (prefs_scoring_down), NULL);
332
333         hbox1 = gtk_hbox_new (FALSE, 8);
334         gtk_widget_show (hbox1);
335         gtk_box_pack_start (GTK_BOX (vbox1), hbox1, TRUE, TRUE, 0);
336
337         kill_score_label = gtk_label_new (_("Kill score"));
338         gtk_widget_show (kill_score_label);
339         gtk_misc_set_alignment (GTK_MISC (kill_score_label), 0, 0.5);
340         gtk_box_pack_start (GTK_BOX (hbox1), kill_score_label,
341                             FALSE, FALSE, 0);
342
343         kill_score_entry = gtk_entry_new ();
344         gtk_widget_show (kill_score_entry);
345         gtk_widget_set_usize (kill_score_entry, 50, -1);
346         gtk_box_pack_start (GTK_BOX (hbox1), kill_score_entry,
347                             FALSE, FALSE, 0);
348
349         score_label = gtk_label_new (_("Important score"));
350         gtk_widget_show (score_label);
351         gtk_misc_set_alignment (GTK_MISC (score_label), 0, 0.5);
352         gtk_box_pack_start (GTK_BOX (hbox1), score_label, FALSE, FALSE, 0);
353
354         important_score_entry = gtk_entry_new ();
355         gtk_widget_show (important_score_entry);
356         gtk_widget_set_usize (important_score_entry, 50, -1);
357         gtk_box_pack_start (GTK_BOX (hbox1), important_score_entry,
358                             FALSE, FALSE, 0);
359
360         gtk_widget_show_all(window);
361
362         scoring.window    = window;
363         scoring.ok_btn = ok_btn;
364
365         scoring.cond_entry = cond_entry;
366         scoring.score_entry = score_entry;
367         scoring.kill_score_entry = kill_score_entry;
368         scoring.kill_score_label = kill_score_label;
369         scoring.important_score_entry = important_score_entry;
370
371         scoring.cond_clist   = cond_clist;
372 }
373
374 static void prefs_scoring_set_dialog(ScoringProp * cond)
375 {
376         GtkCList *clist = GTK_CLIST(scoring.cond_clist);
377         GSList *cur;
378         GSList * prefs_scoring;
379         gchar * score_str;
380
381         if (cond == NULL)
382                 prefs_scoring_reset_dialog();
383         else
384                 prefs_scoring_select_set_dialog(cond);
385
386         gtk_clist_freeze(clist);
387         gtk_clist_clear(clist);
388
389         prefs_scoring_clist_set_row(-1, NULL);
390         if (cur_item == NULL) {
391                 prefs_scoring = global_scoring;
392                 cur_kill_score = prefs_common.kill_score;
393                 cur_important_score = prefs_common.important_score;
394                 gtk_widget_show(scoring.kill_score_label);
395                 gtk_widget_show(scoring.kill_score_entry);
396         }
397         else {
398                 prefs_scoring = cur_item->prefs->scoring;
399                 cur_kill_score = cur_item->prefs->kill_score;
400                 cur_important_score = cur_item->prefs->important_score;
401                 if (cur_item->folder->type != F_NEWS) {
402                         gtk_widget_hide(scoring.kill_score_label);
403                         gtk_widget_hide(scoring.kill_score_entry);
404                 }
405                 else {
406                         gtk_widget_show(scoring.kill_score_label);
407                         gtk_widget_show(scoring.kill_score_entry);
408                 }
409         }
410
411         for(cur = prefs_scoring ; cur != NULL ;
412             cur = g_slist_next(cur)) {
413                 ScoringProp * prop = (ScoringProp *) cur->data;
414                 
415                 prefs_scoring_clist_set_row(-1, prop);
416         }
417
418         score_str = itos(cur_kill_score);
419         gtk_entry_set_text(GTK_ENTRY(scoring.kill_score_entry),
420                            score_str);
421         score_str = itos(cur_important_score);
422         gtk_entry_set_text(GTK_ENTRY(scoring.important_score_entry),
423                            score_str);
424
425         gtk_clist_thaw(clist);
426 }
427
428 static void prefs_scoring_reset_dialog(void)
429 {
430         gtk_entry_set_text(GTK_ENTRY(scoring.cond_entry), "");
431         gtk_entry_set_text(GTK_ENTRY(scoring.score_entry), "");
432 }
433
434 static void prefs_scoring_set_list(void)
435 {
436         gint row = 1;
437         ScoringProp *prop;
438         GSList * cur;
439         gchar * scoring_str;
440         gchar * tmp;
441         GSList * prefs_scoring;
442
443         if (cur_item == NULL)
444                 prefs_scoring = global_scoring;
445         else
446                 prefs_scoring = cur_item->prefs->scoring;
447
448         for(cur = prefs_scoring ; cur != NULL ;
449             cur = g_slist_next(cur))
450                 scoringprop_free((ScoringProp *) cur->data);
451         g_slist_free(prefs_scoring);
452         prefs_scoring = NULL;
453
454         while (gtk_clist_get_text(GTK_CLIST(scoring.cond_clist),
455                                   row, 0, &scoring_str)) {
456                 if (strcmp(scoring_str, _("(New)")) != 0) {
457                         tmp = scoring_str;
458                         prop = scoringprop_parse(&tmp);
459                         if (prop != NULL)
460                                 prefs_scoring = g_slist_append(prefs_scoring,
461                                                                prop);
462                 }
463                 row++;
464         }
465
466         cur_kill_score = atoi(gtk_entry_get_text(GTK_ENTRY(scoring.kill_score_entry)));
467         cur_important_score = atoi(gtk_entry_get_text(GTK_ENTRY(scoring.important_score_entry)));
468
469         if (cur_item == NULL) {
470                 global_scoring = prefs_scoring;
471                 prefs_common.kill_score = cur_kill_score;
472                 prefs_common.important_score = cur_important_score;
473         }
474         else {
475                 cur_item->prefs->scoring = prefs_scoring;
476                 cur_item->prefs->kill_score = cur_kill_score;
477                 cur_item->prefs->important_score = cur_important_score;
478         }
479 }
480
481 static gint prefs_scoring_clist_set_row(gint row, ScoringProp * prop)
482 {
483         GtkCList *clist = GTK_CLIST(scoring.cond_clist);
484         gchar * str;
485         gchar *cond_str[1];
486
487         if (prop == NULL) {
488                 cond_str[0] = _("(New)");
489                 return gtk_clist_append(clist, cond_str);
490         }
491
492         str = scoringprop_to_string(prop);
493         if (str == NULL) {
494                 return -1;
495         }
496         cond_str[0] = str;
497
498         if (row < 0)
499                 row = gtk_clist_append(clist, cond_str);
500         else
501                 gtk_clist_set_text(clist, row, 0, cond_str[0]);
502         g_free(str);
503
504         return row;
505 }
506
507 static void prefs_scoring_condition_define_done(MatcherList * matchers)
508 {
509         gchar * str;
510
511         if (matchers == NULL)
512                 return;
513
514         str = matcherlist_to_string(matchers);
515
516         if (str != NULL) {
517                 gtk_entry_set_text(GTK_ENTRY(scoring.cond_entry), str);
518                 g_free(str);
519         }
520 }
521
522 static void prefs_scoring_condition_define(void)
523 {
524         gchar * cond_str;
525         MatcherList * matchers = NULL;
526
527         cond_str = gtk_entry_get_text(GTK_ENTRY(scoring.cond_entry));
528
529         if (*cond_str != '\0') {
530                 gchar * tmp;
531                 
532                 tmp = cond_str;
533                 matchers = matcherlist_parse(&tmp);
534                 if (tmp == NULL)
535                         alertpanel_error(_("Match string is not valid."));
536         }
537
538         prefs_matcher_open(matchers, prefs_scoring_condition_define_done);
539
540         if (matchers != NULL)
541                 matcherlist_free(matchers);
542 }
543
544
545 /* register / substitute delete buttons */
546
547 static void prefs_scoring_register_cb(void)
548 {
549         MatcherList * cond;
550         gchar * cond_str;
551         gchar * score_str;
552         ScoringProp * prop;
553         gint score;
554         gchar * tmp;
555
556         cond_str = gtk_entry_get_text(GTK_ENTRY(scoring.cond_entry));
557         if (*cond_str == '\0') {
558                 alertpanel_error(_("Score is not set."));
559                 return;
560         }
561
562         score_str = gtk_entry_get_text(GTK_ENTRY(scoring.score_entry));
563         if (*score_str == '\0') {
564                 alertpanel_error(_("Match string is not set."));
565                 return;
566         }
567
568         score = atoi(score_str);
569         tmp = cond_str;
570         cond = matcherlist_parse(&tmp);
571
572         if (tmp == NULL) {
573                 alertpanel_error(_("Match string is not valid."));
574                 return;
575         }
576
577         prop = scoringprop_new(cond, score);
578
579         prefs_scoring_clist_set_row(-1, prop);
580
581         scoringprop_free(prop);
582
583         prefs_scoring_reset_dialog();
584 }
585
586 static void prefs_scoring_substitute_cb(void)
587 {
588         GtkCList *clist = GTK_CLIST(scoring.cond_clist);
589         gint row;
590         MatcherList * cond;
591         gchar * cond_str;
592         gchar * score_str;
593         ScoringProp * prop;
594         gint score;
595         gchar * tmp;
596
597         if (!clist->selection) return;
598
599         row = GPOINTER_TO_INT(clist->selection->data);
600         if (row == 0) return;
601
602         cond_str = gtk_entry_get_text(GTK_ENTRY(scoring.cond_entry));
603         if (*cond_str == '\0') {
604                 alertpanel_error(_("Score is not set."));
605                 return;
606         }
607
608         score_str = gtk_entry_get_text(GTK_ENTRY(scoring.score_entry));
609         if (*score_str == '\0') {
610                 alertpanel_error(_("Match string is not set."));
611                 return;
612         }
613
614         score = atoi(score_str);
615         tmp = cond_str;
616         cond = matcherlist_parse(&tmp);
617
618         if (tmp == NULL) {
619                 alertpanel_error(_("Match string is not valid."));
620                 return;
621         }
622
623         prop = scoringprop_new(cond, score);
624
625         prefs_scoring_clist_set_row(row, prop);
626
627         scoringprop_free(prop);
628
629         prefs_scoring_reset_dialog();
630 }
631
632 static void prefs_scoring_delete_cb(void)
633 {
634         GtkCList *clist = GTK_CLIST(scoring.cond_clist);
635         gint row;
636
637         if (!clist->selection) return;
638         row = GPOINTER_TO_INT(clist->selection->data);
639         if (row == 0) return;
640
641         if (alertpanel(_("Delete rule"),
642                        _("Do you really want to delete this rule?"),
643                        _("Yes"), _("No"), NULL) == G_ALERTALTERNATE)
644                 return;
645
646         gtk_clist_remove(clist, row);
647 }
648
649 static void prefs_scoring_up(void)
650 {
651         GtkCList *clist = GTK_CLIST(scoring.cond_clist);
652         gint row;
653
654         if (!clist->selection) return;
655
656         row = GPOINTER_TO_INT(clist->selection->data);
657         if (row > 1) {
658                 gtk_clist_row_move(clist, row, row - 1);
659         }
660 }
661
662 static void prefs_scoring_down(void)
663 {
664         GtkCList *clist = GTK_CLIST(scoring.cond_clist);
665         gint row;
666
667         if (!clist->selection) return;
668
669         row = GPOINTER_TO_INT(clist->selection->data);
670         if (row > 0 && row < clist->rows - 1) {
671                 gtk_clist_row_move(clist, row, row + 1);
672         }
673 }
674
675 static void prefs_scoring_select_set_dialog(ScoringProp * prop)
676 {
677         gchar * matcher_str;
678         gchar * score_str;
679
680         if (prop == NULL)
681                 return;
682
683         matcher_str = matcherlist_to_string(prop->matchers);
684         if (matcher_str == NULL) {
685                 scoringprop_free(prop);
686                 return;
687         }
688
689         score_str = itos(prop->score);
690
691         gtk_entry_set_text(GTK_ENTRY(scoring.cond_entry), matcher_str);
692         gtk_entry_set_text(GTK_ENTRY(scoring.score_entry), score_str);
693
694         g_free(matcher_str);
695 }
696
697 static void prefs_scoring_select(GtkCList *clist, gint row, gint column,
698                                 GdkEvent *event)
699 {
700         ScoringProp * prop;
701         gchar * tmp;
702
703         gchar * scoring_str;
704
705         if (row == 0) {
706                 prefs_scoring_reset_dialog();
707                 return;
708         }
709
710         if (!gtk_clist_get_text(GTK_CLIST(scoring.cond_clist),
711                                 row, 0, &scoring_str))
712                 return;
713
714         tmp = scoring_str;
715         prop = scoringprop_parse(&tmp);
716         if (tmp == NULL)
717                 return;
718
719         prefs_scoring_select_set_dialog(prop);
720
721         scoringprop_free(prop);
722 }
723
724 static gint prefs_scoring_deleted(GtkWidget *widget, GdkEventAny *event,
725                                  gpointer data)
726 {
727         prefs_scoring_cancel();
728         return TRUE;
729 }
730
731 static void prefs_scoring_key_pressed(GtkWidget *widget, GdkEventKey *event,
732                                      gpointer data)
733 {
734         if (event && event->keyval == GDK_Escape)
735                 prefs_scoring_cancel();
736 }
737
738 static void prefs_scoring_ok(void)
739 {
740         prefs_scoring_set_list();
741         prefs_scoring_write_config();
742         if (cur_item != NULL)
743                 prefs_folder_item_save_config(cur_item);
744         gtk_widget_hide(scoring.window);
745 }
746
747 static void prefs_scoring_cancel(void)
748 {
749         prefs_scoring_read_config();
750         gtk_widget_hide(scoring.window);
751 }