sync with sylpheed 0.6.4 release
[claws.git] / src / prefs_filtering.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 <gtk/gtkoptionmenu.h>
29 #include <gdk/gdkkeysyms.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34
35 #include "intl.h"
36 #include "main.h"
37 #include "prefs.h"
38 #include "prefs_matcher.h"
39 #include "prefs_filtering.h"
40 #include "prefs_common.h"
41 #include "mainwindow.h"
42 #include "foldersel.h"
43 #include "manage_window.h"
44 #include "inc.h"
45 #include "utils.h"
46 #include "gtkutils.h"
47 #include "alertpanel.h"
48 #include "folder.h"
49 #include "filtering.h"
50 #include "addr_compl.h"
51 #include "colorlabel.h"
52
53 static struct Filtering {
54         GtkWidget *window;
55
56         GtkWidget *ok_btn;
57         GtkWidget *cond_entry;
58         GtkWidget *action_list;
59         GtkWidget *action_combo;
60         GtkWidget *account_list;
61         GtkWidget *account_combo;
62         GtkWidget *dest_entry;
63         GtkWidget *dest_btn;
64         GtkWidget *dest_label;
65         GtkWidget *exec_label;
66         GtkWidget *exec_btn;
67
68         GtkWidget *color_label;
69         GtkWidget *color_optmenu;
70
71         GtkWidget *cond_clist;
72
73         /* need this to make address completion entry work */
74         gint current_action;
75 } filtering;
76
77 /* widget creating functions */
78 static void prefs_filtering_create              (void);
79
80 static void prefs_filtering_set_dialog  (void);
81 static void prefs_filtering_set_list    (void);
82
83 /* callback functions */
84 /* static void prefs_filtering_select_dest_cb   (void); */
85 static void prefs_filtering_register_cb (void);
86 static void prefs_filtering_substitute_cb       (void);
87 static void prefs_filtering_delete_cb   (void);
88 static void prefs_filtering_up          (void);
89 static void prefs_filtering_down                (void);
90 static void prefs_filtering_select              (GtkCList       *clist,
91                                          gint            row,
92                                          gint            column,
93                                          GdkEvent       *event);
94
95 static gint prefs_filtering_deleted     (GtkWidget      *widget,
96                                          GdkEventAny    *event,
97                                          gpointer        data);
98 static void prefs_filtering_key_pressed (GtkWidget      *widget,
99                                          GdkEventKey    *event,
100                                          gpointer        data);
101 static void prefs_filtering_cancel              (void);
102 static void prefs_filtering_ok          (void);
103
104 static void prefs_filtering_condition_define    (void);
105 static gint prefs_filtering_clist_set_row(gint row, FilteringProp * prop);
106 static void prefs_filtering_select_dest(void);
107 static void prefs_filtering_action_select(GtkList *list,
108                                           GtkWidget *widget, 
109                                           gpointer user_data);
110 static void prefs_filtering_action_selection_changed(GtkList *list,
111                                                      gpointer user_data);
112                                           
113 static void prefs_filtering_reset_dialog(void);
114
115 enum {
116         ACTION_MOVE = 0,
117         ACTION_COPY = 1,
118         ACTION_DELETE = 2,
119         ACTION_MARK = 3,
120         ACTION_UNMARK = 4,
121         ACTION_MARK_AS_READ = 5,
122         ACTION_MARK_AS_UNREAD = 6,
123         ACTION_FORWARD = 7,
124         ACTION_FORWARD_AS_ATTACHMENT = 8,
125         ACTION_EXECUTE = 9,
126         ACTION_COLOR = 10
127 };
128
129 static gint get_sel_from_list(GtkList * list)
130 {
131         gint row = 0;
132         void * sel;
133         GList * child;
134
135         if (list->selection == NULL)
136                 return -1;
137
138         sel = list->selection->data;
139         for(child = list->children ; child != NULL ;
140             child = g_list_next(child)) {
141                 if (child->data == sel)
142                         return row;
143                 row ++;
144         }
145         
146         return row;
147 }
148
149 static gint get_account_id_from_list_id(gint list_id)
150 {
151         GList * accounts;
152
153         for (accounts = account_get_list() ; accounts != NULL;
154              accounts = accounts->next) {
155                 PrefsAccount *ac = (PrefsAccount *)accounts->data;
156
157                 if (list_id == 0)
158                         return ac->account_id;
159                 list_id--;
160         }
161         return 0;
162 }
163
164 static gint get_list_id_from_account_id(gint account_id)
165 {
166         GList * accounts;
167         gint list_id = 0;
168
169         for (accounts = account_get_list() ; accounts != NULL;
170              accounts = accounts->next) {
171                 PrefsAccount *ac = (PrefsAccount *)accounts->data;
172
173                 if (account_id == ac->account_id)
174                         return list_id;
175                 list_id++;
176         }
177         return 0;
178 }
179
180 static gint prefs_filtering_get_matching_from_action(gint action_id)
181 {
182         switch(action_id) {
183         case ACTION_MOVE:
184                 return MATCHING_ACTION_MOVE;
185         case ACTION_COPY:
186                 return MATCHING_ACTION_COPY;
187         case ACTION_DELETE:
188                 return MATCHING_ACTION_DELETE;
189         case ACTION_MARK:
190                 return MATCHING_ACTION_MARK;
191         case ACTION_UNMARK:
192                 return MATCHING_ACTION_UNMARK;
193         case ACTION_MARK_AS_READ:
194                 return MATCHING_ACTION_MARK_AS_READ;
195         case ACTION_MARK_AS_UNREAD:
196                 return MATCHING_ACTION_MARK_AS_UNREAD;
197         case ACTION_FORWARD:
198                 return MATCHING_ACTION_FORWARD;
199         case ACTION_FORWARD_AS_ATTACHMENT:
200                 return MATCHING_ACTION_FORWARD_AS_ATTACHMENT;
201         case ACTION_EXECUTE:
202                 return MATCHING_EXECUTE;
203         case ACTION_COLOR:
204                 return MATCHING_ACTION_COLOR;
205         default:
206                 return -1;
207         }
208 }
209
210 static gchar * action_text [] = {
211         N_("Move"),     
212         N_("Copy"), 
213         N_("Delete"),
214         N_("Mark"), 
215         N_("Unmark"), 
216         N_("Mark as read"), 
217         N_("Mark as unread"),
218         N_("Forward"), 
219         N_("Forward as attachment"), 
220         N_("Execute"),
221         N_("Color")
222 };
223
224 void prefs_filtering_open(void)
225 {
226         if (prefs_rc_is_readonly(FILTERING_RC))
227                 return;
228
229         inc_autocheck_timer_remove();
230
231         if (!filtering.window) {
232                 prefs_filtering_create();
233         }
234
235         manage_window_set_transient(GTK_WINDOW(filtering.window));
236         gtk_widget_grab_focus(filtering.ok_btn);
237
238         prefs_filtering_set_dialog();
239
240         gtk_widget_show(filtering.window);
241
242         start_address_completion();
243 }
244
245 /* prefs_filtering_close() - just to have one common exit point */
246 static void prefs_filtering_close(void)
247 {
248         end_address_completion();
249         
250         gtk_widget_hide(filtering.window);
251 }
252
253 static void prefs_filtering_create(void)
254 {
255         GtkWidget *window;
256         GtkWidget *vbox;
257         GtkWidget *ok_btn;
258         GtkWidget *cancel_btn;
259         GtkWidget *confirm_area;
260
261         GtkWidget *vbox1;
262         GtkWidget *hbox1;
263         GtkWidget *reg_hbox;
264         GtkWidget *arrow;
265         GtkWidget *btn_hbox;
266
267         GtkWidget *cond_label;
268         GtkWidget *cond_entry;
269         GtkWidget *cond_btn;
270         GtkWidget *action_label;
271         GtkWidget *action_list;
272         GtkWidget *action_combo;
273         GtkWidget *account_label;
274         GtkWidget *account_list;
275         GtkWidget *account_combo;
276         GtkWidget *dest_label;
277         GtkWidget *exec_label;
278         GtkWidget *dest_entry;
279         GtkWidget *dest_btn;
280         GtkWidget *exec_btn;
281         GtkWidget *color_label;
282         GtkWidget *color_optmenu;
283
284         GtkWidget *reg_btn;
285         GtkWidget *subst_btn;
286         GtkWidget *del_btn;
287
288         GtkWidget *cond_hbox;
289         GtkWidget *cond_scrolledwin;
290         GtkWidget *cond_clist;
291
292         GtkWidget *btn_vbox;
293         GtkWidget *up_btn;
294         GtkWidget *down_btn;
295
296         GtkWidget *dummy;
297
298         GList *combo_items;
299         gint i;
300
301         GList *accounts;
302         GList * cur;
303
304         gchar *title[] = {_("Registered rules")};
305
306         debug_print(_("Creating filtering setting window...\n"));
307
308         window = gtk_window_new (GTK_WINDOW_DIALOG);
309         gtk_container_set_border_width (GTK_CONTAINER (window), 8);
310         gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
311         gtk_window_set_modal (GTK_WINDOW (window), TRUE);
312         gtk_window_set_policy (GTK_WINDOW (window), FALSE, TRUE, FALSE);
313
314         vbox = gtk_vbox_new (FALSE, 6);
315         gtk_widget_show (vbox);
316         gtk_container_add (GTK_CONTAINER (window), vbox);
317
318         gtkut_button_set_create(&confirm_area, &ok_btn, _("OK"),
319                                 &cancel_btn, _("Cancel"), NULL, NULL);
320         gtk_widget_show (confirm_area);
321         gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
322         gtk_widget_grab_default (ok_btn);
323
324         gtk_window_set_title (GTK_WINDOW(window),
325                               _("Filtering setting"));
326         gtk_signal_connect (GTK_OBJECT(window), "delete_event",
327                             GTK_SIGNAL_FUNC(prefs_filtering_deleted), NULL);
328         gtk_signal_connect (GTK_OBJECT(window), "key_press_event",
329                             GTK_SIGNAL_FUNC(prefs_filtering_key_pressed), NULL);
330         gtk_signal_connect (GTK_OBJECT(window), "focus_in_event",
331                             GTK_SIGNAL_FUNC(manage_window_focus_in), NULL);
332         gtk_signal_connect (GTK_OBJECT(window), "focus_out_event",
333                             GTK_SIGNAL_FUNC(manage_window_focus_out), NULL);
334         gtk_signal_connect (GTK_OBJECT(ok_btn), "clicked",
335                             GTK_SIGNAL_FUNC(prefs_filtering_ok), NULL);
336         gtk_signal_connect (GTK_OBJECT(cancel_btn), "clicked",
337                             GTK_SIGNAL_FUNC(prefs_filtering_cancel), NULL);
338
339         vbox1 = gtk_vbox_new (FALSE, VSPACING);
340         gtk_widget_show (vbox1);
341         gtk_box_pack_start (GTK_BOX (vbox), vbox1, TRUE, TRUE, 0);
342         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
343
344         cond_label = gtk_label_new (_("Condition"));
345         gtk_widget_show (cond_label);
346         gtk_misc_set_alignment (GTK_MISC (cond_label), 0, 0.5);
347         gtk_box_pack_start (GTK_BOX (vbox1), cond_label, FALSE, FALSE, 0);
348
349         hbox1 = gtk_hbox_new (FALSE, VSPACING);
350         gtk_widget_show (vbox1);
351         gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
352         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
353
354         cond_entry = gtk_entry_new ();
355         gtk_widget_show (cond_entry);
356 //      gtk_widget_set_usize (cond_entry, 200, -1);
357         gtk_box_pack_start (GTK_BOX (hbox1), cond_entry, TRUE, TRUE, 0);
358
359         cond_btn = gtk_button_new_with_label (_("Define ..."));
360         gtk_widget_show (cond_btn);
361         gtk_box_pack_start (GTK_BOX (hbox1), cond_btn, FALSE, FALSE, 0);
362         gtk_signal_connect (GTK_OBJECT (cond_btn), "clicked",
363                             GTK_SIGNAL_FUNC (prefs_filtering_condition_define),
364                             NULL);
365
366         hbox1 = gtk_hbox_new (FALSE, VSPACING);
367         gtk_widget_show (vbox1);
368         gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
369         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
370
371         action_label = gtk_label_new (_("Action"));
372         gtk_widget_show (action_label);
373         gtk_misc_set_alignment (GTK_MISC (action_label), 0, 0.5);
374         gtk_box_pack_start (GTK_BOX (hbox1), action_label, FALSE, FALSE, 0);
375
376         action_combo = gtk_combo_new ();
377         gtk_widget_show (action_combo);
378 //      gtk_widget_set_usize (action_combo, 200, -1);
379         gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(action_combo)->entry),
380                                FALSE);
381
382         combo_items = NULL;
383
384         for(i = 0 ; i < (gint) (sizeof(action_text) / sizeof(gchar *)) ;
385             i++) {
386                 combo_items = g_list_append(combo_items,
387                                             (gpointer) _(action_text[i]));
388         }
389         gtk_combo_set_popdown_strings(GTK_COMBO(action_combo), combo_items);
390
391         g_list_free(combo_items);
392
393         gtk_box_pack_start (GTK_BOX (hbox1), action_combo,
394                             TRUE, TRUE, 0);
395         action_list = GTK_COMBO(action_combo)->list;
396         gtk_signal_connect (GTK_OBJECT (action_list), "select-child",
397                             GTK_SIGNAL_FUNC (prefs_filtering_action_select),
398                             NULL);
399
400         gtk_signal_connect(GTK_OBJECT(action_list), "selection-changed",
401                            GTK_SIGNAL_FUNC(prefs_filtering_action_selection_changed),
402                            NULL);
403
404         /* accounts */
405
406         hbox1 = gtk_hbox_new (FALSE, VSPACING);
407         gtk_widget_show (vbox1);
408         gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
409         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
410
411         account_label = gtk_label_new (_("Account"));
412         gtk_widget_show (account_label);
413         gtk_misc_set_alignment (GTK_MISC (account_label), 0, 0.5);
414         gtk_box_pack_start (GTK_BOX (hbox1), account_label, FALSE, FALSE, 0);
415
416         account_combo = gtk_combo_new ();
417         gtk_widget_show (account_combo);
418
419         combo_items = NULL;
420         for (accounts = account_get_list() ; accounts != NULL;
421              accounts = accounts->next) {
422                 PrefsAccount *ac = (PrefsAccount *)accounts->data;
423                 gchar *name;
424
425                 name = g_strdup_printf("%s <%s> (%s)",
426                                        ac->name, ac->address,
427                                        ac->account_name);
428                 combo_items = g_list_append(combo_items, (gpointer) name);
429         }
430
431         gtk_combo_set_popdown_strings(GTK_COMBO(account_combo), combo_items);
432
433         for(cur = g_list_first(combo_items) ; cur != NULL ;
434             cur = g_list_next(cur))
435                 g_free(cur->data);
436         g_list_free(combo_items);
437
438         gtk_box_pack_start (GTK_BOX (hbox1), account_combo,
439                             TRUE, TRUE, 0);
440         account_list = GTK_COMBO(account_combo)->list;
441         gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(account_combo)->entry),
442                                FALSE);
443
444         /* destination */
445
446         hbox1 = gtk_hbox_new (FALSE, VSPACING);
447         gtk_widget_show (vbox1);
448         gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
449         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
450
451         dest_label = gtk_label_new (_("Destination"));
452         gtk_widget_show (dest_label);
453         gtk_misc_set_alignment (GTK_MISC (dest_label), 0, 0.5);
454         gtk_box_pack_start (GTK_BOX (hbox1), dest_label, FALSE, FALSE, 0);
455
456         exec_label = gtk_label_new (_("Execute"));
457         gtk_widget_show (exec_label);
458         gtk_misc_set_alignment (GTK_MISC (exec_label), 0, 0.5);
459         gtk_box_pack_start (GTK_BOX (hbox1), exec_label, FALSE, FALSE, 0);
460         
461         color_label = gtk_label_new (_("Color"));
462         gtk_widget_show(color_label);
463         gtk_misc_set_alignment(GTK_MISC(color_label), 0, 0.5);
464         gtk_box_pack_start(GTK_BOX(hbox1), color_label, FALSE, FALSE, 0);
465
466         dest_entry = gtk_entry_new ();
467         gtk_widget_show (dest_entry);
468 //      gtk_widget_set_usize (dest_entry, 200, -1);
469         gtk_box_pack_start (GTK_BOX (hbox1), dest_entry, TRUE, TRUE, 0);
470         
471         color_optmenu = gtk_option_menu_new();
472         gtk_option_menu_set_menu(GTK_OPTION_MENU(color_optmenu),
473                                  colorlabel_create_color_menu());
474 //      gtk_widget_set_usize(color_optmenu, -1, -1);
475         gtk_box_pack_start(GTK_BOX(hbox1), color_optmenu, TRUE, TRUE, 0);
476
477         dest_btn = gtk_button_new_with_label (_("Select ..."));
478         gtk_widget_show (dest_btn);
479         gtk_box_pack_start (GTK_BOX (hbox1), dest_btn, FALSE, FALSE, 0);
480         gtk_signal_connect (GTK_OBJECT (dest_btn), "clicked",
481                             GTK_SIGNAL_FUNC (prefs_filtering_select_dest),
482                             NULL);
483
484         exec_btn = gtk_button_new_with_label (_("Info ..."));
485         gtk_widget_show (exec_btn);
486         gtk_box_pack_start (GTK_BOX (hbox1), exec_btn, FALSE, FALSE, 0);
487         gtk_signal_connect (GTK_OBJECT (exec_btn), "clicked",
488                             GTK_SIGNAL_FUNC (prefs_matcher_exec_info),
489                             NULL);
490
491 //      dummy = gtk_label_new("");
492 //      gtk_widget_show (dummy);
493 //      gtk_box_pack_start(GTK_BOX (hbox1), dummy, FALSE, FALSE, 0);
494         
495
496         /* register / substitute / delete */
497
498         reg_hbox = gtk_hbox_new (FALSE, 4);
499         gtk_widget_show (reg_hbox);
500         gtk_box_pack_start (GTK_BOX (vbox1), reg_hbox, FALSE, FALSE, 0);
501
502         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
503         gtk_widget_show (arrow);
504         gtk_box_pack_start (GTK_BOX (reg_hbox), arrow, FALSE, FALSE, 0);
505         gtk_widget_set_usize (arrow, -1, 16);
506
507         btn_hbox = gtk_hbox_new (TRUE, 4);
508         gtk_widget_show (btn_hbox);
509         gtk_box_pack_start (GTK_BOX (reg_hbox), btn_hbox, FALSE, FALSE, 0);
510
511         reg_btn = gtk_button_new_with_label (_("Register"));
512         gtk_widget_show (reg_btn);
513         gtk_box_pack_start (GTK_BOX (btn_hbox), reg_btn, FALSE, TRUE, 0);
514         gtk_signal_connect (GTK_OBJECT (reg_btn), "clicked",
515                             GTK_SIGNAL_FUNC (prefs_filtering_register_cb), NULL);
516
517         subst_btn = gtk_button_new_with_label (_(" Substitute "));
518         gtk_widget_show (subst_btn);
519         gtk_box_pack_start (GTK_BOX (btn_hbox), subst_btn, FALSE, TRUE, 0);
520         gtk_signal_connect (GTK_OBJECT (subst_btn), "clicked",
521                             GTK_SIGNAL_FUNC (prefs_filtering_substitute_cb),
522                             NULL);
523
524         del_btn = gtk_button_new_with_label (_("Delete"));
525         gtk_widget_show (del_btn);
526         gtk_box_pack_start (GTK_BOX (btn_hbox), del_btn, FALSE, TRUE, 0);
527         gtk_signal_connect (GTK_OBJECT (del_btn), "clicked",
528                             GTK_SIGNAL_FUNC (prefs_filtering_delete_cb), NULL);
529
530         cond_hbox = gtk_hbox_new (FALSE, 8);
531         gtk_widget_show (cond_hbox);
532         gtk_box_pack_start (GTK_BOX (vbox1), cond_hbox, TRUE, TRUE, 0);
533
534         cond_scrolledwin = gtk_scrolled_window_new (NULL, NULL);
535         gtk_widget_show (cond_scrolledwin);
536         gtk_widget_set_usize (cond_scrolledwin, -1, 150);
537         gtk_box_pack_start (GTK_BOX (cond_hbox), cond_scrolledwin,
538                             TRUE, TRUE, 0);
539         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (cond_scrolledwin),
540                                         GTK_POLICY_AUTOMATIC,
541                                         GTK_POLICY_AUTOMATIC);
542
543         cond_clist = gtk_clist_new_with_titles(1, title);
544         gtk_widget_show (cond_clist);
545         gtk_container_add (GTK_CONTAINER (cond_scrolledwin), cond_clist);
546         gtk_clist_set_column_width (GTK_CLIST (cond_clist), 0, 80);
547         gtk_clist_set_selection_mode (GTK_CLIST (cond_clist),
548                                       GTK_SELECTION_BROWSE);
549         GTK_WIDGET_UNSET_FLAGS (GTK_CLIST (cond_clist)->column[0].button,
550                                 GTK_CAN_FOCUS);
551         gtk_signal_connect (GTK_OBJECT (cond_clist), "select_row",
552                             GTK_SIGNAL_FUNC (prefs_filtering_select), NULL);
553
554         btn_vbox = gtk_vbox_new (FALSE, 8);
555         gtk_widget_show (btn_vbox);
556         gtk_box_pack_start (GTK_BOX (cond_hbox), btn_vbox, FALSE, FALSE, 0);
557
558         up_btn = gtk_button_new_with_label (_("Up"));
559         gtk_widget_show (up_btn);
560         gtk_box_pack_start (GTK_BOX (btn_vbox), up_btn, FALSE, FALSE, 0);
561         gtk_signal_connect (GTK_OBJECT (up_btn), "clicked",
562                             GTK_SIGNAL_FUNC (prefs_filtering_up), NULL);
563
564         down_btn = gtk_button_new_with_label (_("Down"));
565         gtk_widget_show (down_btn);
566         gtk_box_pack_start (GTK_BOX (btn_vbox), down_btn, FALSE, FALSE, 0);
567         gtk_signal_connect (GTK_OBJECT (down_btn), "clicked",
568                             GTK_SIGNAL_FUNC (prefs_filtering_down), NULL);
569
570         gtk_widget_set_usize(window, 500, -1);
571
572         gtk_widget_show_all(window);
573
574         filtering.window    = window;
575         filtering.ok_btn = ok_btn;
576
577         filtering.cond_entry = cond_entry;
578         filtering.action_list = action_list;
579         filtering.action_combo = action_combo;
580         filtering.account_list = account_list;
581         filtering.account_combo = account_combo;
582         filtering.dest_entry = dest_entry;
583         filtering.dest_btn = dest_btn;
584         filtering.dest_label = dest_label;
585         filtering.exec_label = exec_label;
586         filtering.exec_btn = exec_btn;
587
588         filtering.cond_clist   = cond_clist;
589
590         filtering.color_label   = color_label;
591         filtering.color_optmenu = color_optmenu;
592 }
593
594 static void prefs_filtering_update_hscrollbar(void)
595 {
596         gint optwidth = gtk_clist_optimal_column_width(GTK_CLIST(filtering.cond_clist), 0);
597         gtk_clist_set_column_width(GTK_CLIST(filtering.cond_clist), 0, optwidth);
598 }
599
600 static void prefs_filtering_set_dialog(void)
601 {
602         GtkCList *clist = GTK_CLIST(filtering.cond_clist);
603         GSList *cur;
604         
605         gtk_clist_freeze(clist);
606         gtk_clist_clear(clist);
607
608         prefs_filtering_clist_set_row(-1, NULL);
609         for(cur = prefs_filtering ; cur != NULL ; cur = g_slist_next(cur)) {
610                 FilteringProp * prop = (FilteringProp *) cur->data;
611
612                 prefs_filtering_clist_set_row(-1, prop);
613         }
614
615         prefs_filtering_update_hscrollbar();
616         gtk_clist_thaw(clist);
617
618         prefs_filtering_reset_dialog();
619 }
620
621 static void prefs_filtering_reset_dialog(void)
622 {
623         gtk_list_select_item(GTK_LIST(filtering.action_list), 0);
624         gtk_list_select_item(GTK_LIST(filtering.account_list), 0);
625         gtk_entry_set_text(GTK_ENTRY(filtering.dest_entry), "");
626         gtk_entry_set_text(GTK_ENTRY(filtering.cond_entry), "");
627 }
628
629 static void prefs_filtering_set_list(void)
630 {
631         gint row = 1;
632         FilteringProp *prop;
633         GSList * cur;
634         gchar * filtering_str;
635         gchar * tmp;
636
637         for(cur = prefs_filtering ; cur != NULL ; cur = g_slist_next(cur))
638                 filteringprop_free((FilteringProp *) cur->data);
639         g_slist_free(prefs_filtering);
640         prefs_filtering = NULL;
641
642         while (gtk_clist_get_text(GTK_CLIST(filtering.cond_clist),
643                                   row, 0, &filtering_str)) {
644                 if (strcmp(filtering_str, _("(New)")) != 0) {
645                         tmp = filtering_str;
646                         prop = filteringprop_parse(&tmp);
647                         if (prop != NULL)
648                                 prefs_filtering = g_slist_append(prefs_filtering,
649                                                                prop);
650                 }
651                 row++;
652         }
653 }
654
655 static gint prefs_filtering_clist_set_row(gint row, FilteringProp * prop)
656 {
657         GtkCList *clist = GTK_CLIST(filtering.cond_clist);
658         gchar * str;
659         gchar *cond_str[1];
660
661         if (prop == NULL) {
662                 cond_str[0] = _("(New)");
663                 return gtk_clist_append(clist, cond_str);
664         }
665
666         str = filteringprop_to_string(prop);
667         if (str == NULL) {
668                 return -1;
669         }
670         cond_str[0] = str;
671
672         if (row < 0)
673                 row = gtk_clist_append(clist, cond_str);
674         else
675                 gtk_clist_set_text(clist, row, 0, cond_str[0]);
676         g_free(str);
677
678         return row;
679 }
680
681 static void prefs_filtering_condition_define_done(MatcherList * matchers)
682 {
683         gchar * str;
684
685         if (matchers == NULL)
686                 return;
687
688         str = matcherlist_to_string(matchers);
689
690         if (str != NULL) {
691                 gtk_entry_set_text(GTK_ENTRY(filtering.cond_entry), str);
692                 g_free(str);
693         }
694 }
695
696 static void prefs_filtering_condition_define(void)
697 {
698         gchar * cond_str;
699         MatcherList * matchers = NULL;
700
701         cond_str = gtk_entry_get_text(GTK_ENTRY(filtering.cond_entry));
702
703         if (*cond_str != '\0') {
704                 gchar * tmp;
705                 
706                 tmp = cond_str;
707                 matchers = matcherlist_parse(&tmp);
708                 if (tmp == NULL)
709                         alertpanel_error(_("Match string is not valid."));
710         }
711
712         prefs_matcher_open(matchers, prefs_filtering_condition_define_done);
713
714         if (matchers != NULL)
715                 matcherlist_free(matchers);
716 }
717
718
719 /* register / substitute delete buttons */
720
721
722 static FilteringProp * prefs_filtering_dialog_to_filtering(void)
723 {
724         MatcherList * cond;
725         gchar * cond_str;
726         FilteringProp * prop;
727         FilteringAction * action;
728         gchar * tmp;
729         gint list_id;
730         gint action_id;
731         gint action_type;
732         gint account_id;
733         gchar * destination;
734         gint labelcolor;
735         
736         cond_str = gtk_entry_get_text(GTK_ENTRY(filtering.cond_entry));
737         if (*cond_str == '\0') {
738                 alertpanel_error(_("Score is not set."));
739                 return NULL;
740         }
741
742         action_id = get_sel_from_list(GTK_LIST(filtering.action_list));
743         action_type = prefs_filtering_get_matching_from_action(action_id);
744         list_id = get_sel_from_list(GTK_LIST(filtering.account_list));
745         account_id = get_account_id_from_list_id(list_id);
746
747         switch (action_id) {
748         case ACTION_MOVE:
749         case ACTION_COPY:
750         case ACTION_FORWARD:
751         case ACTION_FORWARD_AS_ATTACHMENT:
752         case ACTION_EXECUTE:
753                 destination = gtk_entry_get_text(GTK_ENTRY(filtering.dest_entry));
754                 if (*destination == '\0') {
755                         alertpanel_error(_("Destination is not set."));
756                         return NULL;
757                 }
758                 break;
759         case ACTION_COLOR:
760                 labelcolor = colorlabel_get_color_menu_active_item(
761                         gtk_option_menu_get_menu(GTK_OPTION_MENU(filtering.color_optmenu)));
762                 destination = NULL;     
763                 break;
764         default:
765                 destination = NULL;
766                 break;
767         }
768         
769         action = filteringaction_new(action_type, account_id, destination, labelcolor);
770
771         tmp = cond_str;
772         cond = matcherlist_parse(&tmp);
773
774         if (tmp == NULL) {
775                 alertpanel_error(_("Match string is not valid."));
776                 filteringaction_free(action);
777                 return NULL;
778         }
779
780         prop = filteringprop_new(cond, action);
781
782         return prop;
783 }
784
785 static void prefs_filtering_register_cb(void)
786 {
787         FilteringProp * prop;
788         
789         prop = prefs_filtering_dialog_to_filtering();
790         if (prop == NULL)
791                 return;
792         prefs_filtering_clist_set_row(-1, prop);
793
794         filteringprop_free(prop);
795         
796         prefs_filtering_update_hscrollbar();
797 }
798
799 static void prefs_filtering_substitute_cb(void)
800 {
801         GtkCList *clist = GTK_CLIST(filtering.cond_clist);
802         gint row;
803         FilteringProp * prop;
804         
805         if (!clist->selection) return;
806
807         row = GPOINTER_TO_INT(clist->selection->data);
808         if (row == 0) return;
809
810         prop = prefs_filtering_dialog_to_filtering();
811         if (prop == NULL)
812                 return;
813         prefs_filtering_clist_set_row(row, prop);
814
815         filteringprop_free(prop);
816         
817         prefs_filtering_update_hscrollbar();
818 }
819
820 static void prefs_filtering_delete_cb(void)
821 {
822         GtkCList *clist = GTK_CLIST(filtering.cond_clist);
823         gint row;
824
825         if (!clist->selection) return;
826         row = GPOINTER_TO_INT(clist->selection->data);
827         if (row == 0) return;
828
829         if (alertpanel(_("Delete rule"),
830                        _("Do you really want to delete this rule?"),
831                        _("Yes"), _("No"), NULL) == G_ALERTALTERNATE)
832                 return;
833
834         gtk_clist_remove(clist, row);
835
836         prefs_filtering_update_hscrollbar();
837 }
838
839 static void prefs_filtering_up(void)
840 {
841         GtkCList *clist = GTK_CLIST(filtering.cond_clist);
842         gint row;
843
844         if (!clist->selection) return;
845
846         row = GPOINTER_TO_INT(clist->selection->data);
847         if (row > 1) {
848                 gtk_clist_row_move(clist, row, row - 1);
849                 if(gtk_clist_row_is_visible(clist, row - 1) != GTK_VISIBILITY_FULL) {
850                         gtk_clist_moveto(clist, row - 1, 0, 0, 0);
851                 } 
852         }
853 }
854
855 static void prefs_filtering_down(void)
856 {
857         GtkCList *clist = GTK_CLIST(filtering.cond_clist);
858         gint row;
859
860         if (!clist->selection) return;
861
862         row = GPOINTER_TO_INT(clist->selection->data);
863         if (row > 0 && row < clist->rows - 1) {
864                 gtk_clist_row_move(clist, row, row + 1);
865                 if(gtk_clist_row_is_visible(clist, row + 1) != GTK_VISIBILITY_FULL) {
866                         gtk_clist_moveto(clist, row + 1, 0, 1, 0);
867                 } 
868         }
869 }
870
871 static void prefs_filtering_select_set(FilteringProp * prop)
872 {
873         FilteringAction * action;
874         gchar * matcher_str;
875         gint list_id;
876
877         prefs_filtering_reset_dialog();
878
879         action = prop->action;
880
881         matcher_str = matcherlist_to_string(prop->matchers);
882         if (matcher_str == NULL) {
883                 filteringprop_free(prop);
884                 return;
885         }
886
887         gtk_entry_set_text(GTK_ENTRY(filtering.cond_entry), matcher_str);
888         
889         if (action->destination)
890                 gtk_entry_set_text(GTK_ENTRY(filtering.dest_entry), action->destination);
891         else
892                 gtk_entry_set_text(GTK_ENTRY(filtering.dest_entry), "");
893
894         switch(action->type) {
895         case MATCHING_ACTION_MOVE:
896                 gtk_list_select_item(GTK_LIST(filtering.action_list),
897                                      ACTION_MOVE);
898                 break;
899         case MATCHING_ACTION_COPY:
900                 gtk_list_select_item(GTK_LIST(filtering.action_list),
901                                      ACTION_COPY);
902                 break;
903         case MATCHING_ACTION_DELETE:
904                 gtk_list_select_item(GTK_LIST(filtering.action_list),
905                                      ACTION_DELETE);
906                 break;
907         case MATCHING_ACTION_MARK:
908                 gtk_list_select_item(GTK_LIST(filtering.action_list),
909                                      ACTION_MARK);
910                 break;
911         case MATCHING_ACTION_UNMARK:
912                 gtk_list_select_item(GTK_LIST(filtering.action_list),
913                                      ACTION_UNMARK);
914                 break;
915         case MATCHING_ACTION_MARK_AS_READ:
916                 gtk_list_select_item(GTK_LIST(filtering.action_list),
917                                      ACTION_MARK_AS_READ);
918                 break;
919         case MATCHING_ACTION_MARK_AS_UNREAD:
920                 gtk_list_select_item(GTK_LIST(filtering.action_list),
921                                      ACTION_MARK_AS_UNREAD);
922                 break;
923         case MATCHING_ACTION_FORWARD:
924                 gtk_list_select_item(GTK_LIST(filtering.action_list),
925                                      ACTION_FORWARD);
926                 list_id = get_list_id_from_account_id(action->account_id);
927                 gtk_list_select_item(GTK_LIST(filtering.account_list),
928                                      list_id);
929                 break;
930         case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
931                 list_id = get_list_id_from_account_id(action->account_id);
932                 gtk_list_select_item(GTK_LIST(filtering.action_list),
933                                      ACTION_FORWARD_AS_ATTACHMENT);
934                 gtk_list_select_item(GTK_LIST(filtering.account_list),
935                                      list_id);
936                 break;
937         case MATCHING_EXECUTE:
938                 gtk_list_select_item(GTK_LIST(filtering.action_list),
939                                      ACTION_EXECUTE);
940                 break;
941         case MATCHING_ACTION_COLOR:
942                 gtk_list_select_item(GTK_LIST(filtering.action_list),
943                                      ACTION_COLOR);
944                 gtk_option_menu_set_history(GTK_OPTION_MENU(filtering.color_optmenu), action->labelcolor);     
945                 break;
946         }
947
948         g_free(matcher_str);
949 }
950
951 static void prefs_filtering_select(GtkCList *clist, gint row, gint column,
952                                 GdkEvent *event)
953 {
954         FilteringProp * prop;
955         gchar * tmp;
956         gchar * filtering_str;
957
958         if (row == 0) {
959                 prefs_filtering_reset_dialog();
960                 return;
961         }
962
963         if (!gtk_clist_get_text(GTK_CLIST(filtering.cond_clist),
964                                 row, 0, &filtering_str))
965                 return;
966         
967         tmp = filtering_str;
968         prop = filteringprop_parse(&tmp);
969         if (tmp == NULL)
970                 return;
971
972         prefs_filtering_select_set(prop);
973
974         filteringprop_free(prop);
975 }
976
977 static void prefs_filtering_select_dest(void)
978 {
979         FolderItem *dest;
980         gchar * path;
981
982         dest = foldersel_folder_sel(NULL, NULL);
983         if (!dest) return;
984
985         path = folder_item_get_identifier(dest);
986
987         gtk_entry_set_text(GTK_ENTRY(filtering.dest_entry), path);
988         g_free(path);
989 }
990
991 static void prefs_filtering_action_selection_changed(GtkList *list,
992                                                      gpointer user_data)
993 {
994         gint value;
995
996         value = get_sel_from_list(GTK_LIST(filtering.action_list));
997
998         if (filtering.current_action != value) {
999                 if (filtering.current_action == ACTION_FORWARD 
1000                 ||  filtering.current_action == ACTION_FORWARD_AS_ATTACHMENT) {
1001                         debug_print("unregistering address completion entry\n");
1002                         address_completion_unregister_entry(GTK_ENTRY(filtering.dest_entry));
1003                 }
1004                 if (value == ACTION_FORWARD || value == ACTION_FORWARD_AS_ATTACHMENT) {
1005                         debug_print("registering address completion entry\n");
1006                         address_completion_register_entry(GTK_ENTRY(filtering.dest_entry));
1007                 }
1008                 filtering.current_action = value;
1009         }
1010 }
1011
1012 static void prefs_filtering_action_select(GtkList *list,
1013                                           GtkWidget *widget,
1014                                           gpointer user_data)
1015 {
1016         gint value;
1017
1018         value = get_sel_from_list(GTK_LIST(filtering.action_list));
1019
1020         switch (value) {
1021         case ACTION_MOVE:
1022                 gtk_widget_set_sensitive(filtering.account_combo, FALSE);
1023                 gtk_widget_show(filtering.dest_entry);
1024                 gtk_widget_set_sensitive(filtering.dest_entry, TRUE);
1025                 gtk_widget_show(filtering.dest_btn);
1026                 gtk_widget_show(filtering.dest_label);
1027                 gtk_widget_hide(filtering.exec_label);
1028                 gtk_widget_hide(filtering.exec_btn);
1029                 gtk_widget_hide(filtering.color_optmenu);
1030                 gtk_widget_hide(filtering.color_label);
1031                 break;
1032         case ACTION_COPY:
1033                 gtk_widget_set_sensitive(filtering.account_combo, FALSE);
1034                 gtk_widget_show(filtering.dest_entry);
1035                 gtk_widget_set_sensitive(filtering.dest_entry, TRUE);
1036                 gtk_widget_show(filtering.dest_btn);
1037                 gtk_widget_show(filtering.dest_label);
1038                 gtk_widget_hide(filtering.exec_label);
1039                 gtk_widget_hide(filtering.exec_btn);
1040                 gtk_widget_hide(filtering.color_optmenu);
1041                 gtk_widget_hide(filtering.color_label);
1042                 break;
1043         case ACTION_DELETE:
1044                 gtk_widget_set_sensitive(filtering.account_combo, FALSE);
1045                 gtk_widget_show(filtering.dest_entry);
1046                 gtk_widget_set_sensitive(filtering.dest_entry, FALSE);
1047                 gtk_widget_hide(filtering.dest_btn);
1048                 gtk_widget_show(filtering.dest_label);
1049                 gtk_widget_hide(filtering.exec_label);
1050                 gtk_widget_hide(filtering.exec_btn);
1051                 gtk_widget_hide(filtering.color_optmenu);
1052                 gtk_widget_hide(filtering.color_label);
1053                 break;
1054         case ACTION_MARK:
1055                 gtk_widget_set_sensitive(filtering.account_combo, FALSE);
1056                 gtk_widget_show(filtering.dest_entry);
1057                 gtk_widget_set_sensitive(filtering.dest_entry, FALSE);
1058                 gtk_widget_hide(filtering.dest_btn);
1059                 gtk_widget_show(filtering.dest_label);
1060                 gtk_widget_hide(filtering.exec_label);
1061                 gtk_widget_hide(filtering.exec_btn);
1062                 gtk_widget_hide(filtering.color_optmenu);
1063                 gtk_widget_hide(filtering.color_label);
1064                 break;
1065         case ACTION_UNMARK:
1066                 gtk_widget_set_sensitive(filtering.account_combo, FALSE);
1067                 gtk_widget_show(filtering.dest_entry);
1068                 gtk_widget_set_sensitive(filtering.dest_entry, FALSE);
1069                 gtk_widget_hide(filtering.dest_btn);
1070                 gtk_widget_show(filtering.dest_label);
1071                 gtk_widget_hide(filtering.exec_label);
1072                 gtk_widget_hide(filtering.exec_btn);
1073                 gtk_widget_hide(filtering.color_optmenu);
1074                 gtk_widget_hide(filtering.color_label);
1075                 break;
1076         case ACTION_MARK_AS_READ:
1077                 gtk_widget_set_sensitive(filtering.account_combo, FALSE);
1078                 gtk_widget_show(filtering.dest_entry);
1079                 gtk_widget_set_sensitive(filtering.dest_entry, FALSE);
1080                 gtk_widget_hide(filtering.dest_btn);
1081                 gtk_widget_show(filtering.dest_label);
1082                 gtk_widget_hide(filtering.exec_label);
1083                 gtk_widget_hide(filtering.exec_btn);
1084                 gtk_widget_hide(filtering.color_optmenu);
1085                 gtk_widget_hide(filtering.color_label);
1086                 break;
1087         case ACTION_MARK_AS_UNREAD:
1088                 gtk_widget_set_sensitive(filtering.account_combo, FALSE);
1089                 gtk_widget_show(filtering.dest_entry);
1090                 gtk_widget_set_sensitive(filtering.dest_entry, FALSE);
1091                 gtk_widget_hide(filtering.dest_btn);
1092                 gtk_widget_show(filtering.dest_label);
1093                 gtk_widget_hide(filtering.exec_label);
1094                 gtk_widget_hide(filtering.exec_btn);
1095                 gtk_widget_hide(filtering.color_optmenu);
1096                 gtk_widget_hide(filtering.color_label);
1097                 break;
1098         case ACTION_FORWARD:
1099                 gtk_widget_set_sensitive(filtering.account_combo, TRUE);
1100                 gtk_widget_show(filtering.dest_entry);
1101                 gtk_widget_set_sensitive(filtering.dest_entry, TRUE);
1102                 gtk_widget_hide(filtering.dest_btn);
1103                 gtk_widget_show(filtering.dest_label);
1104                 gtk_widget_hide(filtering.exec_label);
1105                 gtk_widget_hide(filtering.exec_btn);
1106                 gtk_widget_hide(filtering.color_optmenu);
1107                 gtk_widget_hide(filtering.color_label);
1108                 break;
1109         case ACTION_FORWARD_AS_ATTACHMENT:
1110                 gtk_widget_set_sensitive(filtering.account_combo, TRUE);
1111                 gtk_widget_show(filtering.dest_entry);
1112                 gtk_widget_set_sensitive(filtering.dest_entry, TRUE);
1113                 gtk_widget_hide(filtering.dest_btn);
1114                 gtk_widget_show(filtering.dest_label);
1115                 gtk_widget_hide(filtering.exec_label);
1116                 gtk_widget_hide(filtering.exec_btn);
1117                 gtk_widget_hide(filtering.color_optmenu);
1118                 gtk_widget_hide(filtering.color_label);
1119                 break;
1120         case ACTION_EXECUTE:
1121                 gtk_widget_set_sensitive(filtering.account_combo, FALSE);
1122                 gtk_widget_show(filtering.dest_entry);
1123                 gtk_widget_set_sensitive(filtering.dest_entry, TRUE);
1124                 gtk_widget_hide(filtering.dest_btn);
1125                 gtk_widget_hide(filtering.dest_label);
1126                 gtk_widget_show(filtering.exec_label);
1127                 gtk_widget_set_sensitive(filtering.exec_btn, FALSE);
1128                 gtk_widget_show(filtering.exec_btn);
1129                 gtk_widget_hide(filtering.color_optmenu);
1130                 gtk_widget_hide(filtering.color_label);
1131                 break;
1132         case ACTION_COLOR:
1133                 gtk_widget_set_sensitive(filtering.account_combo, FALSE);
1134                 gtk_widget_hide(filtering.dest_entry);
1135                 gtk_widget_hide(filtering.dest_btn);
1136                 gtk_widget_hide(filtering.dest_label);
1137                 gtk_widget_hide(filtering.exec_label);
1138                 gtk_widget_show(filtering.exec_btn);
1139                 gtk_widget_set_sensitive(filtering.exec_btn, FALSE);
1140                 gtk_widget_show(filtering.color_optmenu);
1141                 gtk_widget_show(filtering.color_label);
1142                 break;
1143         }
1144 }
1145
1146 static gint prefs_filtering_deleted(GtkWidget *widget, GdkEventAny *event,
1147                                  gpointer data)
1148 {
1149         prefs_filtering_cancel();
1150         return TRUE;
1151 }
1152
1153 static void prefs_filtering_key_pressed(GtkWidget *widget, GdkEventKey *event,
1154                                      gpointer data)
1155 {
1156         if (event && event->keyval == GDK_Escape)
1157                 prefs_filtering_cancel();
1158 }
1159
1160 static void prefs_filtering_ok(void)
1161 {
1162         prefs_filtering_set_list();
1163         prefs_filtering_write_config();
1164         prefs_filtering_close();
1165 }
1166
1167 static void prefs_filtering_cancel(void)
1168 {
1169         prefs_filtering_read_config();
1170         prefs_filtering_close();
1171 }