Statistics
| Revision:

root / src / prefs_filter.c @ 3047

History | View | Annotate | Download (23.1 kB)

1 1 hiro
/*
2 1 hiro
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 3014 hiro
 * Copyright (C) 1999-2012 Hiroyuki Yamamoto
4 1 hiro
 *
5 1 hiro
 * This program is free software; you can redistribute it and/or modify
6 1 hiro
 * it under the terms of the GNU General Public License as published by
7 1 hiro
 * the Free Software Foundation; either version 2 of the License, or
8 1 hiro
 * (at your option) any later version.
9 1 hiro
 *
10 1 hiro
 * This program is distributed in the hope that it will be useful,
11 1 hiro
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 1 hiro
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 1 hiro
 * GNU General Public License for more details.
14 1 hiro
 *
15 1 hiro
 * You should have received a copy of the GNU General Public License
16 1 hiro
 * along with this program; if not, write to the Free Software
17 1 hiro
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 1 hiro
 */
19 1 hiro
20 1 hiro
#ifdef HAVE_CONFIG_H
21 1 hiro
#  include "config.h"
22 1 hiro
#endif
23 1 hiro
24 1 hiro
#include "defs.h"
25 1 hiro
26 1 hiro
#include <glib.h>
27 92 hiro
#include <glib/gi18n.h>
28 1 hiro
#include <gtk/gtk.h>
29 1 hiro
#include <gdk/gdkkeysyms.h>
30 1 hiro
#include <stdio.h>
31 1 hiro
#include <stdlib.h>
32 1 hiro
#include <string.h>
33 1 hiro
#include <errno.h>
34 1 hiro
35 1 hiro
#include "main.h"
36 1 hiro
#include "prefs.h"
37 527 hiro
#include "prefs_ui.h"
38 1 hiro
#include "prefs_filter.h"
39 1 hiro
#include "prefs_filter_edit.h"
40 1 hiro
#include "prefs_common.h"
41 1 hiro
#include "mainwindow.h"
42 1 hiro
#include "foldersel.h"
43 1 hiro
#include "manage_window.h"
44 1 hiro
#include "stock_pixmap.h"
45 1 hiro
#include "inc.h"
46 1 hiro
#include "procheader.h"
47 1 hiro
#include "menu.h"
48 1 hiro
#include "filter.h"
49 1 hiro
#include "utils.h"
50 1 hiro
#include "gtkutils.h"
51 1 hiro
#include "alertpanel.h"
52 1 hiro
#include "xml.h"
53 3014 hiro
#include "plugin.h"
54 1 hiro
55 1 hiro
static struct FilterRuleListWindow {
56 1 hiro
        GtkWidget *window;
57 1 hiro
58 195 hiro
        GtkWidget *treeview;
59 195 hiro
        GtkListStore *store;
60 195 hiro
        GtkTreeSelection *selection;
61 1 hiro
62 1 hiro
        GtkWidget *add_btn;
63 1 hiro
        GtkWidget *edit_btn;
64 1 hiro
        GtkWidget *copy_btn;
65 1 hiro
        GtkWidget *del_btn;
66 1 hiro
67 1 hiro
        GSList *default_hdr_list;
68 1 hiro
        GSList *user_hdr_list;
69 1 hiro
        GSList *msg_hdr_list;
70 1 hiro
71 1 hiro
        GHashTable *msg_hdr_table;
72 1 hiro
73 1 hiro
        GtkWidget *close_btn;
74 3018 hiro
75 3018 hiro
        gboolean on_init;
76 3018 hiro
        gboolean modified;
77 1 hiro
} rule_list_window;
78 1 hiro
79 195 hiro
enum {
80 195 hiro
        COL_ENABLED,
81 195 hiro
        COL_NAME,
82 195 hiro
        COL_FILTER_RULE,
83 195 hiro
        N_COLS
84 195 hiro
};
85 1 hiro
86 1 hiro
static void prefs_filter_create                        (void);
87 1 hiro
88 1 hiro
static void prefs_filter_set_dialog                (void);
89 195 hiro
static void prefs_filter_set_list_row                (GtkTreeIter        *iter,
90 1 hiro
                                                 FilterRule        *rule,
91 1 hiro
                                                 gboolean         move_view);
92 1 hiro
93 1 hiro
static void prefs_filter_set_list                (void);
94 1 hiro
95 1 hiro
/* callback functions */
96 1 hiro
static void prefs_filter_add_cb                (void);
97 1 hiro
static void prefs_filter_edit_cb        (void);
98 1 hiro
static void prefs_filter_copy_cb        (void);
99 1 hiro
static void prefs_filter_delete_cb        (void);
100 1 hiro
static void prefs_filter_top                (void);
101 1 hiro
static void prefs_filter_up                (void);
102 1 hiro
static void prefs_filter_down                (void);
103 1 hiro
static void prefs_filter_bottom                (void);
104 1 hiro
105 195 hiro
static gboolean prefs_filter_select        (GtkTreeSelection        *selection,
106 195 hiro
                                         GtkTreeModel                *model,
107 195 hiro
                                         GtkTreePath                *path,
108 195 hiro
                                         gboolean                 cur_selected,
109 195 hiro
                                         gpointer                 data);
110 195 hiro
static void prefs_filter_enable_toggled        (GtkCellRenderer        *cell,
111 195 hiro
                                         gchar                        *path,
112 195 hiro
                                         gpointer                 data);
113 1 hiro
114 195 hiro
static void prefs_filter_row_activated        (GtkTreeView                *treeview,
115 195 hiro
                                         GtkTreePath                *path,
116 195 hiro
                                         GtkTreeViewColumn        *column,
117 195 hiro
                                         gpointer                 data);
