aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Williams <peterw@src.gnome.org>2000-08-18 01:42:21 +0800
committerPeter Williams <peterw@src.gnome.org>2000-08-18 01:42:21 +0800
commit7cf30eb79276d4f255c1d603e2c203bb054cf50e (patch)
tree687a003be1d0fbcc0ff06eccd900a04c38ad7aa0
parentb3f1da4f99afadb51862fe732d66b72437224b99 (diff)
downloadgsoc2013-evolution-7cf30eb79276d4f255c1d603e2c203bb054cf50e.tar.gz
gsoc2013-evolution-7cf30eb79276d4f255c1d603e2c203bb054cf50e.tar.zst
gsoc2013-evolution-7cf30eb79276d4f255c1d603e2c203bb054cf50e.zip
Filtering on demand! booyeah!
svn path=/trunk/; revision=4864
-rw-r--r--filter/ChangeLog42
-rw-r--r--filter/filter-driver.c22
-rw-r--r--filter/filter-driver.h1
-rw-r--r--filter/filter-editor.c79
-rw-r--r--filter/filter-rule.c31
-rw-r--r--filter/filter-rule.h8
-rw-r--r--filter/filter.glade3
-rw-r--r--filter/rule-context.c35
-rw-r--r--filter/rule-context.h9
-rw-r--r--mail/ChangeLog53
-rw-r--r--mail/folder-browser-factory.c61
-rw-r--r--mail/folder-browser.c19
-rw-r--r--mail/folder-browser.h15
-rw-r--r--mail/mail-autofilter.c2
-rw-r--r--mail/mail-callbacks.c19
-rw-r--r--mail/mail-tools.c10
-rw-r--r--mail/mail-tools.h6
-rw-r--r--mail/mail-vfolder.c2
-rw-r--r--mail/mail.h2
-rw-r--r--mail/message-list.c20
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 <peterw@helixcode.com>
+
+ 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 <peterw@curious-george.helixcode.com>
* 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 @@
<widget>
<class>GtkOptionMenu</class>
<name>filter_source</name>
- <sensitive>False</sensitive>
<can_focus>True</can_focus>
<items>Incoming
-Outgoing
+On Demand
</items>
<initial_choice>0</initial_choice>
<child>
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 <peterw@helixcode.com>
+
+ 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 <rhult@hem.passagen.se>
* 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
@@ -53,6 +53,61 @@ static GnomeUIInfo gnome_toolbar [] = {
};
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 <gtk/gtktable.h>
#include "camel/camel-stream.h"
#include <bonobo/bonobo-property-bag.h>
+#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 <camel/camel.h>
+#include <filter/filter-driver.h> /*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)
{