From 7cf30eb79276d4f255c1d603e2c203bb054cf50e Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Thu, 17 Aug 2000 17:42:21 +0000 Subject: Filtering on demand! booyeah! svn path=/trunk/; revision=4864 --- filter/ChangeLog | 42 +++++++++++++++++++++++ filter/filter-driver.c | 22 +++++++++--- filter/filter-driver.h | 1 + filter/filter-editor.c | 79 ++++++++++++++++++++++++++++++++----------- filter/filter-rule.c | 31 +++++++++++++++++ filter/filter-rule.h | 8 +++++ filter/filter.glade | 3 +- filter/rule-context.c | 35 ++++++++++++++++--- filter/rule-context.h | 9 +++-- mail/ChangeLog | 53 +++++++++++++++++++++++++++++ mail/folder-browser-factory.c | 61 ++++++++++++++++++++++++++++++++- mail/folder-browser.c | 19 +++++++++++ mail/folder-browser.h | 15 +++++--- mail/mail-autofilter.c | 2 +- mail/mail-callbacks.c | 19 ++++++++++- mail/mail-tools.c | 10 +++--- mail/mail-tools.h | 6 ++++ mail/mail-vfolder.c | 2 +- mail/mail.h | 2 ++ mail/message-list.c | 20 +++++++++++ 20 files changed, 394 insertions(+), 45 deletions(-) diff --git a/filter/ChangeLog b/filter/ChangeLog index 70950b51be..fff445dcf6 100644 --- a/filter/ChangeLog +++ b/filter/ChangeLog @@ -1,3 +1,45 @@ +2000-08-17 Peter Williams + + Implement filtering on demand. + + * rule-context.h: Add a new callback to rule_context_load + that allows the caller to hook on-demand rules into its UI. + + * rule-context.c (rule_context_load): Changed to pass the + extra parameters to load(). + (load): If the rule is successfully loaded, call the provided + callback so that the UI can be updated. + + * filter-editor.c (rule_add): Set the source of the new filter. + (rule_edit): Use the new rule_context_get_rank_rule_with_source() + so that we don't get a bad index into the GtkList. + (rule_delete): Same as above. + (rule_up): Same as above. + (rule_down): Same as above. + (select_source): New function. When the user changes the + dropdown list to select a new source type, repopulate the + list with rules of the appropriate type. + (filter_editor_construct): Code moved from here into + select_source(). Hook up all the elements of the source optionmenu + to callbacks to select_source(). + + * filter-rule.c (xml_encode): Save the rule's source type. + (xml_decode): Load it. Default to 'incoming' if unspecified. + + * filter-rule.h: New enumeration, _filter_source_t, the + specifies the rule's source. Add it to struct _FilterRule. + + * filter-driver.c (filter_driver_run): Add a new input, + sourcetype, that specifies which rules to run (only ones + with the same source will be run). struct filter_mail_input_t + changed to accomodate. + (do_filter_mail): Skip rules if they're not the specified source. + If source and dest are the same, don't delete the messages or + copy unnecessarily. + + * filter.glade: Make the optionmenu sensitive. Change "Outgoing" + to "On Demand" (outgoing should be added later). + 2000-08-15 Peter Williams * vfoldertype.xml, filtertypes.xml: Add entries defining the diff --git a/filter/filter-driver.c b/filter/filter-driver.c index e22fc7235b..e3e1c7df5e 100644 --- a/filter/filter-driver.c +++ b/filter/filter-driver.c @@ -37,11 +37,14 @@ #include "filter-filter.h" #include "e-util/e-sexp.h" +#define d(x) + /* mail-thread filter input data type */ typedef struct { FilterDriver *driver; CamelFolder *source; CamelFolder *inbox; + enum _filter_source_t sourcetype; gboolean self_destruct; gpointer unhook_func; gpointer unhook_data; @@ -414,6 +417,7 @@ static const mail_operation_spec op_filter_mail = void filter_driver_run (FilterDriver *d, CamelFolder *source, CamelFolder *inbox, + enum _filter_source_t sourcetype, gboolean self_destruct, gpointer unhook_func, gpointer unhook_data) { filter_mail_input_t *input; @@ -422,6 +426,7 @@ filter_driver_run (FilterDriver *d, CamelFolder *source, CamelFolder *inbox, input->driver = d; input->source = source; input->inbox = inbox; + input->sourcetype = sourcetype; input->self_destruct = self_destruct; input->unhook_func = unhook_func; input->unhook_data = unhook_data; @@ -502,15 +507,20 @@ do_filter_mail (gpointer in_data, gpointer op_data, CamelException *ex) rule = NULL; while ( (rule = (FilterFilter *)rule_context_next_rule((RuleContext *)p->context, (FilterRule *)rule)) ) { + + if (((FilterRule *)rule)->source != input->sourcetype) { + d(printf("skipping rule %s - wrong source type (%d %d)\n", ((FilterRule *)rule)->name, + ((FilterRule *)rule)->source, input->sourcetype)); + continue; + } + g_string_truncate(s, 0); g_string_truncate(a, 0); filter_rule_build_code((FilterRule *)rule, s); filter_filter_build_action(rule, a); -#if 0 - printf("applying rule %s\n action %s\n", s->str, a->str); -#endif + d(printf("applying rule %s\n action %s\n", s->str, a->str)); mail_tool_camel_lock_up (); p->matches = camel_folder_search_by_expression (p->source, s->str, p->ex); @@ -574,14 +584,16 @@ do_filter_mail (gpointer in_data, gpointer op_data, CamelException *ex) copies = tmp; } - if (!procuid) { + if (!procuid && inbox != source) { printf("Applying default rule to message %s\n", uid); camel_folder_append_message(inbox, mm, info, p->ex); } camel_object_unref (CAMEL_OBJECT (mm)); } - camel_folder_delete_message (p->source, uid); + + if (inbox != source) + camel_folder_delete_message (p->source, uid); mail_tool_camel_lock_down (); } diff --git a/filter/filter-driver.h b/filter/filter-driver.h index 338243212a..1ef62b7118 100644 --- a/filter/filter-driver.h +++ b/filter/filter-driver.h @@ -56,6 +56,7 @@ FilterDriver *filter_driver_new (FilterContext *ctx, FilterGetFolderFunc fe /* apply rules to a folder, unmatched messages goto inbox, if not NULL */ void filter_driver_run(FilterDriver *d, CamelFolder *source, CamelFolder *inbox, + enum _filter_source_t sourcetype, gboolean self_destruct, gpointer unhook_func, gpointer unhook_data); #if 0 diff --git a/filter/filter-editor.c b/filter/filter-editor.c index 368a5fbcfc..76fe9df704 100644 --- a/filter/filter-editor.c +++ b/filter/filter-editor.c @@ -129,6 +129,7 @@ struct _editor_data { FilterRule *current; GtkList *list; GtkButton *buttons[BUTTON_LAST]; + enum _filter_source_t current_source; }; static void set_sensitive(struct _editor_data *data); @@ -144,6 +145,7 @@ static void rule_add(GtkWidget *widget, struct _editor_data *data) d(printf("add rule\n")); /* create a new rule with 1 match and 1 action */ rule = filter_filter_new(); + ((FilterRule *)rule)->source = data->current_source; part = rule_context_next_part(data->f, NULL); filter_rule_add_part((FilterRule *)rule, filter_part_clone(part)); @@ -183,13 +185,14 @@ static void rule_edit(GtkWidget *widget, struct _editor_data *data) d(printf("edit rule\n")); rule = data->current; w = filter_rule_get_widget(rule, data->f); - gd = (GnomeDialog *)gnome_dialog_new("Edit Rule", "Ok", NULL); + gd = (GnomeDialog *)gnome_dialog_new("Edit Rule", GNOME_STOCK_BUTTON_OK, + GNOME_STOCK_BUTTON_CANCEL, NULL); gtk_box_pack_start((GtkBox *)gd->vbox, w, FALSE, TRUE, 0); gtk_widget_show((GtkWidget *)gd); result = gnome_dialog_run_and_close(gd); if (result == 0) { - pos = rule_context_get_rank_rule(data->f, data->current); + pos = rule_context_get_rank_rule_with_source (data->f, data->current, data->current_source); if (pos != -1) { GtkListItem *item = g_list_nth_data(data->list->children, pos); gtk_label_set_text((GtkLabel *)(((GtkBin *)item)->child), data->current->name); @@ -204,7 +207,7 @@ static void rule_delete(GtkWidget *widget, struct _editor_data *data) GtkListItem *item; d(printf("ddelete rule\n")); - pos = rule_context_get_rank_rule(data->f, data->current); + pos = rule_context_get_rank_rule_with_source (data->f, data->current, data->current_source); if (pos != -1) { rule_context_remove_rule(data->f, data->current); @@ -240,7 +243,7 @@ static void rule_up(GtkWidget *widget, struct _editor_data *data) int pos; d(printf("up rule\n")); - pos = rule_context_get_rank_rule(data->f, data->current); + pos = rule_context_get_rank_rule_with_source(data->f, data->current, data->current_source); if (pos>0) { rule_move(data, pos, pos-1); } @@ -251,7 +254,7 @@ static void rule_down(GtkWidget *widget, struct _editor_data *data) int pos; d(printf("down rule\n")); - pos = rule_context_get_rank_rule(data->f, data->current); + pos = rule_context_get_rank_rule_with_source(data->f, data->current, data->current_source); rule_move(data, pos, pos+1); } @@ -296,12 +299,49 @@ select_rule(GtkWidget *w, GtkWidget *child, struct _editor_data *data) set_sensitive(data); } +/* FIXME: we need a way to change a rule from one source type + * to a different type. Maybe keep the selected ones? + */ + +static void +select_source (GtkMenuItem *mi, struct _editor_data *data) +{ + FilterRule *rule = NULL; + GList *newitems = NULL; + enum _filter_source_t source; + + source = (enum _filter_source_t) GPOINTER_TO_INT ( + gtk_object_get_data (GTK_OBJECT (mi), "number")); + + gtk_list_clear_items (GTK_LIST (data->list), 0, -1); + + d(printf("Checking for rules that are of type %d\n", source)); + while ((rule = rule_context_next_rule (data->f, rule)) != NULL) { + GtkWidget *item; + + if (rule->source != source) { + d(printf(" skipping %s: %d != %d\n", rule->name, rule->source, source)); + continue; + } + + d(printf(" hit %s (%d)\n", rule->name, source)); + item = gtk_list_item_new_with_label (rule->name); + gtk_object_set_data (GTK_OBJECT (item), "rule", rule); + gtk_widget_show (GTK_WIDGET (item)); + newitems = g_list_append (newitems, item); + } + + gtk_list_append_items (data->list, newitems); + data->current_source = source; + data->current = NULL; + set_sensitive (data); +} + GtkWidget *filter_editor_construct (struct _FilterContext *f) { GladeXML *gui; - GtkWidget *d, *w; + GtkWidget *d, *w, *b, *firstitem = NULL; GList *l; - FilterRule *rule = NULL; struct _editor_data *data; int i; @@ -320,29 +360,28 @@ GtkWidget *filter_editor_construct (struct _FilterContext *f) gtk_signal_connect((GtkObject *)w, "clicked", edit_buttons[i].func, data); } - /* to be defined yet */ -#if 0 w = glade_xml_get_widget (gui, "filter_source"); l = GTK_MENU_SHELL(GTK_OPTION_MENU(w)->menu)->children; + i = 0; while (l) { - b = l->data; + b = GTK_WIDGET (l->data); + + if (i == 0) + firstitem = b; + + /* make sure that the glade is in sync with enum _filter_source_t! */ + gtk_object_set_data (GTK_OBJECT (b), "number", GINT_TO_POINTER (i)); + gtk_signal_connect (GTK_OBJECT (b), "activate", select_source, data); + + i++; l = l->next; } -#endif w = glade_xml_get_widget (gui, "rule_list"); data->list = (GtkList *)w; - l = NULL; - while ((rule = rule_context_next_rule((RuleContext *)f, rule))) { - GtkListItem *item = (GtkListItem *)gtk_list_item_new_with_label(rule->name); - gtk_object_set_data((GtkObject *)item, "rule", rule); - gtk_widget_show((GtkWidget *)item); - l = g_list_append(l, item); - } - gtk_list_append_items(data->list, l); gtk_signal_connect((GtkObject *)w, "select_child", select_rule, data); + select_source (GTK_MENU_ITEM (firstitem), data); - set_sensitive(data); gtk_object_unref((GtkObject *)gui); return d; diff --git a/filter/filter-rule.c b/filter/filter-rule.c index 9c47af6daf..58a2d76518 100644 --- a/filter/filter-rule.c +++ b/filter/filter-rule.c @@ -158,6 +158,19 @@ static xmlNodePtr xml_encode(FilterRule *fr) xmlSetProp(node, "grouping", "any"); break; } + + switch (fr->source) { + case FILTER_SOURCE_INCOMING: + xmlSetProp(node, "source", "incoming"); + break; + case FILTER_SOURCE_DEMAND: + xmlSetProp(node, "source", "ondemand"); + break; + case FILTER_SOURCE_OUTGOING: + xmlSetProp(node, "source", "outgoing"); + break; + } + if (fr->name) { work = xmlNewNode(NULL, "title"); xmlNodeSetContent(work, fr->name); @@ -209,16 +222,34 @@ static int xml_decode(FilterRule *fr, xmlNodePtr node, RuleContext *f) { xmlNodePtr work; char *grouping; + char *source; if (fr->name) { g_free(fr->name); fr->name = NULL; } + grouping = xmlGetProp(node, "grouping"); if (!strcmp(grouping, "any")) fr->grouping = FILTER_GROUP_ANY; else fr->grouping = FILTER_GROUP_ALL; + + /* FIXME: free source and grouping? */ + source = xmlGetProp (node, "source"); + if (!source) /*default to incoming*/ + fr->source = FILTER_SOURCE_INCOMING; + else if (!strcmp (source, "outgoing")) + fr->source = FILTER_SOURCE_OUTGOING; + else if (!strcmp (source, "ondemand")) + fr->source = FILTER_SOURCE_DEMAND; + else if (!strcmp (source, "incoming")) + fr->source = FILTER_SOURCE_INCOMING; + else { + g_warning ("Unknown filter source type \"%s\"", source); + fr->source = FILTER_SOURCE_INCOMING; + } + work = node->childs; while (work) { if (!strcmp(work->name, "partset")) { diff --git a/filter/filter-rule.h b/filter/filter-rule.h index 396af19e59..425d0ac350 100644 --- a/filter/filter-rule.h +++ b/filter/filter-rule.h @@ -39,6 +39,13 @@ enum _filter_grouping_t { FILTER_GROUP_ANY /* any rule must match */ }; +enum _filter_source_t { + FILTER_SOURCE_INCOMING, /* performed on incoming email */ + FILTER_SOURCE_DEMAND, /* performed on the selected folder + * when the user asks for it */ + FILTER_SOURCE_OUTGOING /* performed on outgoing mail */ +}; + struct _FilterRule { GtkObject parent; struct _FilterRulePrivate *priv; @@ -46,6 +53,7 @@ struct _FilterRule { char *name; enum _filter_grouping_t grouping; + enum _filter_source_t source; GList *parts; }; diff --git a/filter/filter.glade b/filter/filter.glade index d9b26e4489..5f8a04d64e 100644 --- a/filter/filter.glade +++ b/filter/filter.glade @@ -73,10 +73,9 @@ GtkOptionMenu filter_source - False True Incoming -Outgoing +On Demand 0 diff --git a/filter/rule-context.c b/filter/rule-context.c index c297ae1a61..8114d34197 100644 --- a/filter/rule-context.c +++ b/filter/rule-context.c @@ -26,7 +26,8 @@ #define d(x) x -static int load(RuleContext *f, const char *system, const char *user); +static int load(RuleContext *f, const char *system, const char *user, + RCRegisterFunc on_demand_cb, gpointer user_data); static int save(RuleContext *f, const char *user); static void rule_context_class_init (RuleContextClass *class); @@ -167,19 +168,25 @@ rule_context_set_error(RuleContext *f, char *error) * @f: * @system: * @user: + * @on_demand_cb: An optional callback to allow UI registration of on-demand rules + * @user_data: Extra data for the callback * * Load a rule context from a system and user description file. * * Return value: **/ -int rule_context_load(RuleContext *f, const char *system, const char *user) +int rule_context_load(RuleContext *f, const char *system, const char *user, + RCRegisterFunc on_demand_cb, gpointer user_data ) { printf("rule_context: loading %s %s\n", system, user); - return ((RuleContextClass *)((GtkObject *)f)->klass)->load(f, system, user); + return ((RuleContextClass *)((GtkObject *)f)->klass)->load(f, system, user, + on_demand_cb, + user_data); } -static int load(RuleContext *f, const char *system, const char *user) +static int load(RuleContext *f, const char *system, const char *user, + RCRegisterFunc on_demand_cb, gpointer user_data) { xmlNodePtr set, rule; struct _part_set_map *part_map; @@ -245,6 +252,9 @@ static int load(RuleContext *f, const char *system, const char *user) FilterRule *part = FILTER_RULE(gtk_type_new(rule_map->type)); if (filter_rule_xml_decode(part, rule, f) == 0) { rule_map->append(f, part); + + if (on_demand_cb && part->source == FILTER_SOURCE_DEMAND) + (on_demand_cb) (f, part, user_data); } else { gtk_object_unref((GtkObject *)part); g_warning("Cannot load filter part"); @@ -398,3 +408,20 @@ int rule_context_get_rank_rule(RuleContext *f, FilterRule *rule) { return g_list_index(f->rules, rule); } + +int +rule_context_get_rank_rule_with_source(RuleContext *f, FilterRule *rule, enum _filter_source_t source) +{ + int i; + GList *iter; + + i = 0; + for (iter = f->rules; iter; iter = iter->next) { + if (iter->data == rule) + return i; + if (((FilterRule *)iter->data)->source == source) + i++; + } + + return -1; +} diff --git a/filter/rule-context.h b/filter/rule-context.h index 06d32e0be3..27078adbcf 100644 --- a/filter/rule-context.h +++ b/filter/rule-context.h @@ -52,11 +52,14 @@ struct _RuleContext { GList *rule_set_list; }; +typedef void (*RCRegisterFunc)(RuleContext *f, FilterRule *rule, gpointer data); + struct _RuleContextClass { GtkObjectClass parent_class; /* virtual methods */ - int (*load)(RuleContext *f, const char *system, const char *user); + int (*load)(RuleContext *f, const char *system, const char *user, + RCRegisterFunc on_demand_cb, gpointer user_data); int (*save)(RuleContext *f, const char *user); /* signals */ @@ -85,7 +88,8 @@ guint rule_context_get_type (void); RuleContext *rule_context_new (void); /* methods */ -int rule_context_load(RuleContext *f, const char *system, const char *user); +int rule_context_load(RuleContext *f, const char *system, const char *user, + RCRegisterFunc on_demand_cb, gpointer user_data); int rule_context_save(RuleContext *f, const char *user); void rule_context_add_part(RuleContext *f, FilterPart *new); @@ -102,6 +106,7 @@ void rule_context_remove_rule(RuleContext *f, FilterRule *rule); /* get/set the rank (position) of a rule */ void rule_context_rank_rule(RuleContext *f, FilterRule *rule, int rank); int rule_context_get_rank_rule(RuleContext *f, FilterRule *rule); +int rule_context_get_rank_rule_with_source(RuleContext *f, FilterRule *rule, enum _filter_source_t source); void rule_context_delete_rule(RuleContext *f, FilterRule *rule); diff --git a/mail/ChangeLog b/mail/ChangeLog index 0bb4298961..1cbdce64c8 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,56 @@ +2000-08-17 Peter Williams + + Implement filtering on demand. + + * folder-browser-factory.c (register_ondemand): New function. Callback + to put the filter-on-demand filters into the bonobo UIH; + (create_ondemand_hooks): New function. Read in our on-demand filters + and hook them into the UI. + (remove_ondemand_hooks): New function. Remove the hooks when done with + them. + (control_activate): Call create_ondemand_hooks() + (control_deactivate): Call remove_ondemand_hooks(); + + * mail-callbacks.c (run_filter_ondemand): New function. Callback + for running a filter on demand. + (filter_edit): Pass NULLs as the new arguments to rule_context_load. + + * mail.h: Prototype run_filter_ondemand(); + + * folder-browser.c (oc_destroy): New function. Iterator to destroy + an fb_ondemand_closure. + (folder_browser_destroy): Free the data associated with the ondemand + menu items. + (my_folder_browser_init): Clear the filter_ variables. + + * folder-browser.h: Two new members of FolderBrowser: filter_menu_paths, + a list of fb_ondemand_closures so that the menu items can be freed and + removed; and filter_context, a permanently loaded FilterContext for + running the ondemand filters. Prototype the new fb_ondemand_closure + structure. + + * mail-autofilter.c (filter_gui_add_from_message): Pass NULLs as the + new parameters to rule_context_load (we don't need to hook up ondemand + menu items...) + + * mail-tools.c (mail_tool_filter_get_folder_func): Rename from + get_folder_func() and make public so mail-callbacks.c:run_filter_ondemand() + can use it too. + (mail_tool_filter_contents_into): Use the new name of get_folder_func. + Pass NULLs as the extra arguments to rule_context_load. Pass the + extra source type to filter_driver_run (only use INCOMING). + + * mail-tools.h: Publicly prototype mail_tool_filter_get_folder_func() + + * mail-vfolder.c (vfolder_create_storage): Pass NULLs as the extra + arguments to rule_context_load. + + * message-list.c (message_list_init): Free our strdup'd uids when + the table model gets destroyed. + (nuke_uids): New function. Walk the tree nodes to free the uids. + (nuke_uids_cb): New callback for nuke_uids(); + + 2000-08-16 Richard Hult * mail-ops.c (cleanup_display_message): Use a configurable timeout. diff --git a/mail/folder-browser-factory.c b/mail/folder-browser-factory.c index 2c29d78f26..9a71dbe8ab 100644 --- a/mail/folder-browser-factory.c +++ b/mail/folder-browser-factory.c @@ -52,6 +52,61 @@ static GnomeUIInfo gnome_toolbar [] = { GNOMEUIINFO_END }; +static void +register_ondemand (RuleContext *f, FilterRule *rule, gpointer data) +{ + FolderBrowser *fb = FOLDER_BROWSER (data); + BonoboUIHandler *uih = gtk_object_get_data (GTK_OBJECT (fb), "uih"); + gchar *text; + struct fb_ondemand_closure *oc; + + oc = g_new (struct fb_ondemand_closure, 1); + oc->rule = rule; + oc->fb = fb; + oc->path = g_strdup_printf ("/Actions/Filter-%s", rule->name); + + if (fb->filter_menu_paths == NULL) + bonobo_ui_handler_menu_new_separator (uih, "/Actions/separator2", -1); + + text = g_strdup_printf (_("Run filter \"%s\""), rule->name); + fb->filter_menu_paths = g_slist_prepend (fb->filter_menu_paths, oc); + + bonobo_ui_handler_menu_new_item (uih, oc->path, text, + NULL, -1, + BONOBO_UI_HANDLER_PIXMAP_NONE, + 0, + 0, 0, run_filter_ondemand, oc); + g_free (text); +} + +static void +create_ondemand_hooks (FolderBrowser *fb, BonoboUIHandler *uih) +{ + gchar *system, *user; + + user = g_strdup_printf ("%s/filters.xml", evolution_dir); + system = EVOLUTION_DATADIR "/evolution/filtertypes.xml"; + fb->filter_context = filter_context_new(); + gtk_object_set_data (GTK_OBJECT (fb), "uih", uih); + rule_context_load ((RuleContext *) fb->filter_context, system, user, + register_ondemand, fb); + gtk_object_remove_data (GTK_OBJECT (fb), "uih"); + g_free (user); +} + +static void +remove_ondemand_hooks (FolderBrowser *fb, BonoboUIHandler *uih) +{ + GSList *iter; + struct fb_ondemand_closure *oc; + + for (iter = fb->filter_menu_paths; iter; iter = iter->next) { + oc = (struct fb_ondemand_closure *) iter->data; + + bonobo_ui_handler_menu_remove (uih, oc->path); + } +} + static void control_activate (BonoboControl *control, BonoboUIHandler *uih, FolderBrowser *fb) @@ -143,7 +198,9 @@ control_activate (BonoboControl *control, BonoboUIHandler *uih, BONOBO_UI_HANDLER_PIXMAP_NONE, 0, 0, 0, configure_folder, folder_browser); - + + create_ondemand_hooks (fb, uih); + toolbar = gtk_toolbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_BOTH); @@ -196,6 +253,8 @@ control_deactivate (BonoboControl *control, bonobo_ui_handler_menu_remove (uih, "/Tools/Configure Folder"); bonobo_ui_handler_dock_remove (uih, toolbar_name); g_free (toolbar_name); + + remove_ondemand_hooks (fb, uih); } static void diff --git a/mail/folder-browser.c b/mail/folder-browser.c index 4707351f8c..8534378143 100644 --- a/mail/folder-browser.c +++ b/mail/folder-browser.c @@ -33,6 +33,14 @@ static GtkObjectClass *folder_browser_parent_class; +static void oc_destroy (gpointer obj, gpointer user) +{ + struct fb_ondemand_closure *oc = (struct fb_ondemand_closure *) obj; + + g_free (oc->path); + g_free (oc); +} + static void folder_browser_destroy (GtkObject *object) { @@ -60,6 +68,14 @@ folder_browser_destroy (GtkObject *object) if (folder_browser->mail_display) gtk_widget_destroy (GTK_WIDGET (folder_browser->mail_display)); + if (folder_browser->filter_context) + gtk_object_unref (GTK_OBJECT (folder_browser->filter_context)); + + if (folder_browser->filter_menu_paths) { + g_slist_foreach (folder_browser->filter_menu_paths, oc_destroy, NULL); + g_slist_free (folder_browser->filter_menu_paths); + } + folder_browser_parent_class->destroy (object); } @@ -402,6 +418,9 @@ my_folder_browser_init (GtkObject *object) gtk_signal_connect (GTK_OBJECT (fb->message_list->etable), "key_press", GTK_SIGNAL_FUNC (etable_key), fb); + fb->filter_menu_paths = NULL; + fb->filter_context = NULL; + folder_browser_gui_init (fb); } diff --git a/mail/folder-browser.h b/mail/folder-browser.h index 53bcb5b925..86c1c6f149 100644 --- a/mail/folder-browser.h +++ b/mail/folder-browser.h @@ -8,6 +8,8 @@ #include #include "camel/camel-stream.h" #include +#include "filter/filter-rule.h" +#include "filter/filter-context.h" /*eek*/ #include "message-list.h" #include "mail-display.h" #include "shell/Evolution.h" @@ -19,7 +21,6 @@ #define IS_FOLDER_BROWSER(o) (GTK_CHECK_TYPE ((o), FOLDER_BROWSER_TYPE)) #define IS_FOLDER_BROWSER_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), FOLDER_BROWSER_TYPE)) - struct _FolderBrowser { GtkTable parent; @@ -44,7 +45,10 @@ struct _FolderBrowser { GtkWidget *search_entry; gboolean preview_shown; - + + /* Stuff to allow on-demand filtering */ + GSList *filter_menu_paths; + FilterContext *filter_context; }; @@ -52,8 +56,11 @@ typedef struct { GtkTableClass parent_class; } FolderBrowserClass; - - +struct fb_ondemand_closure { + FilterRule *rule; + FolderBrowser *fb; + gchar *path; +}; GtkType folder_browser_get_type (void); GtkWidget *folder_browser_new (void); diff --git a/mail/mail-autofilter.c b/mail/mail-autofilter.c index 4aa246666a..2de013a448 100644 --- a/mail/mail-autofilter.c +++ b/mail/mail-autofilter.c @@ -255,7 +255,7 @@ filter_gui_add_from_message(CamelMimeMessage *msg, int flags) fc = filter_context_new(); userrules = g_strdup_printf("%s/filters.xml", evolution_dir); systemrules = g_strdup_printf("%s/evolution/filtertypes.xml", EVOLUTION_DATADIR); - rule_context_load((RuleContext *)fc, systemrules, userrules); + rule_context_load((RuleContext *)fc, systemrules, userrules, NULL, NULL); rule = filter_rule_from_message(fc, msg, flags); rule_context_add_rule_gui((RuleContext *)fc, rule, "Add Filter Rule", userrules); g_free (userrules); diff --git a/mail/mail-callbacks.c b/mail/mail-callbacks.c index 2156145d59..33b44c1c6c 100644 --- a/mail/mail-callbacks.c +++ b/mail/mail-callbacks.c @@ -525,7 +525,7 @@ filter_edit (BonoboUIHandler *uih, void *user_data, const char *path) fc = filter_context_new(); user = g_strdup_printf ("%s/filters.xml", evolution_dir); system = g_strdup_printf ("%s/evolution/filtertypes.xml", EVOLUTION_DATADIR); - rule_context_load ((RuleContext *)fc, system, user); + rule_context_load ((RuleContext *)fc, system, user, NULL, NULL); g_free (user); g_free (system); @@ -634,4 +634,21 @@ edit_message (BonoboUIHandler *uih, void *user_data, const char *path) edit_msg (NULL, user_data); } +void +run_filter_ondemand (BonoboUIHandler *uih, gpointer user_data, const char *path) +{ + struct fb_ondemand_closure *oc = (struct fb_ondemand_closure *) user_data; + FilterDriver *d; + + if (oc->fb->folder == NULL) + return; + + printf ("Running filter \"%s\"\n", oc->rule->name); + d = filter_driver_new (oc->fb->filter_context, + mail_tool_filter_get_folder_func, + NULL); + filter_driver_run (d, oc->fb->folder, oc->fb->folder, + FILTER_SOURCE_DEMAND, TRUE, + NULL, NULL); +} diff --git a/mail/mail-tools.c b/mail/mail-tools.c index 18996ed946..2d10411f91 100644 --- a/mail/mail-tools.c +++ b/mail/mail-tools.c @@ -487,7 +487,8 @@ mail_tool_fetch_mail_into_searchable (const char *source_url, gboolean keep_on_s return search_folder; } -static CamelFolder *get_folder_func (FilterDriver *d, const char *uri, void *data) +CamelFolder * +mail_tool_filter_get_folder_func (FilterDriver *d, const char *uri, void *data) { return mail_tool_uri_to_folder_noex (uri); } @@ -506,17 +507,18 @@ mail_tool_filter_contents_into (CamelFolder *source, CamelFolder *dest, userrules = g_strdup_printf ("%s/filters.xml", evolution_dir); systemrules = g_strdup_printf ("%s/evolution/filtertypes.xml", EVOLUTION_DATADIR); fc = filter_context_new(); - rule_context_load ((RuleContext *)fc, systemrules, userrules); + rule_context_load ((RuleContext *)fc, systemrules, userrules, NULL, NULL); g_free (userrules); g_free (systemrules); - filter = filter_driver_new (fc, get_folder_func, 0); + filter = filter_driver_new (fc, mail_tool_filter_get_folder_func, 0); if (hook_func) camel_object_hook_event (CAMEL_OBJECT (dest), "folder_changed", hook_func, hook_data); - filter_driver_run (filter, source, dest, TRUE, hook_func, hook_data); + filter_driver_run (filter, source, dest, FILTER_SOURCE_INCOMING, + TRUE, hook_func, hook_data); camel_folder_sync (CAMEL_FOLDER (source), TRUE, ex); camel_folder_sync (CAMEL_FOLDER (dest), TRUE, ex); diff --git a/mail/mail-tools.h b/mail/mail-tools.h index 106a971530..3aba7dde2c 100644 --- a/mail/mail-tools.h +++ b/mail/mail-tools.h @@ -26,6 +26,7 @@ #define MAIL_TOOLS_H #include +#include /*eek*/ /* A global recursive lock on Camel */ void mail_tool_camel_lock_up (void); @@ -106,4 +107,9 @@ mail_tool_uri_to_folder_noex (const char *uri); GHashTable * mail_lookup_url_table (CamelMimeMessage *mime_message); +/* Appropriate for filter_driver_run */ +CamelFolder * +mail_tool_filter_get_folder_func (FilterDriver *d, const char *uri, void *data); + + #endif diff --git a/mail/mail-vfolder.c b/mail/mail-vfolder.c index ba1a69517a..b33c5d9660 100644 --- a/mail/mail-vfolder.c +++ b/mail/mail-vfolder.c @@ -163,7 +163,7 @@ vfolder_create_storage(EvolutionShellComponent *shell_component) context = vfolder_context_new(); printf("loading rules %s %s\n", system, user); - if (rule_context_load((RuleContext *)context, system, user) != 0) { + if (rule_context_load((RuleContext *)context, system, user, NULL, NULL) != 0) { g_warning("cannot load vfolders: %s\n", ((RuleContext *)context)->error); } g_free(user); diff --git a/mail/mail.h b/mail/mail.h index 03045e1075..8a67d745fb 100644 --- a/mail/mail.h +++ b/mail/mail.h @@ -80,6 +80,8 @@ void mail_reply (CamelFolder *folder, CamelMimeMessage *msg, const char *uid, gb void composer_send_cb (EMsgComposer *composer, gpointer data); void mail_print_msg (MailDisplay *md); +void run_filter_ondemand (BonoboUIHandler *uih, gpointer user_data, const char *path); + /* mail view */ GtkWidget *mail_view_create (CamelFolder *source, const char *uid, CamelMimeMessage *msg); diff --git a/mail/message-list.c b/mail/message-list.c index f9772fa7b0..7499cbb651 100644 --- a/mail/message-list.c +++ b/mail/message-list.c @@ -71,6 +71,7 @@ static gint on_right_click (ETableScrolled *table, gint row, gint col, GdkEvent static void on_double_click (ETableScrolled *table, gint row, MessageList *list); static void select_msg (MessageList *message_list, gint row); static char *filter_date (const void *data); +static void nuke_uids (GtkObject *o); static struct { char **image_base; @@ -591,6 +592,8 @@ message_list_init (GtkObject *object) ml_tree_is_cell_editable, message_list); e_tree_model_root_node_set_visible ((ETreeModel *)message_list->table_model, FALSE); + gtk_signal_connect (GTK_OBJECT (message_list->table_model), "destroy", + (GtkSignalFunc) nuke_uids, NULL); message_list_init_renderers (message_list); message_list_init_header (message_list); @@ -846,6 +849,23 @@ build_subtree (MessageList *ml, ETreePath *parent, } } +static gboolean +nuke_uids_cb (GNode *node, gpointer data) +{ + g_free (e_tree_model_node_get_data (E_TREE_MODEL (data), node)); + return FALSE; +} + +static void +nuke_uids (GtkObject *o) +{ + ETreeModel *etm = E_TREE_MODEL (o); + + g_node_traverse (etm->root, G_IN_ORDER, + G_TRAVERSE_ALL, 0, + nuke_uids_cb, etm); +} + static void build_flat (MessageList *ml, GPtrArray *uids) { -- cgit v1.2.3