118 195 hiro
static void prefs_filter_row_reordered        (GtkTreeModel                *model,
119 195 hiro
                                         GtkTreePath                *path,
120 195 hiro
                                         GtkTreeIter                *iter,
121 195 hiro
                                         gpointer                 data,
122 195 hiro
                                         gpointer                 user_data);
123 195 hiro
124 1 hiro
static gint prefs_filter_deleted        (GtkWidget        *widget,
125 1 hiro
                                         GdkEventAny        *event,
126 1 hiro
                                         gpointer         data);
127 1 hiro
static gboolean prefs_filter_key_pressed(GtkWidget        *widget,
128 1 hiro
                                         GdkEventKey        *event,
129 1 hiro
                                         gpointer         data);
130 1 hiro
static void prefs_filter_close                (void);
131 1 hiro
132 1 hiro
133 2042 hiro
void prefs_filter_open(MsgInfo *msginfo, const gchar *header, const gchar *key)
134 1 hiro
{
135 1 hiro
        inc_lock();
136 1 hiro
137 3018 hiro
        rule_list_window.on_init = TRUE;
138 3018 hiro
139 1 hiro
        if (!rule_list_window.window)
140 1 hiro
                prefs_filter_create();
141 1 hiro
142 1 hiro
        prefs_filter_set_header_list(msginfo);
143 1 hiro
144 1 hiro
        manage_window_set_transient(GTK_WINDOW(rule_list_window.window));
145 1 hiro
        gtk_widget_grab_focus(rule_list_window.close_btn);
146 1 hiro
147 1 hiro
        prefs_filter_set_dialog();
148 1 hiro
149 1 hiro
        gtk_widget_show(rule_list_window.window);
150 660 hiro
        manage_window_focus_in(rule_list_window.window, NULL, NULL);
151 1 hiro
152 3018 hiro
        rule_list_window.modified = FALSE;
153 3018 hiro
154 3014 hiro
        syl_plugin_signal_emit("prefs-filter-open", rule_list_window.window);
155 3014 hiro
156 1 hiro
        if (msginfo) {
157 1 hiro
                FilterRule *rule;
158 1 hiro
159 2042 hiro
                rule = prefs_filter_edit_open(NULL, header, key);
160 730 hiro
                gtk_window_present(GTK_WINDOW(rule_list_window.window));
161 1 hiro
162 1 hiro
                if (rule) {
163 195 hiro
                        prefs_filter_set_list_row(NULL, rule, TRUE);
164 1 hiro
                        prefs_filter_set_list();
165 1 hiro
                }
166 1 hiro
        }
167 3018 hiro
168 3018 hiro
        rule_list_window.on_init = FALSE;
169 1 hiro
}
170 1 hiro
171 1 hiro
static void prefs_filter_create(void)
172 1 hiro
{
173 1 hiro
        GtkWidget *window;
174 1 hiro
        GtkWidget *vbox;
175 1 hiro
        GtkWidget *close_btn;
176 1 hiro
        GtkWidget *confirm_area;
177 1 hiro
178 1 hiro
        GtkWidget *hbox;
179 1 hiro
        GtkWidget *scrolledwin;
180 195 hiro
        GtkWidget *treeview;
181 195 hiro
        GtkListStore *store;
182 195 hiro
        GtkTreeSelection *selection;
183 195 hiro
        GtkTreeViewColumn *column;
184 195 hiro
        GtkCellRenderer *renderer;
185 1 hiro
186 1 hiro
        GtkWidget *btn_vbox;
187 1 hiro
        GtkWidget *spc_vbox;
188 1 hiro
        GtkWidget *top_btn;
189 1 hiro
        GtkWidget *up_btn;
190 1 hiro
        GtkWidget *down_btn;
191 1 hiro
        GtkWidget *bottom_btn;
192 1 hiro
193 1 hiro
        GtkWidget *btn_hbox;
194 1 hiro
        GtkWidget *add_btn;
195 1 hiro
        GtkWidget *edit_btn;
196 1 hiro
        GtkWidget *copy_btn;
197 1 hiro
        GtkWidget *del_btn;
198 2890 hiro
        GtkWidget *image;
199 1 hiro
200 1 hiro
        debug_print("Creating filter setting window...\n");
201 1 hiro
202 1 hiro
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
203 1 hiro
        gtk_container_set_border_width(GTK_CONTAINER(window), 8);
204 11 hiro
        gtk_widget_set_size_request(window, 540, 360);
205 1 hiro
        gtk_window_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
206 1 hiro
        gtk_window_set_modal(GTK_WINDOW(window), TRUE);
207 1 hiro
        gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, FALSE);
208 1 hiro
209 1 hiro
        vbox = gtk_vbox_new(FALSE, 6);
210 1 hiro
        gtk_widget_show(vbox);
211 1 hiro
        gtk_container_add(GTK_CONTAINER(window), vbox);
212 1 hiro
213 30 hiro
        gtkut_stock_button_set_create(&confirm_area,
214 30 hiro
                                      &close_btn, GTK_STOCK_CLOSE,
215 30 hiro
                                      NULL, NULL, NULL, NULL);
216 1 hiro
        gtk_widget_show(confirm_area);
