diff options
Diffstat (limited to 'src/prefs_filter.c')
| -rw-r--r-- | src/prefs_filter.c | 875 |
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 | |||
| 55 | static 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 | |||
| 79 | enum { | ||
| 80 | COL_ENABLED, | ||
| 81 | COL_NAME, | ||
| 82 | COL_FILTER_RULE, | ||
| 83 | N_COLS | ||
| 84 | }; | ||
| 85 | |||
| 86 | static void prefs_filter_create (void); | ||
| 87 | |||
| 88 | static void prefs_filter_set_dialog (void); | ||
| 89 | static void prefs_filter_set_list_row (GtkTreeIter *iter, | ||
| 90 | FilterRule *rule, | ||
| 91 | gboolean move_view); | ||
| 92 | |||
| 93 | static void prefs_filter_set_list (void); | ||
| 94 | |||
| 95 | /* callback functions */ | ||
| 96 | static void prefs_filter_add_cb (void); | ||
| 97 | static void prefs_filter_edit_cb (void); | ||
| 98 | static void prefs_filter_copy_cb (void); | ||
| 99 | static void prefs_filter_delete_cb (void); | ||
| 100 | static void prefs_filter_top (void); | ||
| 101 | static void prefs_filter_up (void); | ||
| 102 | static void prefs_filter_down (void); | ||
| 103 | static void prefs_filter_bottom (void); | ||
| 104 | |||
| 105 | static gboolean prefs_filter_select (GtkTreeSelection *selection, | ||
| 106 | GtkTreeModel *model, | ||
| 107 | GtkTreePath *path, | ||
| 108 | gboolean cur_selected, | ||
| 109 | gpointer data); | ||
| 110 | static void prefs_filter_enable_toggled (GtkCellRenderer *cell, | ||
| 111 | gchar *path, | ||
| 112 | gpointer data); | ||
| 113 | |||
| 114 | static void prefs_filter_row_activated (GtkTreeView *treeview, | ||
| 115 | GtkTreePath *path, | ||
| 116 | GtkTreeViewColumn *column, | ||
| 117 | gpointer data); | ||
| 118 | static void prefs_filter_row_reordered (GtkTreeModel *model, | ||
| 119 | GtkTreePath *path, | ||
| 120 | GtkTreeIter *iter, | ||
| 121 | gpointer data, | ||
| 122 | gpointer user_data); | ||
| 123 | static void prefs_filter_row_inserted (GtkTreeModel *model, | ||
| 124 | GtkTreePath *path, | ||
| 125 | GtkTreeIter *iter, | ||
| 126 | gpointer user_data); | ||
| 127 | |||
| 128 | static gint prefs_filter_deleted (GtkWidget *widget, | ||
| 129 | GdkEventAny *event, | ||
| 130 | gpointer data); | ||
| 131 | static gboolean prefs_filter_key_pressed(GtkWidget *widget, | ||
| 132 | GdkEventKey *event, | ||
| 133 | gpointer data); | ||
| 134 | static void prefs_filter_close (void); | ||
| 135 | |||
| 136 | |||
| 137 | void 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 | |||
| 175 | static 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 | |||
| 386 | static 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 | |||
| 398 | static 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 | |||
| 464 | GSList *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 | |||
| 484 | GSList *prefs_filter_get_user_header_list(void) | ||
| 485 | { | ||
| 486 | return rule_list_window.user_hdr_list; | ||
| 487 | } | ||
| 488 | |||
| 489 | gchar *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 | |||
| 498 | void 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 | |||
| 504 | void 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 | |||
| 555 | void 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 | |||
| 593 | void 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 | |||
| 620 | static 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 | |||
| 640 | static 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 | |||
| 653 | static 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 | |||
| 675 | static 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 | |||
| 697 | static 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 | |||
| 730 | static 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 | |||
| 741 | static 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 | |||
| 759 | static 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 | |||
| 773 | static 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 | |||
| 784 | static gboolean prefs_filter_select(GtkTreeSelection *selection, | ||
| 785 | GtkTreeModel *model, GtkTreePath *path, | ||
| 786 | gboolean cur_selected, gpointer data) | ||
| 787 | { | ||
| 788 | return TRUE; | ||
| 789 | } | ||
| 790 | |||
| 791 | static 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 | |||
| 812 | static 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 | |||
| 819 | static 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 | |||
| 837 | static void prefs_filter_row_inserted(GtkTreeModel *model, GtkTreePath *path, | ||
| 838 | GtkTreeIter *iter, gpointer user_data) | ||
| 839 | { | ||
| 840 | rule_list_window.modified = TRUE; | ||
| 841 | } | ||
| 842 | |||
| 843 | static gint prefs_filter_deleted(GtkWidget *widget, GdkEventAny *event, | ||
| 844 | gpointer data) | ||
| 845 | { | ||
| 846 | prefs_filter_close(); | ||
| 847 | return TRUE; | ||
| 848 | } | ||
| 849 | |||
| 850 | static 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 | |||
| 861 | static 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 | } | ||
