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