217 1 hiro
        gtk_box_pack_end(GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
218 1 hiro
        gtk_widget_grab_default(close_btn);
219 1 hiro
220 1 hiro
        gtk_window_set_title(GTK_WINDOW(window),
221 1602 hiro
                             _("Filter settings"));
222 1 hiro
        g_signal_connect(G_OBJECT(window), "delete_event",
223 1 hiro
                         G_CALLBACK(prefs_filter_deleted), NULL);
224 1 hiro
        g_signal_connect(G_OBJECT(window), "key_press_event",
225 1 hiro
                         G_CALLBACK(prefs_filter_key_pressed), NULL);
226 1 hiro
        MANAGE_WINDOW_SIGNALS_CONNECT (window);
227 1 hiro
        g_signal_connect(G_OBJECT(close_btn), "clicked",
228 1 hiro
                         G_CALLBACK(prefs_filter_close), NULL);
229 1 hiro
230 1 hiro
        /* Rule list */
231 1 hiro
232 1 hiro
        hbox = gtk_hbox_new(FALSE, 8);
233 1 hiro
        gtk_widget_show(hbox);
234 1 hiro
        gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
235 1 hiro
236 1 hiro
        scrolledwin = gtk_scrolled_window_new(NULL, NULL);
237 1 hiro
        gtk_widget_show(scrolledwin);
238 11 hiro
        gtk_widget_set_size_request(scrolledwin, -1, 150);
239 1 hiro
        gtk_box_pack_start(GTK_BOX(hbox), scrolledwin, TRUE, TRUE, 0);
240 1 hiro
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
241 1 hiro
                                       GTK_POLICY_AUTOMATIC,
242 1 hiro
                                       GTK_POLICY_AUTOMATIC);
243 195 hiro
        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
244 195 hiro
                                            GTK_SHADOW_IN);
245 1 hiro
246 195 hiro
        store = gtk_list_store_new
247 195 hiro
                (N_COLS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER);
248 1 hiro
249 195 hiro
        treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
250 195 hiro
        g_object_unref(G_OBJECT(store));
251 195 hiro
        gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE);
252 195 hiro
        gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
253 195 hiro
        gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), COL_NAME);
254 195 hiro
        gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview), TRUE);
255 195 hiro
256 195 hiro
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
257 195 hiro
        gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
258 195 hiro
        gtk_tree_selection_set_select_function(selection, prefs_filter_select,
259 195 hiro
                                               NULL, NULL);
260 195 hiro
261 195 hiro
        renderer = gtk_cell_renderer_toggle_new();
262 195 hiro
        g_signal_connect(renderer, "toggled",
263 195 hiro
                         G_CALLBACK(prefs_filter_enable_toggled), NULL);
264 195 hiro
        column = gtk_tree_view_column_new_with_attributes
265 195 hiro
                (_("Enabled"), renderer, "active", COL_ENABLED, NULL);
266 195 hiro
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
267 195 hiro
268 195 hiro
        renderer = gtk_cell_renderer_text_new();
269 195 hiro
        column = gtk_tree_view_column_new_with_attributes
270 195 hiro
                (_("Name"), renderer, "text", COL_NAME, NULL);
271 197 hiro
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
272 195 hiro
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
273 195 hiro
274 195 hiro
        gtk_widget_show(treeview);
275 195 hiro
        gtk_container_add(GTK_CONTAINER(scrolledwin), treeview);
276 195 hiro
277 195 hiro
        g_signal_connect(G_OBJECT(treeview), "row-activated",
278 195 hiro
                         G_CALLBACK(prefs_filter_row_activated), NULL);
279 195 hiro
        g_signal_connect_after(G_OBJECT(store), "rows-reordered",
280 195 hiro
                               G_CALLBACK(prefs_filter_row_reordered), NULL);
281 195 hiro
282 1 hiro
        /* Up / Down */
283 1 hiro
284 1 hiro
        btn_vbox = gtk_vbox_new (FALSE, 8);
285 1 hiro
        gtk_widget_show(btn_vbox);
286 1 hiro
        gtk_box_pack_start(GTK_BOX(hbox), btn_vbox, FALSE, FALSE, 0);
287 1 hiro
288 98 hiro
        top_btn = gtk_button_new_from_stock(GTK_STOCK_GOTO_TOP);
289 1 hiro
        gtk_widget_show(top_btn);
290 1 hiro
        gtk_box_pack_start(GTK_BOX(btn_vbox), top_btn, FALSE, FALSE, 0);
291 1 hiro
        g_signal_connect(G_OBJECT(top_btn), "clicked",
292 1 hiro
                         G_CALLBACK(prefs_filter_top), NULL);
293 1 hiro
294 1 hiro
        PACK_VSPACER(btn_vbox, spc_vbox, VSPACING_NARROW_2);
295 1 hiro
296 2890 hiro
        up_btn = gtk_button_new();
297 2890 hiro
        image = gtk_image_new_from_stock(GTK_STOCK_GO_UP, GTK_ICON_SIZE_BUTTON);
298 2890 hiro
        gtk_widget_show(image);
299 2890 hiro
        gtk_button_set_image(GTK_BUTTON(up_btn), image);
300 1 hiro
        gtk_widget_show(up_btn);
301 1 hiro
        gtk_box_pack_start(GTK_BOX(btn_vbox), up_btn, FALSE, FALSE, 0);
302 1 hiro
        g_signal_connect(G_OBJECT(up_btn), "clicked",
303 1 hiro
                         G_CALLBACK(prefs_filter_up), NULL);
304 1 hiro
305 2890 hiro
        down_btn = gtk_button_new();
306 2890 hiro
        image = gtk_image_new_from_stock(GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON);
307 2890 hiro
        gtk_widget_show(image);
308 2890 hiro
        gtk_button_set_image(GTK_BUTTON(down_btn), image);
309 1 hiro
        gtk_widget_show(down_btn);
310 1 hiro
        gtk_box_pack_start(GTK_BOX(btn_vbox), down_btn, FALSE, FALSE, 0);
311 1 hiro
        g_signal_connect(G_OBJECT(down_btn), "clicked",
312 1 hiro
                         G_CALLBACK(prefs_filter_down), NULL);
313 1 hiro
314 1 hiro
        PACK_VSPACER(btn_vbox, spc_vbox, VSPACING_NARROW_2);
315 1 hiro
316 98 hiro
        bottom_btn = gtk_button_new_from_stock(GTK_STOCK_GOTO_BOTTOM);
317 1 hiro
        gtk_widget_show(bottom_btn);
318 1 hiro
        gtk_box_pack_start(GTK_BOX(btn_vbox), bottom_btn, FALSE, FALSE, 0);
319 1 hiro
        g_signal_connect(G_OBJECT(bottom_btn), "clicked",
320 1 hiro
                         G_CALLBACK(prefs_filter_bottom), NULL);
321 1 hiro
322 1 hiro
        /* add / edit / copy / delete */
323 1 hiro
324 1 hiro
        hbox = gtk_hbox_new(FALSE, 4);
325 1 hiro
        gtk_widget_show(hbox);
326 1 hiro
        gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
327 1 hiro
328 1 hiro
        btn_hbox = gtk_hbox_new(TRUE, 4);
329 1 hiro
        gtk_widget_show(btn_hbox);
330 1 hiro
        gtk_box_pack_start(GTK_BOX(hbox), btn_hbox, FALSE, FALSE, 0);
331 1 hiro
332 98 hiro
        add_btn = gtk_button_new_from_stock(GTK_STOCK_ADD);
333 1 hiro
        gtk_widget_show(add_btn);
334 1 hiro
        gtk_box_pack_start(GTK_BOX(btn_hbox), add_btn, FALSE, TRUE, 0);
335 1 hiro
        g_signal_connect(G_OBJECT(add_btn), "clicked",
336 1 hiro
                         G_CALLBACK(prefs_filter_add_cb), NULL);
337 1 hiro
338 319 hiro
#ifdef GTK_STOCK_EDIT
339 319 hiro
        edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);
340 319 hiro
#else
341 1 hiro
        edit_btn = gtk_button_new_with_label(_("Edit"));
342 319 hiro
#endif
343 1 hiro
        gtk_widget_show(edit_btn);
344 1 hiro
        gtk_box_pack_start(GTK_BOX(btn_hbox), edit_btn, FALSE, TRUE, 0);
345 1 hiro
        g_signal_connect(G_OBJECT(edit_btn), "clicked",
346 1 hiro
                         G_CALLBACK(prefs_filter_edit_cb), NULL);
347 1 hiro
348 98 hiro
        copy_btn = gtk_button_new_from_stock(GTK_STOCK_COPY);
349 1 hiro
        gtk_widget_show(copy_btn);
350 1 hiro
        gtk_box_pack_start(GTK_BOX(btn_hbox), copy_btn, FALSE, TRUE, 0);
351 1 hiro
        g_signal_connect(G_OBJECT(copy_btn), "clicked",
352 1 hiro
                         G_CALLBACK(prefs_filter_copy_cb), NULL);
353 1 hiro
354 98 hiro
        del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
355 1 hiro
        gtk_widget_show(del_btn);
356 1 hiro
        gtk_box_pack_start(GTK_BOX(btn_hbox), del_btn, FALSE, TRUE, 0);
357 1 hiro
        g_signal_connect(G_OBJECT(del_btn), "clicked",
358 1 hiro
                         G_CALLBACK(prefs_filter_delete_cb), NULL);
359 1 hiro
360 1 hiro
        gtk_widget_show_all(window);
361 1 hiro
362 1 hiro
        rule_list_window.window = window;
363 1 hiro
        rule_list_window.close_btn = close_btn;
364 1 hiro
365 195 hiro
        rule_list_window.treeview = treeview;
366 195 hiro
        rule_list_window.store = store;
367 195 hiro
        rule_list_window.selection = selection;
368 1 hiro
369 195 hiro
        rule_list_window.add_btn = add_btn;
370 195 hiro
        rule_list_window.edit_btn = edit_btn;
371 195 hiro
        rule_list_window.copy_btn = copy_btn;
372 195 hiro
        rule_list_window.del_btn = del_btn;
373 195 hiro
374 195 hiro
        rule_list_window.default_hdr_list = NULL;
375 195 hiro
        rule_list_window.user_hdr_list = NULL;
376 195 hiro
        rule_list_window.msg_hdr_list = NULL;
377 1 hiro
        rule_list_window.msg_hdr_table = NULL;
378 1 hiro
}
379 1 hiro
380 1 hiro
static void prefs_filter_set_dialog(void)
381 1 hiro
{
382 1 hiro
        GSList *cur;
383 1 hiro
384 195 hiro
        gtk_list_store_clear(rule_list_window.store);
385 1 hiro
386 1 hiro
        for (cur = prefs_common.fltlist; cur != NULL; cur = cur->next) {
387 1 hiro
                FilterRule *rule = (FilterRule *)cur->data;
388 195 hiro
                prefs_filter_set_list_row(NULL, rule, FALSE);
389 1 hiro
        }
390 1 hiro
}
391 1 hiro
392 195 hiro
static void prefs_filter_set_list_row(GtkTreeIter *iter, FilterRule *rule,
393 1 hiro
                                      gboolean move_view)
394 1 hiro
{
395 195 hiro
        GtkListStore *store = rule_list_window.store;
396 195 hiro
        gchar *rule_name;
397 195 hiro
        GtkTreeIter iter_;
398 1 hiro
399 1 hiro
        g_return_if_fail(rule != NULL);
400 1 hiro
401 1 hiro
        if (rule->name && *rule->name)
402 195 hiro
                rule_name = g_strdup(rule->name);
403 195 hiro
        else
404 195 hiro
                rule_name = filter_get_str(rule);
405 1 hiro
406 195 hiro
        if (!iter) {
407 195 hiro
                gtk_list_store_append(store, &iter_);
408 195 hiro
                gtk_list_store_set(store, &iter_,
409 195 hiro
                                   COL_ENABLED, rule->enabled,
410 195 hiro
                                   COL_NAME, rule_name,
411 195 hiro
                                   COL_FILTER_RULE, rule, -1);
412 195 hiro
        } else {
413 195 hiro
                FilterRule *prev_rule = NULL;
414 1 hiro
415 195 hiro
                iter_ = *iter;
416 195 hiro
                gtk_tree_model_get(GTK_TREE_MODEL(store), &iter_,
417 195 hiro
                                   COL_FILTER_RULE, &prev_rule, -1);
418 195 hiro
                if (!prev_rule) {
419 195 hiro
                        g_warning("rule at the row not found\n");
420 195 hiro
                        gtk_list_store_append(store, &iter_);
421 195 hiro
                }
422 195 hiro
423 195 hiro
                gtk_list_store_set(store, &iter_,
424 195 hiro
                                   COL_ENABLED, rule->enabled,
425 195 hiro
                                   COL_NAME, rule_name,
426 195 hiro
                                   COL_FILTER_RULE, rule, -1);
427 195 hiro
428 195 hiro
                if (prev_rule && prev_rule != rule)
429 1 hiro
                        filter_rule_free(prev_rule);
430 1 hiro
        }
431 1 hiro
432 195 hiro
        g_free(rule_name);
433 1 hiro
434 195 hiro
        if (move_view) {
435 195 hiro
                GtkTreePath *path;
436 1 hiro
437 195 hiro
                path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter_);
438 195 hiro
                gtk_tree_view_scroll_to_cell
439 195 hiro
                        (GTK_TREE_VIEW(rule_list_window.treeview),
440 195 hiro
                         path, NULL, TRUE, 0.5, 0.0);
441 195 hiro
                gtk_tree_path_free(path);
442 195 hiro
        }
443 3018 hiro
444 3018 hiro
        rule_list_window.modified = TRUE;
445 1 hiro
}
446 1 hiro
447 1 hiro
#define APPEND_HDR_LIST(hdr_list)                                          \
448 1 hiro
        for (cur = hdr_list; cur != NULL; cur = cur->next) {                  \
449 1 hiro
                header = (Header *)cur->data;                                  \
450 1 hiro
                                                                          \
451 1 hiro
                if (!g_hash_table_lookup(table, header->name)) {          \
452 1 hiro
                        g_hash_table_insert(table, header->name, header); \
453 1532 hiro
                        list = procheader_add_header_list                  \
454 1532 hiro
                                (list, header->name, header->body);          \
455 1 hiro
                }                                                          \
456 1 hiro
        }
457 1 hiro
458 1 hiro
GSList *prefs_filter_get_header_list(void)
459 1 hiro
{
460 1 hiro
        GSList *list = NULL;
461 1 hiro
        GSList *cur;
462 1 hiro
        GHashTable *table;
463 1 hiro
        Header *header;
464 1 hiro
465 1 hiro
        table = g_hash_table_new(str_case_hash, str_case_equal);
466 1 hiro
467 1 hiro
        APPEND_HDR_LIST(rule_list_window.default_hdr_list)
468 1 hiro
        APPEND_HDR_LIST(rule_list_window.user_hdr_list);
469 1 hiro
        APPEND_HDR_LIST(rule_list_window.msg_hdr_list);
470 1 hiro
471 1 hiro
        g_hash_table_destroy(table);
472 1 hiro
473 1 hiro
        return list;
474 1 hiro
}
475 1 hiro
476 1 hiro
#undef APPEND_HDR_LIST
477 1 hiro
478 1 hiro
GSList *prefs_filter_get_user_header_list(void)
479 1 hiro
{
480 1 hiro
        return rule_list_window.user_hdr_list;
481 1 hiro
}
482 1 hiro
483 1 hiro
gchar *prefs_filter_get_msg_header_field(const gchar *header_name)
484 1 hiro
{
485 1 hiro
        if (!rule_list_window.msg_hdr_table)
486 1 hiro
                return NULL;
487 1 hiro
488 1 hiro
        return (gchar *)g_hash_table_lookup
489 1 hiro
                (rule_list_window.msg_hdr_table, header_name);
490 1 hiro
}
491 1 hiro
492 1 hiro
void prefs_filter_set_user_header_list(GSList *list)
493 1 hiro
{
494 1 hiro
        procheader_header_list_destroy(rule_list_window.user_hdr_list);
495 1 hiro
        rule_list_window.user_hdr_list = list;
496 1 hiro
}
497 1 hiro
498 1 hiro
void prefs_filter_set_msg_header_list(MsgInfo *msginfo)
499 1 hiro
{
500 1 hiro
        gchar *file;
501 1 hiro
        GSList *cur;
502 1 hiro
        GSList *next;
503 1 hiro
        Header *header;
504 1 hiro
505 1 hiro
        if (rule_list_window.msg_hdr_table) {
506 1 hiro
                g_hash_table_destroy(rule_list_window.msg_hdr_table);
507 1 hiro
                rule_list_window.msg_hdr_table = NULL;
508 1 hiro
        }
509 1 hiro
        if (rule_list_window.msg_hdr_list) {
510 1 hiro
                procheader_header_list_destroy(rule_list_window.msg_hdr_list);
511 1 hiro
                rule_list_window.msg_hdr_list = NULL;
512 1 hiro
        }
513 1 hiro
514 1 hiro
        if (!msginfo)
515 1 hiro
                return;
516 1 hiro
517 1 hiro
        file = procmsg_get_message_file(msginfo);
518 1 hiro
        g_return_if_fail(file != NULL);
519 1 hiro
520 1 hiro
        rule_list_window.msg_hdr_list =
521 1 hiro
                procheader_get_header_list_from_file(file);
522 1 hiro
523 1 hiro
        g_free(file);
524 1 hiro
525 1 hiro
        rule_list_window.msg_hdr_table =
526 1 hiro
                g_hash_table_new(str_case_hash, str_case_equal);
527 1 hiro
528 1 hiro
        for (cur = rule_list_window.msg_hdr_list; cur != NULL;
529 1 hiro
             cur = next) {
530 1 hiro
                next = cur->next;
531 1 hiro
                header = (Header *)cur->data;
532 333 hiro
                if (!g_ascii_strcasecmp(header->name, "Received") ||
533 333 hiro
                    !g_ascii_strcasecmp(header->name, "Mime-Version") ||
534 333 hiro
                    !g_ascii_strcasecmp(header->name, "X-UIDL")) {
535 1 hiro
                        procheader_header_free(header);
536 1 hiro
                        rule_list_window.msg_hdr_list =
537 1 hiro
                                g_slist_remove(rule_list_window.msg_hdr_list,
538 1 hiro
                                               header);
539 1 hiro
                        continue;
540 1 hiro
                }
541 1 hiro
                if (!g_hash_table_lookup(rule_list_window.msg_hdr_table,
542 1 hiro
                                         header->name)) {
543 1 hiro
                        g_hash_table_insert(rule_list_window.msg_hdr_table,
544 1 hiro
                                            header->name, header->body);
545 1 hiro
                }
546 1 hiro
        }
547 1 hiro
}
548 1 hiro
549 811 hiro
void prefs_filter_set_header_list(MsgInfo *msginfo)
550 1 hiro
{
551 1 hiro
        GSList *list = NULL;
552 1 hiro
        gchar *path;
553 1 hiro
        FILE *fp;
554 1 hiro
555 1 hiro
        list = procheader_add_header_list(list, "From", NULL);
556 1 hiro
        list = procheader_add_header_list(list, "To", NULL);
557 1 hiro
        list = procheader_add_header_list(list, "Cc", NULL);
558 1 hiro
        list = procheader_add_header_list(list, "Subject", NULL);
559 1 hiro
        list = procheader_add_header_list(list, "Reply-To", NULL);
560 1 hiro
        list = procheader_add_header_list(list, "List-Id", NULL);
561 1 hiro
        list = procheader_add_header_list(list, "X-ML-Name", NULL);
562 1 hiro
563 1 hiro
        procheader_header_list_destroy(rule_list_window.default_hdr_list);
564 1 hiro
        rule_list_window.default_hdr_list = list;
565 1 hiro
566 1 hiro
        list = NULL;
567 1 hiro
        path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_HEADER_RC,
568 1 hiro
                           NULL);
569 478 hiro
        if ((fp = g_fopen(path, "rb")) != NULL) {
570 1 hiro
                gchar buf[PREFSBUFSIZE];
571 1 hiro
572 1 hiro
                while (fgets(buf, sizeof(buf), fp) != NULL) {
573 1 hiro
                        g_strstrip(buf);
574 1 hiro
                        if (buf[0] == '\0') continue;
575 1 hiro
                        list = procheader_add_header_list(list, buf, NULL);
576 1 hiro
                }
577 1 hiro
578 1 hiro
                fclose(fp);
579 1 hiro
        } else
580 1 hiro
                if (ENOENT != errno) FILE_OP_ERROR(path, "fopen");
581 1 hiro
        g_free(path);
582 1 hiro
583 1 hiro
        prefs_filter_set_user_header_list(list);
584 1 hiro
        prefs_filter_set_msg_header_list(msginfo);
585 1 hiro
}
586 1 hiro
587 1532 hiro
void prefs_filter_write_user_header_list(void)
588 1 hiro
{
589 1 hiro
        gchar *path;
590 1 hiro
        PrefFile *pfile;
591 1 hiro
        GSList *cur;
592 1 hiro
593 1 hiro
        path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_HEADER_RC,
594 1 hiro
                           NULL);
595 1 hiro
596 1 hiro
        if ((pfile = prefs_file_open(path)) == NULL) {
597 1 hiro
                g_warning("failed to write filter user header list\n");
598 1 hiro
                g_free(path);
599 1 hiro
                return;
600 1 hiro
        }
601 1 hiro
        g_free(path);
602 1 hiro
603 1 hiro
        for (cur = rule_list_window.user_hdr_list; cur != NULL;
604 1 hiro
             cur = cur->next) {
605 1 hiro
                Header *header = (Header *)cur->data;
606 1 hiro
                fputs(header->name, pfile->fp);
607 1 hiro
                fputc('\n', pfile->fp);
608 1 hiro
        }
609 1 hiro
610 1 hiro
        if (prefs_file_close(pfile) < 0)
611 1 hiro
                g_warning("failed to write filter user header list\n");
612 1 hiro
}
613 1 hiro
614 1 hiro
static void prefs_filter_set_list(void)
615 1 hiro
{
616 1 hiro
        FilterRule *rule;
617 195 hiro
        GtkTreeIter iter;
618 195 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(rule_list_window.store);
619 1 hiro
620 1 hiro
        g_slist_free(prefs_common.fltlist);
621 1 hiro
        prefs_common.fltlist = NULL;
622 1 hiro
623 195 hiro
        if (!gtk_tree_model_get_iter_first(model, &iter))
624 195 hiro
                return;
625 195 hiro
626 195 hiro
        do {
627 195 hiro
                gtk_tree_model_get(model, &iter, COL_FILTER_RULE, &rule, -1);
628 195 hiro
                if (rule)
629 195 hiro
                        prefs_common.fltlist =
630 195 hiro
                                g_slist_append(prefs_common.fltlist, rule);
631 195 hiro
        } while (gtk_tree_model_iter_next(model, &iter));
632 1 hiro
}
633 1 hiro
634 1 hiro
static void prefs_filter_add_cb(void)
635 1 hiro
{
636 1 hiro
        FilterRule *rule;
637 1 hiro
638 2042 hiro
        rule = prefs_filter_edit_open(NULL, NULL, NULL);
639 730 hiro
        gtk_window_present(GTK_WINDOW(rule_list_window.window));
640 1 hiro
641 1 hiro
        if (rule) {
642 195 hiro
                prefs_filter_set_list_row(NULL, rule, TRUE);
643 1 hiro
                prefs_filter_set_list();
644 1 hiro
        }
645 1 hiro
}
646 1 hiro
647 1 hiro
static void prefs_filter_edit_cb(void)
648 1 hiro
{
649 195 hiro
        GtkTreeIter iter;
650 1 hiro
        FilterRule *rule, *new_rule;
651 1 hiro
652 195 hiro
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
653 195 hiro
                                             NULL, &iter))
654 195 hiro
                return;
655 1 hiro
656 195 hiro
        gtk_tree_model_get(GTK_TREE_MODEL(rule_list_window.store), &iter,
657 195 hiro
                           COL_FILTER_RULE, &rule, -1);
658 1 hiro
        g_return_if_fail(rule != NULL);
659 1 hiro
660 2042 hiro
        new_rule = prefs_filter_edit_open(rule, NULL, NULL);
661 730 hiro
        gtk_window_present(GTK_WINDOW(rule_list_window.window));
662 1 hiro
663 1 hiro
        if (new_rule) {
664 195 hiro
                prefs_filter_set_list_row(&iter, new_rule, TRUE);
665 1 hiro
                prefs_filter_set_list();
666 1 hiro
        }
667 1 hiro
}
668 1 hiro
669 1 hiro
static void prefs_filter_copy_cb(void)
670 1 hiro
{
671 195 hiro
        GtkTreeIter iter;
672 1 hiro
        FilterRule *rule, *new_rule;
673 1 hiro
674 195 hiro
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
675 195 hiro
                                             NULL, &iter))
676 195 hiro
                return;
677 1 hiro
678 195 hiro
        gtk_tree_model_get(GTK_TREE_MODEL(rule_list_window.store), &iter,
679 195 hiro
                           COL_FILTER_RULE, &rule, -1);
680 1 hiro
        g_return_if_fail(rule != NULL);
681 1 hiro
682 2042 hiro
        new_rule = prefs_filter_edit_open(rule, NULL, NULL);
683 730 hiro
        gtk_window_present(GTK_WINDOW(rule_list_window.window));
684 1 hiro
685 1 hiro
        if (new_rule) {
686 195 hiro
                prefs_filter_set_list_row(NULL, new_rule, TRUE);
687 1 hiro
                prefs_filter_set_list();
688 1 hiro
        }
689 1 hiro
}
690 1 hiro
691 1 hiro
static void prefs_filter_delete_cb(void)
692 1 hiro
{
693 195 hiro
        GtkTreeIter iter;
694 1 hiro
        FilterRule *rule;
695 195 hiro
        gchar buf[BUFFSIZE];
696 195 hiro
        gboolean valid;
697 1 hiro
698 195 hiro
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
699 195 hiro
                                             NULL, &iter))
700 195 hiro
                return;
701 1 hiro
702 195 hiro
        gtk_tree_model_get(GTK_TREE_MODEL(rule_list_window.store), &iter,
703 195 hiro
                           COL_FILTER_RULE, &rule, -1);
704 195 hiro
        g_return_if_fail(rule != NULL);
705 195 hiro
706 195 hiro
        g_snprintf(buf, sizeof(buf),
707 195 hiro
                   _("Do you really want to delete the rule '%s'?"),
708 195 hiro
                   rule->name ? rule->name : _("(Untitled)"));
709 195 hiro
        if (alertpanel(_("Delete rule"), buf,
710 47 hiro
                       GTK_STOCK_YES, GTK_STOCK_NO, NULL) != G_ALERTDEFAULT)
711 1 hiro
                return;
712 1 hiro
713 195 hiro
        valid = gtk_list_store_remove(rule_list_window.store, &iter);
714 195 hiro
        if (valid)
715 195 hiro
                gtk_tree_selection_select_iter(rule_list_window.selection,
716 195 hiro
                                               &iter);
717 195 hiro
718 195 hiro
        prefs_common.fltlist = g_slist_remove(prefs_common.fltlist, rule);
719 1 hiro
        filter_rule_free(rule);
720 3018 hiro
721 3018 hiro
        rule_list_window.modified = TRUE;
722 1 hiro
}
723 1 hiro
724 1 hiro
static void prefs_filter_top(void)
725 1 hiro
{
726 195 hiro
        GtkTreeIter iter;
727 1 hiro
728 195 hiro
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
729 195 hiro
                                             NULL, &iter))
730 195 hiro
                return;
731 1 hiro
732 195 hiro
        gtk_list_store_move_after(rule_list_window.store, &iter, NULL);
733 1 hiro
}
734 1 hiro
735 1 hiro
static void prefs_filter_up(void)
736 1 hiro
{
737 195 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(rule_list_window.store);
738 195 hiro
        GtkTreeIter iter, prev;
739 195 hiro
        GtkTreePath *path;
740 1 hiro
741 195 hiro
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
742 195 hiro
                                             NULL, &iter))
743 195 hiro
                return;
744 1 hiro
745 195 hiro
        path = gtk_tree_model_get_path(model, &iter);
746 195 hiro
        if (gtk_tree_path_prev(path)) {
747 195 hiro
                gtk_tree_model_get_iter(model, &prev, path);
748 195 hiro
                gtk_list_store_swap(rule_list_window.store, &iter, &prev);
749 195 hiro
        }
750 195 hiro
        gtk_tree_path_free(path);
751 1 hiro
}
752 1 hiro
753 1 hiro
static void prefs_filter_down(void)
754 1 hiro
{
755 195 hiro
        GtkTreeIter iter, next;
756 1 hiro
757 195 hiro
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
758 195 hiro
                                             NULL, &iter))
759 195 hiro
                return;
760 1 hiro
761 195 hiro
        next = iter;
762 195 hiro
        if (gtk_tree_model_iter_next(GTK_TREE_MODEL(rule_list_window.store),
763 195 hiro
                                     &next))
764 195 hiro
                gtk_list_store_swap(rule_list_window.store, &iter, &next);
765 1 hiro
}
766 1 hiro
767 1 hiro
static void prefs_filter_bottom(void)
768 1 hiro
{
769 195 hiro
        GtkTreeIter iter;
770 1 hiro
771 195 hiro
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
772 195 hiro
                                             NULL, &iter))
773 195 hiro
                return;
774 1 hiro
775 195 hiro
        gtk_list_store_move_before(rule_list_window.store, &iter, NULL);
776 1 hiro
}
777 1 hiro
778 195 hiro
static gboolean prefs_filter_select(GtkTreeSelection *selection,
779 195 hiro
                                    GtkTreeModel *model, GtkTreePath *path,
780 195 hiro
                                    gboolean cur_selected, gpointer data)
781 1 hiro
{
782 195 hiro
        return TRUE;
783 195 hiro
}
784 1 hiro
785 195 hiro
static void prefs_filter_enable_toggled(GtkCellRenderer *cell, gchar *path_str,
786 195 hiro
                                        gpointer data)
787 195 hiro
{
788 195 hiro
        FilterRule *rule;
789 195 hiro
        GtkTreeIter iter;
790 195 hiro
        GtkTreePath *path;
791 195 hiro
792 195 hiro
        path = gtk_tree_path_new_from_string(path_str);
793 195 hiro
        gtk_tree_model_get_iter(GTK_TREE_MODEL(rule_list_window.store),
794 195 hiro
                                &iter, path);
795 195 hiro
        gtk_tree_path_free(path);
796 195 hiro
        gtk_tree_model_get(GTK_TREE_MODEL(rule_list_window.store), &iter,
797 195 hiro
                           COL_FILTER_RULE, &rule, -1);
798 195 hiro
799 195 hiro
        rule->enabled ^= TRUE;
800 195 hiro
801 195 hiro
        gtk_list_store_set(rule_list_window.store, &iter,
802 195 hiro
                           COL_ENABLED, rule->enabled, -1);
803 3018 hiro
        rule_list_window.modified = TRUE;
804 1 hiro
}
805 1 hiro
806 195 hiro
static void prefs_filter_row_activated(GtkTreeView *treeview, GtkTreePath *path,
807 195 hiro
                                       GtkTreeViewColumn *column,
808 195 hiro
                                       gpointer data)
809 1 hiro
{
810 195 hiro
        gtk_button_clicked(GTK_BUTTON(rule_list_window.edit_btn));
811 1 hiro
}
812 1 hiro
813 195 hiro
static void prefs_filter_row_reordered(GtkTreeModel *model,
814 195 hiro
                                       GtkTreePath *path, GtkTreeIter *iter,
815 195 hiro
                                       gpointer data, gpointer user_data)
816 195 hiro
{
817 195 hiro
        GtkTreeIter iter_;
818 195 hiro
        GtkTreePath *path_;
819 195 hiro
820 195 hiro
        if (!gtk_tree_selection_get_selected(rule_list_window.selection,
821 195 hiro
                                             NULL, &iter_))
822 195 hiro
                return;
823 195 hiro
        path_ = gtk_tree_model_get_path
824 195 hiro
                (GTK_TREE_MODEL(rule_list_window.store), &iter_);
825 195 hiro
        gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(rule_list_window.treeview),
826 195 hiro
                                     path_, NULL, FALSE, 0.0, 0.0);
827 195 hiro
        gtk_tree_path_free(path_);
828 3018 hiro
        rule_list_window.modified = TRUE;
829 195 hiro
}
830 195 hiro
831 1 hiro
static gint prefs_filter_deleted(GtkWidget *widget, GdkEventAny *event,
832 1 hiro
                                 gpointer data)
833 1 hiro
{
834 1 hiro
        prefs_filter_close();
835 1 hiro
        return TRUE;
836 1 hiro
}
837 1 hiro
838 1 hiro
static gboolean prefs_filter_key_pressed(GtkWidget *widget, GdkEventKey *event,
839 1 hiro
                                         gpointer data)
840 1 hiro
{
841 3018 hiro
        if (rule_list_window.on_init)
842 3018 hiro
                return TRUE;
843 3018 hiro
844 1 hiro
        if (event && event->keyval == GDK_Escape)
845 1 hiro
                prefs_filter_close();
846 1 hiro
        return FALSE;
847 1 hiro
}
848 1 hiro
849 1 hiro
static void prefs_filter_close(void)
850 1 hiro
{
851 3018 hiro
        if (rule_list_window.on_init)
852 3018 hiro
                return;
853 3018 hiro
854 1 hiro
        prefs_filter_set_msg_header_list(NULL);
855 3018 hiro
        if (rule_list_window.modified) {
856 3018 hiro
                prefs_filter_set_list();
857 3018 hiro
                filter_write_config();
858 3018 hiro
        }
859 1 hiro
        gtk_widget_hide(rule_list_window.window);
860 195 hiro
        gtk_list_store_clear(rule_list_window.store);
861 703 hiro
        main_window_popup(main_window_get());
862 1 hiro
        inc_unlock();
863 1 hiro
}