[evolution] Cleanup and rename filter classes.



commit 2b16aef84141800099f859e72d05e1e6bf8e02dd
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sun Oct 25 09:17:23 2009 -0400

    Cleanup and rename filter classes.

 addressbook/gui/widgets/e-addressbook-view.c      |    2 +-
 e-util/e-util.c                                   |    4 +-
 filter/Makefile.am                                |   72 +-
 filter/e-filter-code.c                            |  126 +++
 filter/e-filter-code.h                            |   68 ++
 filter/e-filter-color.c                           |  180 ++++
 filter/e-filter-color.h                           |   70 ++
 filter/{filter-datespec.c => e-filter-datespec.c} |  376 ++++----
 filter/e-filter-datespec.h                        |   87 ++
 filter/e-filter-element.c                         |  472 +++++++++
 filter/e-filter-element.h                         |  118 +++
 filter/e-filter-file.c                            |  278 +++++
 filter/e-filter-file.h                            |   74 ++
 filter/e-filter-input.c                           |  322 ++++++
 filter/e-filter-input.h                           |   74 ++
 filter/e-filter-int.c                             |  261 +++++
 filter/e-filter-int.h                             |   77 ++
 filter/e-filter-option.c                          |  514 ++++++++++
 filter/e-filter-option.h                          |   92 ++
 filter/e-filter-part.c                            |  532 ++++++++++
 filter/e-filter-part.h                            |  104 ++
 filter/e-filter-rule.c                            | 1116 +++++++++++++++++++++
 filter/e-filter-rule.h                            |  161 +++
 filter/e-rule-context.c                           |  988 ++++++++++++++++++
 filter/e-rule-context.h                           |  215 ++++
 filter/e-rule-editor.c                            |  912 +++++++++++++++++
 filter/e-rule-editor.h                            |  122 +++
 filter/filter-code.c                              |  136 ---
 filter/filter-code.h                              |   56 -
 filter/filter-colour.c                            |  219 ----
 filter/filter-colour.h                            |   58 --
 filter/filter-datespec.h                          |   75 --
 filter/filter-element.c                           |  336 -------
 filter/filter-element.h                           |   93 --
 filter/filter-file.c                              |  292 ------
 filter/filter-file.h                              |   67 --
 filter/filter-input.c                             |  360 -------
 filter/filter-input.h                             |   62 --
 filter/filter-int.c                               |  270 -----
 filter/filter-int.h                               |   62 --
 filter/filter-option.c                            |  497 ---------
 filter/filter-option.h                            |   75 --
 filter/filter-part.c                              |  541 ----------
 filter/filter-part.h                              |   89 --
 filter/filter-rule.c                              | 1044 -------------------
 filter/filter-rule.h                              |  134 ---
 filter/rule-context.c                             |  952 ------------------
 filter/rule-context.h                             |  149 ---
 filter/rule-editor.c                              |  880 ----------------
 filter/rule-editor.h                              |  104 --
 mail/e-mail-reader-utils.c                        |    8 +-
 mail/em-filter-context.c                          |   86 +-
 mail/em-filter-context.h                          |   14 +-
 mail/em-filter-editor.c                           |   28 +-
 mail/em-filter-editor.h                           |    6 +-
 mail/em-filter-folder-element.c                   |   49 +-
 mail/em-filter-folder-element.h                   |    6 +-
 mail/em-filter-rule.c                             |  112 +-
 mail/em-filter-rule.h                             |   12 +-
 mail/em-filter-source-element.c                   |   52 +-
 mail/em-filter-source-element.h                   |    6 +-
 mail/em-folder-utils.c                            |    2 +-
 mail/em-search-context.c                          |   30 +-
 mail/em-search-context.h                          |    8 +-
 mail/em-utils.c                                   |    8 +-
 mail/em-vfolder-context.c                         |   36 +-
 mail/em-vfolder-context.h                         |    6 +-
 mail/em-vfolder-editor.c                          |   22 +-
 mail/em-vfolder-editor.h                          |    6 +-
 mail/em-vfolder-rule.c                            |   52 +-
 mail/em-vfolder-rule.h                            |    6 +-
 mail/mail-autofilter.c                            |  140 ++--
 mail/mail-autofilter.h                            |    8 +-
 mail/mail-ops.c                                   |    4 +-
 mail/mail-send-recv.c                             |   12 +-
 mail/mail-session.c                               |   20 +-
 mail/mail-tools.c                                 |    4 +-
 mail/mail-vfolder.c                               |  102 +-
 mail/mail-vfolder.h                               |    8 +-
 modules/addressbook/e-book-shell-view-actions.c   |    2 +-
 modules/addressbook/e-book-shell-view.c           |    8 +-
 modules/calendar/e-cal-shell-view.c               |    8 +-
 modules/calendar/e-memo-shell-view.c              |    8 +-
 modules/calendar/e-task-shell-view.c              |    8 +-
 modules/mail/e-mail-shell-backend.c               |    2 +-
 modules/mail/e-mail-shell-view-actions.c          |    8 +-
 modules/mail/e-mail-shell-view-private.c          |   14 +-
 modules/mail/e-mail-shell-view-private.h          |    4 +-
 modules/mail/e-mail-shell-view.c                  |   20 +-
 plugins/groupwise-features/share-folder-common.c  |    4 +-
 shell/e-shell-content.c                           |   98 +-
 shell/e-shell-content.h                           |   12 +-
 shell/e-shell-window-actions.c                    |   14 +-
 93 files changed, 7712 insertions(+), 7319 deletions(-)
---
diff --git a/addressbook/gui/widgets/e-addressbook-view.c b/addressbook/gui/widgets/e-addressbook-view.c
index 8d07a80..1583f26 100644
--- a/addressbook/gui/widgets/e-addressbook-view.c
+++ b/addressbook/gui/widgets/e-addressbook-view.c
@@ -29,7 +29,7 @@
 #include <table/e-cell-date.h>
 #include <misc/e-gui-utils.h>
 #include <widgets/menus/gal-view-factory-etable.h>
-#include <filter/rule-editor.h>
+#include <filter/e-rule-editor.h>
 #include <widgets/menus/gal-view-etable.h>
 #include <shell/e-shell-sidebar.h>
 
diff --git a/e-util/e-util.c b/e-util/e-util.c
index f4bf144..533b3ef 100644
--- a/e-util/e-util.c
+++ b/e-util/e-util.c
@@ -47,7 +47,9 @@
 
 #include <libedataserver/e-data-server-util.h>
 #include <libedataserver/e-categories.h>
-#include "filter/filter-option.h"
+
+#include "filter/e-filter-option.h"
+
 #include "e-util.h"
 #include "e-util-private.h"
 
diff --git a/filter/Makefile.am b/filter/Makefile.am
index 48cfa5c..d058427 100644
--- a/filter/Makefile.am
+++ b/filter/Makefile.am
@@ -13,44 +13,44 @@ libfilter_la_CPPFLAGS = 			\
 filterincludedir = $(privincludedir)/filter
 
 filterinclude_HEADERS = 			\
-	filter-code.h				\
-	filter-colour.h				\
-	filter-datespec.h			\
-	filter-element.h			\
-	filter-file.h				\
-	filter-input.h				\
-	filter-int.h				\
-	filter-option.h				\
-	filter-part.h				\
-	filter-rule.h				\
-	rule-context.h				\
-	rule-editor.h
+	e-filter-code.h				\
+	e-filter-color.h			\
+	e-filter-datespec.h			\
+	e-filter-element.h			\
+	e-filter-file.h				\
+	e-filter-input.h			\
+	e-filter-int.h				\
+	e-filter-option.h			\
+	e-filter-part.h				\
+	e-filter-rule.h				\
+	e-rule-context.h			\
+	e-rule-editor.h
 
 libfilter_la_SOURCES =				\
-	filter-code.c				\
-	filter-code.h				\
-	filter-colour.c				\
-	filter-colour.h				\
-	filter-datespec.c			\
-	filter-datespec.h			\
-	filter-element.c			\
-	filter-element.h			\
-	filter-file.c				\
-	filter-file.h				\
-	filter-input.c				\
-	filter-input.h				\
-	filter-int.c				\
-	filter-int.h				\
-	filter-option.c				\
-	filter-option.h				\
-	filter-part.c				\
-	filter-part.h				\
-	filter-rule.c				\
-	filter-rule.h				\
-	rule-context.c				\
-	rule-context.h				\
-	rule-editor.c				\
-	rule-editor.h
+	e-filter-code.c				\
+	e-filter-code.h				\
+	e-filter-color.c			\
+	e-filter-color.h			\
+	e-filter-datespec.c			\
+	e-filter-datespec.h			\
+	e-filter-element.c			\
+	e-filter-element.h			\
+	e-filter-file.c				\
+	e-filter-file.h				\
+	e-filter-input.c			\
+	e-filter-input.h			\
+	e-filter-int.c				\
+	e-filter-int.h				\
+	e-filter-option.c			\
+	e-filter-option.h			\
+	e-filter-part.c				\
+	e-filter-part.h				\
+	e-filter-rule.c				\
+	e-filter-rule.h				\
+	e-rule-context.c			\
+	e-rule-context.h			\
+	e-rule-editor.c				\
+	e-rule-editor.h
 
 libfilter_la_LDFLAGS = $(NO_UNDEFINED)
 
diff --git a/filter/e-filter-code.c b/filter/e-filter-code.c
new file mode 100644
index 0000000..7c00baf
--- /dev/null
+++ b/filter/e-filter-code.c
@@ -0,0 +1,126 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-filter-code.h"
+
+static gpointer parent_class;
+
+/* here, the string IS the code */
+static void
+filter_code_build_code (EFilterElement *element,
+                        GString *out,
+                        struct _EFilterPart *part)
+{
+	GList *l;
+	EFilterInput *fi = (EFilterInput *)element;
+	gboolean is_rawcode = fi && fi->type && g_str_equal (fi->type, "rawcode");
+
+	if (!is_rawcode)
+		g_string_append(out, "(match-all ");
+
+	l = fi->values;
+	while (l) {
+		g_string_append(out, (gchar *)l->data);
+		l = g_list_next(l);
+	}
+
+	if (!is_rawcode)
+		g_string_append (out, ")");
+}
+
+/* and we have no value */
+static void
+filter_code_format_sexp (EFilterElement *element,
+                         GString *out)
+{
+}
+
+static void
+filter_code_class_init (EFilterCodeClass *class)
+{
+	EFilterElementClass *filter_element_class;
+
+	parent_class = g_type_class_peek_parent (class);
+
+	filter_element_class = E_FILTER_ELEMENT_CLASS (class);
+	filter_element_class->build_code = filter_code_build_code;
+	filter_element_class->format_sexp = filter_code_format_sexp;
+}
+
+static void
+filter_code_init (EFilterCode *code)
+{
+	EFilterInput *input = E_FILTER_INPUT (code);
+
+	input->type = (gchar *) xmlStrdup ((xmlChar *) "code");
+}
+
+GType
+e_filter_code_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EFilterCodeClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) filter_code_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EFilterCode),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) filter_code_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			E_TYPE_FILTER_INPUT, "EFilterCode", &type_info, 0);
+	}
+
+	return type;
+}
+
+/**
+ * filter_code_new:
+ *
+ * Create a new EFilterCode object.
+ *
+ * Return value: A new #EFilterCode object.
+ **/
+EFilterCode *
+e_filter_code_new (gboolean raw_code)
+{
+	EFilterCode *fc = g_object_new (E_TYPE_FILTER_CODE, NULL, NULL);
+
+	if (fc && raw_code) {
+		xmlFree (((EFilterInput *) fc)->type);
+		((EFilterInput *) fc)->type = (gchar *)xmlStrdup ((xmlChar *)"rawcode");
+	}
+
+	return fc;
+}
diff --git a/filter/e-filter-code.h b/filter/e-filter-code.h
new file mode 100644
index 0000000..6a903a5
--- /dev/null
+++ b/filter/e-filter-code.h
@@ -0,0 +1,68 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_FILTER_CODE_H
+#define E_FILTER_CODE_H
+
+#include "e-filter-input.h"
+
+/* Standard GObject macros */
+#define E_TYPE_FILTER_CODE \
+	(e_filter_code_get_type ())
+#define E_FILTER_CODE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_FILTER_CODE, EFilterCode))
+#define E_FILTER_CODE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_FILTER_CODE, EFilterCodeClass))
+#define E_IS_FILTER_CODE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_FILTER_CODE))
+#define E_IS_FILTER_CODE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_FILTER_CODE))
+#define E_FILTER_CODE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_FILTER_CODE, EFilterCodeClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EFilterCode EFilterCode;
+typedef struct _EFilterCodeClass EFilterCodeClass;
+typedef struct _EFilterCodePrivate EFilterCodePrivate;
+
+struct _EFilterCode {
+	EFilterInput parent;
+	EFilterCodePrivate *priv;
+};
+
+struct _EFilterCodeClass {
+	EFilterInputClass parent_class;
+};
+
+GType		e_filter_code_get_type		(void);
+EFilterCode *	e_filter_code_new		(gboolean raw_code);
+
+G_END_DECLS
+
+#endif /* E_FILTER_CODE_H */
diff --git a/filter/e-filter-color.c b/filter/e-filter-color.c
new file mode 100644
index 0000000..c4a3660
--- /dev/null
+++ b/filter/e-filter-color.c
@@ -0,0 +1,180 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <libedataserver/e-sexp.h>
+
+#include "e-filter-color.h"
+
+static gpointer parent_class;
+
+static void
+set_color (GtkColorButton *color_button, EFilterColor *fc)
+{
+	gtk_color_button_get_color (color_button, &fc->color);
+}
+
+static gint
+filter_color_eq (EFilterElement *element_a,
+                 EFilterElement *element_b)
+{
+	EFilterColor *color_a = E_FILTER_COLOR (element_a);
+	EFilterColor *color_b = E_FILTER_COLOR (element_b);
+
+	return E_FILTER_ELEMENT_CLASS (parent_class)->eq (element_a, element_b)
+		&& gdk_color_equal (&color_a->color, &color_b->color);
+}
+
+static xmlNodePtr
+filter_color_xml_encode (EFilterElement *element)
+{
+	EFilterColor *fc = E_FILTER_COLOR (element);
+	xmlNodePtr value;
+	gchar spec[16];
+
+	g_snprintf (spec, sizeof (spec), "#%04x%04x%04x",
+		fc->color.red, fc->color.green, fc->color.blue);
+
+	value = xmlNewNode(NULL, (xmlChar *)"value");
+	xmlSetProp(value, (xmlChar *)"type", (xmlChar *)"colour");
+	xmlSetProp(value, (xmlChar *)"name", (xmlChar *)element->name);
+	xmlSetProp(value, (xmlChar *)"spec", (xmlChar *)spec);
+
+	return value;
+}
+
+static gint
+filter_color_xml_decode (EFilterElement *element,
+                         xmlNodePtr node)
+{
+	EFilterColor *fc = E_FILTER_COLOR (element);
+	xmlChar *prop;
+
+	xmlFree (element->name);
+	element->name = (gchar *)xmlGetProp(node, (xmlChar *)"name");
+
+	prop = xmlGetProp(node, (xmlChar *)"spec");
+	if (prop != NULL) {
+		gdk_color_parse((gchar *)prop, &fc->color);
+		xmlFree (prop);
+	} else {
+		/* try reading the old RGB properties */
+		prop = xmlGetProp(node, (xmlChar *)"red");
+		sscanf((gchar *)prop, "%" G_GINT16_MODIFIER "x", &fc->color.red);
+		xmlFree (prop);
+		prop = xmlGetProp(node, (xmlChar *)"green");
+		sscanf((gchar *)prop, "%" G_GINT16_MODIFIER "x", &fc->color.green);
+		xmlFree (prop);
+		prop = xmlGetProp(node, (xmlChar *)"blue");
+		sscanf((gchar *)prop, "%" G_GINT16_MODIFIER "x", &fc->color.blue);
+		xmlFree (prop);
+	}
+
+	return 0;
+}
+
+static GtkWidget *
+filter_color_get_widget (EFilterElement *element)
+{
+	EFilterColor *fc = E_FILTER_COLOR (element);
+	GtkWidget *color_button;
+
+	color_button = gtk_color_button_new_with_color (&fc->color);
+	gtk_widget_show (color_button);
+
+	g_signal_connect (
+		G_OBJECT (color_button), "color_set",
+		G_CALLBACK (set_color), element);
+
+	return color_button;
+}
+
+static void
+filter_color_format_sexp (EFilterElement *element,
+                          GString *out)
+{
+	EFilterColor *fc = E_FILTER_COLOR (element);
+	gchar spec[16];
+
+	g_snprintf (spec, sizeof (spec), "#%04x%04x%04x",
+		fc->color.red, fc->color.green, fc->color.blue);
+	e_sexp_encode_string (out, spec);
+}
+
+static void
+filter_color_class_init (EFilterColorClass *class)
+{
+	EFilterElementClass *filter_element_class;
+
+	parent_class = g_type_class_peek_parent (class);
+
+	filter_element_class = E_FILTER_ELEMENT_CLASS (class);
+	filter_element_class->eq = filter_color_eq;
+	filter_element_class->xml_encode = filter_color_xml_encode;
+	filter_element_class->xml_decode = filter_color_xml_decode;
+	filter_element_class->get_widget = filter_color_get_widget;
+	filter_element_class->format_sexp = filter_color_format_sexp;
+}
+
+GType
+e_filter_color_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EFilterColorClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) filter_color_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EFilterColor),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) NULL,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			E_TYPE_FILTER_ELEMENT, "EFilterColor", &type_info, 0);
+	}
+
+	return type;
+}
+
+/**
+ * filter_color_new:
+ *
+ * Create a new EFilterColor object.
+ *
+ * Return value: A new #EFilterColor object.
+ **/
+EFilterColor *
+e_filter_color_new (void)
+{
+	return g_object_new (E_TYPE_FILTER_COLOR, NULL);
+}
diff --git a/filter/e-filter-color.h b/filter/e-filter-color.h
new file mode 100644
index 0000000..cf75bc1
--- /dev/null
+++ b/filter/e-filter-color.h
@@ -0,0 +1,70 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_FILTER_COLOR_H
+#define E_FILTER_COLOR_H
+
+#include "e-filter-element.h"
+
+/* Standard GObject macros */
+#define E_TYPE_FILTER_COLOR \
+	(e_filter_color_get_type ())
+#define E_FILTER_COLOR(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_FILTER_COLOR, EFilterColor))
+#define E_FILTER_COLOR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_FILTER_COLOR, EFilterColorClass))
+#define E_IS_FILTER_COLOR(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_FILTER_COLOR))
+#define E_IS_FILTER_COLOR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_FILTER_COLOR))
+#define E_FILTER_COLOR_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_FILTER_COLOR, EFilterColorClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EFilterColor EFilterColor;
+typedef struct _EFilterColorClass EFilterColorClass;
+typedef struct _EFilterColorPrivate EFilterColorPrivate;
+
+struct _EFilterColor {
+	EFilterElement parent;
+	EFilterColorPrivate *priv;
+
+	GdkColor color;
+};
+
+struct _EFilterColorClass {
+	EFilterElementClass parent_class;
+};
+
+GType		e_filter_color_get_type		(void);
+EFilterColor *	e_filter_color_new		(void);
+
+G_END_DECLS
+
+#endif /* E_FILTER_COLOR_H */
diff --git a/filter/filter-datespec.c b/filter/e-filter-datespec.c
similarity index 67%
rename from filter/filter-datespec.c
rename to filter/e-filter-datespec.c
index a0e981d..1a34cce 100644
--- a/filter/filter-datespec.c
+++ b/filter/e-filter-datespec.c
@@ -33,34 +33,25 @@
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
 #include <glade/glade.h>
+#include <libedataserver/e-sexp.h>
 
-#include "filter-datespec.h"
-#include "libedataserver/e-sexp.h"
 #include "e-util/e-error.h"
 #include "e-util/e-util-private.h"
 
+#include "e-filter-datespec.h"
+#include "e-filter-part.h"
+
 #ifdef G_OS_WIN32
 #define localtime_r(tp,tmp) memcpy(tmp,localtime(tp),sizeof(struct tm))
 #endif
 
-#define d(x)
-
-static gboolean validate (FilterElement *fe, GtkWindow *error_parent);
-static gint date_eq (FilterElement *fe, FilterElement *cm);
-static void xml_create (FilterElement *fe, xmlNodePtr node);
-static xmlNodePtr xml_encode (FilterElement *fe);
-static gint xml_decode (FilterElement *fe, xmlNodePtr node);
-static GtkWidget *get_widget (FilterElement *fe);
-static void build_code (FilterElement *fe, GString *out, struct _FilterPart *fds);
-static void format_sexp (FilterElement *, GString *);
+#define E_FILTER_DATESPEC_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_FILTER_DATESPEC, EFilterDatespecPrivate))
 
-static void filter_datespec_class_init (FilterDatespecClass *klass);
-static void filter_datespec_init (FilterDatespec *fd);
-static void filter_datespec_finalise (GObject *obj);
-
-#define PRIV(x) (((FilterDatespec *)(x))->priv)
+#define d(x)
 
-typedef struct _timespan {
+typedef struct {
 	guint32 seconds;
 	const gchar *past_singular;
 	const gchar *past_plural;
@@ -92,171 +83,14 @@ static const timespan timespans[] = {
 
 #define DAY_INDEX 3
 
-struct _FilterDatespecPrivate {
+struct _EFilterDatespecPrivate {
 	GtkWidget *label_button;
 	GtkWidget *notebook_type, *combobox_type, *calendar_specify, *spin_relative, *combobox_relative, *combobox_past_future;
-	FilterDatespec_type type;
+	EFilterDatespecType type;
 	gint span;
 };
 
-static FilterElementClass *parent_class;
-
-GType
-filter_datespec_get_type (void)
-{
-	static GType type = 0;
-
-	if (!type) {
-		static const GTypeInfo info = {
-			sizeof (FilterDatespecClass),
-			NULL, /* base_class_init */
-			NULL, /* base_class_finalize */
-			(GClassInitFunc) filter_datespec_class_init,
-			NULL, /* class_finalize */
-			NULL, /* class_data */
-			sizeof (FilterDatespec),
-			0,    /* n_preallocs */
-			(GInstanceInitFunc) filter_datespec_init,
-		};
-
-		type = g_type_register_static (FILTER_TYPE_ELEMENT, "FilterDatespec", &info, 0);
-	}
-
-	return type;
-}
-
-static void
-filter_datespec_class_init (FilterDatespecClass *klass)
-{
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-	FilterElementClass *fe_class = FILTER_ELEMENT_CLASS (klass);
-
-	parent_class = g_type_class_ref (FILTER_TYPE_ELEMENT);
-
-	object_class->finalize = filter_datespec_finalise;
-
-	/* override methods */
-	fe_class->validate = validate;
-	fe_class->eq = date_eq;
-	fe_class->xml_create = xml_create;
-	fe_class->xml_encode = xml_encode;
-	fe_class->xml_decode = xml_decode;
-	fe_class->get_widget = get_widget;
-	fe_class->build_code = build_code;
-	fe_class->format_sexp = format_sexp;
-}
-
-static void
-filter_datespec_init (FilterDatespec *fd)
-{
-	fd->priv = g_malloc0 (sizeof (*fd->priv));
-	fd->type = FDST_UNKNOWN;
-}
-
-static void
-filter_datespec_finalise (GObject *obj)
-{
-	FilterDatespec *fd = (FilterDatespec *) obj;
-
-	g_free (fd->priv);
-
-        G_OBJECT_CLASS (parent_class)->finalize (obj);
-}
-
-/**
- * filter_datespec_new:
- *
- * Create a new FilterDatespec object.
- *
- * Return value: A new #FilterDatespec object.
- **/
-FilterDatespec *
-filter_datespec_new (void)
-{
-	return (FilterDatespec *) g_object_new (FILTER_TYPE_DATESPEC, NULL, NULL);
-}
-
-static gboolean
-validate (FilterElement *fe, GtkWindow *error_parent)
-{
-	FilterDatespec *fds = (FilterDatespec *) fe;
-	gboolean valid;
-
-	valid = fds->type != FDST_UNKNOWN;
-	if (!valid) {
-		e_error_run (error_parent, "filter:no-date", NULL);
-	}
-
-	return valid;
-}
-
-static gint
-date_eq (FilterElement *fe, FilterElement *cm)
-{
-	FilterDatespec *fd = (FilterDatespec *)fe, *cd = (FilterDatespec *)cm;
-
-        return FILTER_ELEMENT_CLASS (parent_class)->eq(fe, cm)
-		&& (fd->type == cd->type)
-		&& (fd->value == cd->value);
-}
-
-static void
-xml_create (FilterElement *fe, xmlNodePtr node)
-{
-	/* parent implementation */
-        FILTER_ELEMENT_CLASS (parent_class)->xml_create (fe, node);
-}
-
-static xmlNodePtr
-xml_encode (FilterElement *fe)
-{
-	xmlNodePtr value, work;
-	FilterDatespec *fds = (FilterDatespec *)fe;
-	gchar str[32];
-
-	d(printf ("Encoding datespec as xml\n"));
-
-	value = xmlNewNode (NULL, (const guchar *)"value");
-	xmlSetProp (value, (const guchar *)"name", (guchar *)fe->name);
-	xmlSetProp (value, (const guchar *)"type", (const guchar *)"datespec");
-
-	work = xmlNewChild (value, NULL, (const guchar *)"datespec", NULL);
-	sprintf (str, "%d", fds->type);
-	xmlSetProp (work, (const guchar *)"type", (guchar *)str);
-	sprintf (str, "%d", (gint)fds->value);
-	xmlSetProp (work, (const guchar *)"value", (guchar *)str);
-
-	return value;
-}
-
-static gint
-xml_decode (FilterElement *fe, xmlNodePtr node)
-{
-	FilterDatespec *fds = (FilterDatespec *)fe;
-	xmlNodePtr n;
-	xmlChar *val;
-
-	d(printf ("Decoding datespec from xml %p\n", fe));
-
-	xmlFree (fe->name);
-	fe->name = (gchar *)xmlGetProp (node, (const guchar *)"name");
-
-	n = node->children;
-	while (n) {
-		if (!strcmp ((gchar *)n->name, "datespec")) {
-			val = xmlGetProp (n, (const guchar *)"type");
-			fds->type = atoi ((gchar *)val);
-			xmlFree (val);
-			val = xmlGetProp (n, (const guchar *)"value");
-			fds->value = atoi ((gchar *)val);
-			xmlFree (val);
-			break;
-		}
-		n = n->next;
-	}
-
-	return 0;
-}
+static gpointer parent_class;
 
 static gint
 get_best_span (time_t val)
@@ -273,7 +107,7 @@ get_best_span (time_t val)
 
 /* sets button label */
 static void
-set_button (FilterDatespec *fds)
+set_button (EFilterDatespec *fds)
 {
 	gchar buf[128];
 	gchar *label = buf;
@@ -320,9 +154,9 @@ set_button (FilterDatespec *fds)
 }
 
 static void
-get_values (FilterDatespec *fds)
+get_values (EFilterDatespec *fds)
 {
-	struct _FilterDatespecPrivate *p = PRIV(fds);
+	EFilterDatespecPrivate *p = E_FILTER_DATESPEC_GET_PRIVATE (fds);
 
 	switch (fds->priv->type) {
 	case FDST_SPECIFIED: {
@@ -353,11 +187,11 @@ get_values (FilterDatespec *fds)
 }
 
 static void
-set_values (FilterDatespec *fds)
+set_values (EFilterDatespec *fds)
 {
 	gint note_type;
 
-	struct _FilterDatespecPrivate *p = PRIV(fds);
+	EFilterDatespecPrivate *p = E_FILTER_DATESPEC_GET_PRIVATE (fds);
 
 	p->type = fds->type==FDST_UNKNOWN ? FDST_NOW : fds->type;
 
@@ -396,20 +230,20 @@ set_values (FilterDatespec *fds)
 }
 
 static void
-set_combobox_type (GtkComboBox *combobox, FilterDatespec *fds)
+set_combobox_type (GtkComboBox *combobox, EFilterDatespec *fds)
 {
 	fds->priv->type = gtk_combo_box_get_active (combobox);
 	gtk_notebook_set_current_page ((GtkNotebook*) fds->priv->notebook_type, fds->priv->type);
 }
 
 static void
-set_combobox_relative (GtkComboBox *combobox, FilterDatespec *fds)
+set_combobox_relative (GtkComboBox *combobox, EFilterDatespec *fds)
 {
 	fds->priv->span = gtk_combo_box_get_active (combobox);
 }
 
 static void
-set_combobox_past_future (GtkComboBox *combobox, FilterDatespec *fds)
+set_combobox_past_future (GtkComboBox *combobox, EFilterDatespec *fds)
 {
 	if (gtk_combo_box_get_active (combobox) == 0)
 		fds->type = fds->priv->type = FDST_X_AGO;
@@ -418,9 +252,9 @@ set_combobox_past_future (GtkComboBox *combobox, FilterDatespec *fds)
 }
 
 static void
-button_clicked (GtkButton *button, FilterDatespec *fds)
+button_clicked (GtkButton *button, EFilterDatespec *fds)
 {
-	struct _FilterDatespecPrivate *p = PRIV(fds);
+	EFilterDatespecPrivate *p = E_FILTER_DATESPEC_GET_PRIVATE (fds);
 	GtkWidget *content_area;
 	GtkWidget *toplevel;
 	GtkDialog *dialog;
@@ -465,10 +299,92 @@ button_clicked (GtkButton *button, FilterDatespec *fds)
 	gtk_widget_destroy ((GtkWidget *)dialog);
 }
 
+static gboolean
+filter_datespec_validate (EFilterElement *element,
+                          GtkWindow *error_parent)
+{
+	EFilterDatespec *fds = E_FILTER_DATESPEC (element);
+	gboolean valid;
+
+	valid = fds->type != FDST_UNKNOWN;
+	if (!valid) {
+		e_error_run (error_parent, "filter:no-date", NULL);
+	}
+
+	return valid;
+}
+
+static gint
+filter_datespec_eq (EFilterElement *element_a,
+                    EFilterElement *element_b)
+{
+	EFilterDatespec *datespec_a = E_FILTER_DATESPEC (element_a);
+	EFilterDatespec *datespec_b = E_FILTER_DATESPEC (element_b);
+
+	/* Chain up to parent's eq() method. */
+	if (!E_FILTER_ELEMENT_CLASS (parent_class)->eq (element_a, element_b))
+		return FALSE;
+
+	return (datespec_a->type == datespec_b->type) &&
+		(datespec_a->value == datespec_b->value);
+}
+
+static xmlNodePtr
+filter_datespec_xml_encode (EFilterElement *element)
+{
+	xmlNodePtr value, work;
+	EFilterDatespec *fds = E_FILTER_DATESPEC (element);
+	gchar str[32];
+
+	d(printf ("Encoding datespec as xml\n"));
+
+	value = xmlNewNode (NULL, (xmlChar *)"value");
+	xmlSetProp (value, (xmlChar *)"name", (xmlChar *)element->name);
+	xmlSetProp (value, (xmlChar *)"type", (xmlChar *)"datespec");
+
+	work = xmlNewChild (value, NULL, (xmlChar *)"datespec", NULL);
+	sprintf (str, "%d", fds->type);
+	xmlSetProp (work, (xmlChar *)"type", (xmlChar *)str);
+	sprintf (str, "%d", (gint)fds->value);
+	xmlSetProp (work, (xmlChar *)"value", (xmlChar *)str);
+
+	return value;
+}
+
+static gint
+filter_datespec_xml_decode (EFilterElement *element,
+                            xmlNodePtr node)
+{
+	EFilterDatespec *fds = E_FILTER_DATESPEC (element);
+	xmlNodePtr n;
+	xmlChar *val;
+
+	d(printf ("Decoding datespec from xml %p\n", element));
+
+	xmlFree (element->name);
+	element->name = (gchar *)xmlGetProp (node, (xmlChar *)"name");
+
+	n = node->children;
+	while (n) {
+		if (!strcmp ((gchar *)n->name, "datespec")) {
+			val = xmlGetProp (n, (xmlChar *)"type");
+			fds->type = atoi ((gchar *)val);
+			xmlFree (val);
+			val = xmlGetProp (n, (xmlChar *)"value");
+			fds->value = atoi ((gchar *)val);
+			xmlFree (val);
+			break;
+		}
+		n = n->next;
+	}
+
+	return 0;
+}
+
 static GtkWidget *
-get_widget (FilterElement *fe)
+filter_datespec_get_widget (EFilterElement *element)
 {
-	FilterDatespec *fds = (FilterDatespec *)fe;
+	EFilterDatespec *fds = E_FILTER_DATESPEC (element);
 	GtkWidget *button;
 
 	fds->priv->label_button = gtk_label_new ("");
@@ -486,15 +402,10 @@ get_widget (FilterElement *fe)
 }
 
 static void
-build_code (FilterElement *fe, GString *out, struct _FilterPart *fp)
-{
-	return;
-}
-
-static void
-format_sexp (FilterElement *fe, GString *out)
+filter_datespec_format_sexp (EFilterElement *element,
+                             GString *out)
 {
-	FilterDatespec *fds = (FilterDatespec *)fe;
+	EFilterDatespec *fds = E_FILTER_DATESPEC (element);
 
 	switch (fds->type) {
 	case FDST_UNKNOWN:
@@ -507,10 +418,75 @@ format_sexp (FilterElement *fe, GString *out)
 		g_string_append_printf (out, "%d", (gint) fds->value);
 		break;
 	case FDST_X_AGO:
-		g_string_append_printf (out, "(- (get-current-date) %d)", (gint) fds->value);
+		g_string_append_printf (
+			out, "(- (get-current-date) %d)", (gint) fds->value);
 		break;
 	case FDST_X_FUTURE:
-		g_string_append_printf (out, "(+ (get-current-date) %d)", (gint) fds->value);
+		g_string_append_printf (
+			out, "(+ (get-current-date) %d)", (gint) fds->value);
 		break;
 	}
 }
+
+static void
+filter_datespec_class_init (EFilterDatespecClass *class)
+{
+	EFilterElementClass *filter_element_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EFilterDatespecPrivate));
+
+	filter_element_class = E_FILTER_ELEMENT_CLASS (class);
+	filter_element_class->validate = filter_datespec_validate;
+	filter_element_class->eq = filter_datespec_eq;
+	filter_element_class->xml_encode = filter_datespec_xml_encode;
+	filter_element_class->xml_decode = filter_datespec_xml_decode;
+	filter_element_class->get_widget = filter_datespec_get_widget;
+	filter_element_class->format_sexp = filter_datespec_format_sexp;
+}
+
+static void
+filter_datespec_init (EFilterDatespec *datespec)
+{
+	datespec->priv = E_FILTER_DATESPEC_GET_PRIVATE (datespec);
+	datespec->type = FDST_UNKNOWN;
+}
+
+GType
+e_filter_datespec_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EFilterDatespecClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) filter_datespec_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EFilterDatespec),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) filter_datespec_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			E_TYPE_FILTER_ELEMENT, "EFilterDatespec", &type_info, 0);
+	}
+
+	return type;
+}
+
+/**
+ * filter_datespec_new:
+ *
+ * Create a new EFilterDatespec object.
+ *
+ * Return value: A new #EFilterDatespec object.
+ **/
+EFilterDatespec *
+e_filter_datespec_new (void)
+{
+	return g_object_new (E_TYPE_FILTER_DATESPEC, NULL);
+}
diff --git a/filter/e-filter-datespec.h b/filter/e-filter-datespec.h
new file mode 100644
index 0000000..aed978a
--- /dev/null
+++ b/filter/e-filter-datespec.h
@@ -0,0 +1,87 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_FILTER_DATESPEC_H
+#define E_FILTER_DATESPEC_H
+
+#include <time.h>
+#include "e-filter-element.h"
+
+/* Standard GObject types */
+#define E_TYPE_FILTER_DATESPEC \
+	(e_filter_datespec_get_type ())
+#define E_FILTER_DATESPEC(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_FILTER_DATESPEC, EFilterDatespec))
+#define E_FILTER_DATESPEC_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_FILTER_DATESPEC, EFilterDatespecClass))
+#define E_IS_FILTER_DATESPEC(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_FILTER_DATESPEC))
+#define E_IS_FILTER_DATESPEC_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_FILTER_DATESPEC))
+#define E_FILTER_DATESPEC_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_FILTER_DATESPEC, EFilterDatespecClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EFilterDatespec EFilterDatespec;
+typedef struct _EFilterDatespecClass EFilterDatespecClass;
+typedef struct _EFilterDatespecPrivate EFilterDatespecPrivate;
+
+typedef enum {
+	FDST_UNKNOWN = -1,
+	FDST_NOW,
+	FDST_SPECIFIED,
+	FDST_X_AGO,
+	FDST_X_FUTURE
+} EFilterDatespecType;
+
+struct _EFilterDatespec {
+	EFilterElement parent;
+	EFilterDatespecPrivate *priv;
+
+	EFilterDatespecType type;
+
+	/* either a timespan, an absolute time, or 0
+	 * depending on type -- the above mapping to
+	 * (X_FUTURE, X_AGO, SPECIFIED, NOW)
+	 */
+
+	time_t value;
+};
+
+struct _EFilterDatespecClass {
+	EFilterElementClass parent_class;
+};
+
+GType		e_filter_datespec_get_type	(void);
+EFilterDatespec *
+		e_filter_datespec_new		(void);
+
+G_END_DECLS
+
+#endif /* E_FILTER_DATESPEC_H */
diff --git a/filter/e-filter-element.c b/filter/e-filter-element.c
new file mode 100644
index 0000000..707692e
--- /dev/null
+++ b/filter/e-filter-element.c
@@ -0,0 +1,472 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "e-filter-element.h"
+#include "e-filter-part.h"
+
+struct _element_type {
+	gchar *name;
+
+	EFilterElementFunc create;
+	gpointer data;
+};
+
+static gpointer parent_class;
+
+static gboolean
+filter_element_validate (EFilterElement *element,
+                         GtkWindow *error_parent)
+{
+	return TRUE;
+}
+
+static gint
+filter_element_eq (EFilterElement *element_a,
+                   EFilterElement *element_b)
+{
+	return (g_strcmp0 (element_a->name, element_b->name) == 0);
+}
+
+static void
+filter_element_xml_create (EFilterElement *element,
+                           xmlNodePtr node)
+{
+	element->name = (gchar *)xmlGetProp (node, (xmlChar *) "name");
+}
+
+static EFilterElement *
+filter_element_clone (EFilterElement *element)
+{
+	EFilterElement *clone;
+	xmlNodePtr node;
+
+	clone = g_object_new (G_OBJECT_TYPE (element), NULL);
+
+	node = e_filter_element_xml_encode (element);
+	e_filter_element_xml_decode (clone, node);
+	xmlFreeNodeList (node);
+
+	return clone;
+}
+
+/* This is somewhat hackish, implement all the base cases in here */
+#include "e-filter-input.h"
+#include "e-filter-option.h"
+#include "e-filter-code.h"
+#include "e-filter-color.h"
+#include "e-filter-datespec.h"
+#include "e-filter-int.h"
+#include "e-filter-file.h"
+
+static void
+filter_element_copy_value (EFilterElement *dst_element,
+                           EFilterElement *src_element)
+{
+	if (E_IS_FILTER_INPUT (src_element)) {
+		EFilterInput *src_input;
+
+		src_input = E_FILTER_INPUT (src_element);
+
+		if (E_IS_FILTER_INPUT (dst_element)) {
+			EFilterInput *dst_input;
+
+			dst_input = E_FILTER_INPUT (dst_element);
+
+			if (src_input->values)
+				e_filter_input_set_value (
+					dst_input,
+					src_input->values->data);
+
+		} else if (E_IS_FILTER_INT (dst_element)) {
+			EFilterInt *dst_int;
+
+			dst_int = E_FILTER_INT (dst_element);
+
+			dst_int->val = atoi (src_input->values->data);
+		}
+
+	} else if (E_IS_FILTER_COLOR (src_element)) {
+		EFilterColor *src_color;
+
+		src_color = E_FILTER_COLOR (src_element);
+
+		if (E_IS_FILTER_COLOR (dst_element)) {
+			EFilterColor *dst_color;
+
+			dst_color = E_FILTER_COLOR (dst_element);
+
+			dst_color->color = src_color->color;
+		}
+
+	} else if (E_IS_FILTER_DATESPEC (src_element)) {
+		EFilterDatespec *src_datespec;
+
+		src_datespec = E_FILTER_DATESPEC (src_element);
+
+		if (E_IS_FILTER_DATESPEC (dst_element)) {
+			EFilterDatespec *dst_datespec;
+
+			dst_datespec = E_FILTER_DATESPEC (dst_element);
+
+			dst_datespec->type = src_datespec->type;
+			dst_datespec->value = src_datespec->value;
+		}
+
+	} else if (E_IS_FILTER_INT (src_element)) {
+		EFilterInt *src_int;
+
+		src_int = E_FILTER_INT (src_element);
+
+		if (E_IS_FILTER_INT (dst_element)) {
+			EFilterInt *dst_int;
+
+			dst_int = E_FILTER_INT (dst_element);
+
+			dst_int->val = src_int->val;
+
+		} else if (E_IS_FILTER_INPUT (dst_element)) {
+			EFilterInput *dst_input;
+			gchar *values;
+
+			dst_input = E_FILTER_INPUT (dst_element);
+
+			values = g_strdup_printf ("%d", src_int->val);
+			e_filter_input_set_value (dst_input, values);
+			g_free (values);
+		}
+
+	} else if (E_IS_FILTER_OPTION (src_element)) {
+		EFilterOption *src_option;
+
+		src_option = E_FILTER_OPTION (src_element);
+
+		if (E_IS_FILTER_OPTION (dst_element)) {
+			EFilterOption *dst_option;
+
+			dst_option = E_FILTER_OPTION (dst_element);
+
+			if (src_option->current)
+				e_filter_option_set_current (
+					dst_option,
+					src_option->current->value);
+		}
+	}
+}
+
+static void
+filter_element_finalize (GObject *object)
+{
+	EFilterElement *element = E_FILTER_ELEMENT (object);
+
+	xmlFree (element->name);
+
+	/* Chain up to parent's finalize () method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+filter_element_class_init (EFilterElementClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = filter_element_finalize;
+
+	class->validate = filter_element_validate;
+	class->eq = filter_element_eq;
+	class->xml_create = filter_element_xml_create;
+	class->clone = filter_element_clone;
+	class->copy_value = filter_element_copy_value;
+}
+
+GType
+e_filter_element_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EFilterElementClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) filter_element_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EFilterElement),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) NULL,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			G_TYPE_OBJECT, "EFilterElement", &type_info, 0);
+	}
+
+	return type;
+}
+
+/**
+ * filter_element_new:
+ *
+ * Create a new EFilterElement object.
+ *
+ * Return value: A new #EFilterElement object.
+ **/
+EFilterElement *
+e_filter_element_new (void)
+{
+	return g_object_new (E_TYPE_FILTER_ELEMENT, NULL);
+}
+
+gboolean
+e_filter_element_validate (EFilterElement *element,
+                           GtkWindow *error_parent)
+{
+	EFilterElementClass *class;
+
+	g_return_val_if_fail (E_IS_FILTER_ELEMENT (element), FALSE);
+
+	/* Warn but proceed if no parent window was given. */
+	if (error_parent != NULL)
+		g_return_val_if_fail (GTK_IS_WINDOW (error_parent), FALSE);
+	else
+		g_warning ("%s() called with no parent window", G_STRFUNC);
+
+	class = E_FILTER_ELEMENT_GET_CLASS (element);
+	g_return_val_if_fail (class->validate != NULL, FALSE);
+
+	return class->validate (element, error_parent);
+}
+
+gint
+e_filter_element_eq (EFilterElement *element_a,
+                     EFilterElement *element_b)
+{
+	EFilterElementClass *class;
+
+	g_return_val_if_fail (E_IS_FILTER_ELEMENT (element_a), FALSE);
+	g_return_val_if_fail (E_IS_FILTER_ELEMENT (element_b), FALSE);
+
+	/* The elements must be the same type. */
+	if (G_OBJECT_TYPE (element_a) != G_OBJECT_TYPE (element_b))
+		return FALSE;
+
+	class = E_FILTER_ELEMENT_GET_CLASS (element_a);
+	g_return_val_if_fail (class->eq != NULL, FALSE);
+
+	return class->eq (element_a, element_b);
+}
+
+/**
+ * filter_element_xml_create:
+ * @fe: filter element
+ * @node: xml node
+ *
+ * Create a new filter element based on an xml definition of
+ * that element.
+ **/
+void
+e_filter_element_xml_create (EFilterElement *element,
+                             xmlNodePtr node)
+{
+	EFilterElementClass *class;
+
+	g_return_if_fail (E_IS_FILTER_ELEMENT (element));
+	g_return_if_fail (node != NULL);
+
+	class = E_FILTER_ELEMENT_GET_CLASS (element);
+	g_return_if_fail (class->xml_create != NULL);
+
+	class->xml_create (element, node);
+}
+
+/**
+ * filter_element_xml_encode:
+ * @fe: filter element
+ *
+ * Encode the values of a filter element into xml format.
+ *
+ * Return value:
+ **/
+xmlNodePtr
+e_filter_element_xml_encode (EFilterElement *element)
+{
+	EFilterElementClass *class;
+
+	g_return_val_if_fail (E_IS_FILTER_ELEMENT (element), NULL);
+
+	class = E_FILTER_ELEMENT_GET_CLASS (element);
+	g_return_val_if_fail (class->xml_encode != NULL, NULL);
+
+	return class->xml_encode (element);
+}
+
+/**
+ * filter_element_xml_decode:
+ * @fe: filter element
+ * @node: xml node
+ *
+ * Decode the values of a fitler element from xml format.
+ *
+ * Return value:
+ **/
+gint
+e_filter_element_xml_decode (EFilterElement *element,
+                             xmlNodePtr node)
+{
+	EFilterElementClass *class;
+
+	g_return_val_if_fail (E_IS_FILTER_ELEMENT (element), FALSE);
+	g_return_val_if_fail (node != NULL, FALSE);
+
+	class = E_FILTER_ELEMENT_GET_CLASS (element);
+	g_return_val_if_fail (class->xml_decode != NULL, FALSE);
+
+	return class->xml_decode (element, node);
+}
+
+/**
+ * filter_element_clone:
+ * @fe: filter element
+ *
+ * Clones the EFilterElement @fe.
+ *
+ * Return value:
+ **/
+EFilterElement *
+e_filter_element_clone (EFilterElement *element)
+{
+	EFilterElementClass *class;
+
+	g_return_val_if_fail (E_IS_FILTER_ELEMENT (element), NULL);
+
+	class = E_FILTER_ELEMENT_GET_CLASS (element);
+	g_return_val_if_fail (class->clone != NULL, NULL);
+
+	return class->clone (element);
+}
+
+/**
+ * filter_element_get_widget:
+ * @fe: filter element
+ * @node: xml node
+ *
+ * Create a widget to represent this element.
+ *
+ * Return value:
+ **/
+GtkWidget *
+e_filter_element_get_widget (EFilterElement *element)
+{
+	EFilterElementClass *class;
+
+	g_return_val_if_fail (E_IS_FILTER_ELEMENT (element), NULL);
+
+	class = E_FILTER_ELEMENT_GET_CLASS (element);
+	g_return_val_if_fail (class->get_widget != NULL, NULL);
+
+	return class->get_widget (element);
+}
+
+/**
+ * filter_element_build_code:
+ * @fe: filter element
+ * @out: output buffer
+ * @ff:
+ *
+ * Add the code representing this element to the output string @out.
+ **/
+void
+e_filter_element_build_code (EFilterElement *element,
+                             GString *out,
+                             EFilterPart *part)
+{
+	EFilterElementClass *class;
+
+	g_return_if_fail (E_IS_FILTER_ELEMENT (element));
+	g_return_if_fail (out != NULL);
+	g_return_if_fail (E_IS_FILTER_PART (part));
+
+	class = E_FILTER_ELEMENT_GET_CLASS (element);
+
+	/* This method is optional. */
+	if (class->build_code != NULL)
+		class->build_code (element, out, part);
+}
+
+/**
+ * filter_element_format_sexp:
+ * @fe: filter element
+ * @out: output buffer
+ *
+ * Format the value(s) of this element in a method suitable for the context of
+ * sexp where it is used.  Usually as space separated, double-quoted strings.
+ **/
+void
+e_filter_element_format_sexp (EFilterElement *element,
+                              GString *out)
+{
+	EFilterElementClass *class;
+
+	g_return_if_fail (E_IS_FILTER_ELEMENT (element));
+	g_return_if_fail (out != NULL);
+
+	class = E_FILTER_ELEMENT_GET_CLASS (element);
+	g_return_if_fail (class->format_sexp != NULL);
+
+	class->format_sexp (element, out);
+}
+
+void
+e_filter_element_set_data (EFilterElement *element,
+                           gpointer data)
+{
+	g_return_if_fail (E_IS_FILTER_ELEMENT (element));
+
+	element->data = data;
+}
+
+/* only copies the value, not the name/type */
+void
+e_filter_element_copy_value (EFilterElement *dst_element,
+                             EFilterElement *src_element)
+{
+	EFilterElementClass *class;
+
+	g_return_if_fail (E_IS_FILTER_ELEMENT (dst_element));
+	g_return_if_fail (E_IS_FILTER_ELEMENT (src_element));
+
+	class = E_FILTER_ELEMENT_GET_CLASS (dst_element);
+	g_return_if_fail (class->copy_value != NULL);
+
+	class->copy_value (dst_element, src_element);
+}
diff --git a/filter/e-filter-element.h b/filter/e-filter-element.h
new file mode 100644
index 0000000..589d3a4
--- /dev/null
+++ b/filter/e-filter-element.h
@@ -0,0 +1,118 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_FILTER_ELEMENT_H
+#define E_FILTER_ELEMENT_H
+
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <libxml/xmlmemory.h>
+
+#define E_TYPE_FILTER_ELEMENT \
+	(e_filter_element_get_type ())
+#define E_FILTER_ELEMENT(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_FILTER_ELEMENT, EFilterElement))
+#define E_FILTER_ELEMENT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_FILTER_ELEMENT, EFilterElementClass))
+#define E_IS_FILTER_ELEMENT(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_FILTER_ELEMENT))
+#define E_IS_FILTER_ELEMENT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_FILTER_ELEMENT))
+#define E_FILTER_ELEMENT_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_FILTER_ELEMENT, EFilterElementClass))
+
+G_BEGIN_DECLS
+
+struct _EFilterPart;
+
+typedef struct _EFilterElement EFilterElement;
+typedef struct _EFilterElementClass EFilterElementClass;
+typedef struct _EFilterElementPrivate EFilterElementPrivate;
+
+typedef EFilterElement * (*EFilterElementFunc) (gpointer data);
+
+struct _EFilterElement {
+	GObject parent;
+	EFilterElementPrivate *priv;
+
+	gchar *name;
+	gpointer data;
+};
+
+struct _EFilterElementClass {
+	GObjectClass parent_class;
+
+	gboolean	(*validate)		(EFilterElement *element,
+						 GtkWindow *error_parent);
+	gint		(*eq)			(EFilterElement *element_a,
+						 EFilterElement *element_b);
+
+	void		(*xml_create)		(EFilterElement *element,
+						 xmlNodePtr node);
+	xmlNodePtr	(*xml_encode)		(EFilterElement *element);
+	gint		(*xml_decode)		(EFilterElement *element,
+						 xmlNodePtr node);
+
+	EFilterElement *(*clone)		(EFilterElement *element);
+	void		(*copy_value)		(EFilterElement *dst_element,
+						 EFilterElement *src_element);
+
+	GtkWidget *	(*get_widget)		(EFilterElement *element);
+	void		(*build_code)		(EFilterElement *element,
+						 GString *out,
+						 struct _EFilterPart *part);
+	void		(*format_sexp)		(EFilterElement *element,
+						 GString *out);
+};
+
+GType		e_filter_element_get_type	(void);
+EFilterElement	*e_filter_element_new		(void);
+void		e_filter_element_set_data	(EFilterElement *element,
+						 gpointer data);
+gboolean	e_filter_element_validate	(EFilterElement *element,
+						 GtkWindow *error_parent);
+gint		e_filter_element_eq		(EFilterElement *element_a,
+						 EFilterElement *element_b);
+void		e_filter_element_xml_create	(EFilterElement *element,
+						 xmlNodePtr node);
+xmlNodePtr	e_filter_element_xml_encode	(EFilterElement *element);
+gint		e_filter_element_xml_decode	(EFilterElement *element,
+						 xmlNodePtr node);
+EFilterElement *e_filter_element_clone		(EFilterElement *element);
+void		e_filter_element_copy_value	(EFilterElement *dst_element,
+						 EFilterElement *src_element);
+GtkWidget *	e_filter_element_get_widget	(EFilterElement *element);
+void		e_filter_element_build_code	(EFilterElement *element,
+						 GString *out,
+						 struct _EFilterPart *part);
+void		e_filter_element_format_sexp	(EFilterElement *element,
+						 GString *out);
+
+G_END_DECLS
+
+#endif /* E_FILTER_ELEMENT_H */
diff --git a/filter/e-filter-file.c b/filter/e-filter-file.c
new file mode 100644
index 0000000..6364475
--- /dev/null
+++ b/filter/e-filter-file.c
@@ -0,0 +1,278 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/types.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+#include <libedataserver/e-sexp.h>
+
+#include "e-util/e-error.h"
+
+#include "e-filter-file.h"
+#include "e-filter-part.h"
+
+static gpointer parent_class;
+
+static void
+filter_file_filename_changed (GtkFileChooser *file_chooser,
+                              EFilterElement *element)
+{
+	EFilterFile *file = E_FILTER_FILE (element);
+	const gchar *path;
+
+	path = gtk_file_chooser_get_filename (file_chooser);
+
+	g_free (file->path);
+	file->path = g_strdup (path);
+}
+
+static void
+filter_file_finalize (GObject *object)
+{
+	EFilterFile *file = E_FILTER_FILE (object);
+
+	xmlFree (file->type);
+	g_free (file->path);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+filter_file_validate (EFilterElement *element,
+                      GtkWindow *error_parent)
+{
+	EFilterFile *file = E_FILTER_FILE (element);
+
+	if (!file->path) {
+		e_error_run (error_parent, "filter:no-file", NULL);
+		return FALSE;
+	}
+
+	/* FIXME: do more to validate command-lines? */
+
+	if (g_strcmp0 (file->type, "file") == 0) {
+		if (!g_file_test (file->path, G_FILE_TEST_IS_REGULAR)) {
+			e_error_run (
+				error_parent, "filter:bad-file",
+				file->path, NULL);
+			return FALSE;
+		}
+	} else if (g_strcmp0 (file->type, "command") == 0) {
+		/* Only requirements so far is that the
+		 * command can't be an empty string. */
+		return (file->path[0] != '\0');
+	}
+
+	return TRUE;
+}
+
+static gint
+filter_file_eq (EFilterElement *element_a,
+                EFilterElement *element_b)
+{
+	EFilterFile *file_a = E_FILTER_FILE (element_a);
+	EFilterFile *file_b = E_FILTER_FILE (element_b);
+
+	/* Chain up to parent's eq() method. */
+	if (!E_FILTER_ELEMENT_CLASS (parent_class)->eq (element_a, element_b))
+		return FALSE;
+
+	if (g_strcmp0 (file_a->path, file_b->path) != 0)
+		return FALSE;
+
+	if (g_strcmp0 (file_a->type, file_b->type) != 0)
+		return FALSE;
+
+	return TRUE;
+}
+
+static xmlNodePtr
+filter_file_xml_encode (EFilterElement *element)
+{
+	EFilterFile *file = E_FILTER_FILE (element);
+	xmlNodePtr cur, value;
+	const gchar *type;
+
+	type = file->type ? file->type : "file";
+
+	value = xmlNewNode (NULL, (xmlChar *)"value");
+	xmlSetProp (value, (xmlChar *) "name", (xmlChar *) element->name);
+	xmlSetProp (value, (xmlChar *) "type", (xmlChar *) type);
+
+	cur = xmlNewChild (value, NULL, (xmlChar *)type, NULL);
+	xmlNodeSetContent (cur, (xmlChar *)file->path);
+
+	return value;
+}
+
+static gint
+filter_file_xml_decode (EFilterElement *element,
+                        xmlNodePtr node)
+{
+	EFilterFile *file = E_FILTER_FILE (element);
+	gchar *name, *str, *type;
+	xmlNodePtr child;
+
+	name = (gchar *)xmlGetProp (node, (xmlChar *) "name");
+	type = (gchar *)xmlGetProp (node, (xmlChar *) "type");
+
+	xmlFree (element->name);
+	element->name = name;
+
+	xmlFree (file->type);
+	file->type = type;
+
+	g_free (file->path);
+	file->path = NULL;
+
+	child = node->children;
+	while (child != NULL) {
+		if (!strcmp ((gchar *)child->name, type)) {
+			str = (gchar *)xmlNodeGetContent (child);
+			file->path = g_strdup (str ? str : "");
+			xmlFree (str);
+
+			break;
+		} else if (child->type == XML_ELEMENT_NODE) {
+			g_warning (
+				"Unknown node type '%s' encountered "
+				"decoding a %s\n", child->name, type);
+		}
+
+		child = child->next;
+	}
+
+	return 0;
+}
+
+static GtkWidget *
+filter_file_get_widget (EFilterElement *element)
+{
+	EFilterFile *file = E_FILTER_FILE (element);
+	GtkWidget *widget;
+
+	widget = gtk_file_chooser_button_new (
+		_("Choose a File"), GTK_FILE_CHOOSER_ACTION_OPEN);
+	gtk_file_chooser_set_filename (
+		GTK_FILE_CHOOSER (widget), file->path);
+	g_signal_connect (
+		widget, "selection-changed",
+		G_CALLBACK (filter_file_filename_changed), element);
+
+	return widget;
+}
+
+static void
+filter_file_format_sexp (EFilterElement *element,
+                         GString *out)
+{
+	EFilterFile *file = E_FILTER_FILE (element);
+
+	e_sexp_encode_string (out, file->path);
+}
+
+static void
+filter_file_class_init (EFilterFileClass *class)
+{
+	GObjectClass *object_class;
+	EFilterElementClass *filter_element_class;
+
+	parent_class = g_type_class_peek_parent (class);
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = filter_file_finalize;
+
+	filter_element_class = E_FILTER_ELEMENT_CLASS (class);
+	filter_element_class->validate = filter_file_validate;
+	filter_element_class->eq = filter_file_eq;
+	filter_element_class->xml_encode = filter_file_xml_encode;
+	filter_element_class->xml_decode = filter_file_xml_decode;
+	filter_element_class->get_widget = filter_file_get_widget;
+	filter_element_class->format_sexp = filter_file_format_sexp;
+}
+
+GType
+e_filter_file_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EFilterFileClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) filter_file_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EFilterFile),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) NULL,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			E_TYPE_FILTER_ELEMENT, "EFilterFile", &type_info, 0);
+	}
+
+	return type;
+}
+
+/**
+ * filter_file_new:
+ *
+ * Create a new EFilterFile object.
+ *
+ * Return value: A new #EFilterFile object.
+ **/
+EFilterFile *
+e_filter_file_new (void)
+{
+	return g_object_new (E_TYPE_FILTER_FILE, NULL);
+}
+
+EFilterFile *
+e_filter_file_new_type_name (const gchar *type)
+{
+	EFilterFile *file;
+
+	file = e_filter_file_new ();
+	file->type = (gchar *) xmlStrdup ((xmlChar *)type);
+
+	return file;
+}
+
+void
+e_filter_file_set_path (EFilterFile *file,
+                        const gchar *path)
+{
+	g_return_if_fail (E_IS_FILTER_FILE (file));
+
+	g_free (file->path);
+	file->path = g_strdup (path);
+}
diff --git a/filter/e-filter-file.h b/filter/e-filter-file.h
new file mode 100644
index 0000000..6f7946e
--- /dev/null
+++ b/filter/e-filter-file.h
@@ -0,0 +1,74 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_FILTER_FILE_H
+#define E_FILTER_FILE_H
+
+#include "e-filter-element.h"
+
+/* Standard GObject macros */
+#define E_TYPE_FILTER_FILE \
+	(e_filter_file_get_type ())
+#define E_FILTER_FILE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_FILTER_FILE, EFilterFile))
+#define E_FILTER_FILE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_FILTER_FILE, EFilterFileClass))
+#define E_IS_FILTER_FILE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_FILTER_FILE))
+#define E_IS_FILTER_FILE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_FILTER_FILE))
+#define E_FILTER_FILE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_FILTER_FILE, EFilterFileClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EFilterFile EFilterFile;
+typedef struct _EFilterFileClass EFilterFileClass;
+typedef struct _EFilterFilePrivate EFilterFilePrivate;
+
+struct _EFilterFile {
+	EFilterElement parent;
+	EFilterFilePrivate *priv;
+
+	gchar *type;
+	gchar *path;
+};
+
+struct _EFilterFileClass {
+	EFilterElementClass parent_class;
+};
+
+GType		e_filter_file_get_type		(void);
+EFilterFile *	e_filter_file_new		(void);
+EFilterFile *	e_filter_file_new_type_name	(const gchar *type);
+void		e_filter_file_set_path		(EFilterFile *file,
+						 const gchar *path);
+
+G_END_DECLS
+
+#endif /* E_FILTER_FILE_H */
diff --git a/filter/e-filter-input.c b/filter/e-filter-input.c
new file mode 100644
index 0000000..a8d6123
--- /dev/null
+++ b/filter/e-filter-input.c
@@ -0,0 +1,322 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include <libedataserver/e-sexp.h>
+
+#include "e-util/e-error.h"
+
+#include "e-filter-input.h"
+
+static gpointer parent_class;
+
+static void
+filter_input_entry_changed (GtkEntry *entry,
+                            EFilterElement *element)
+{
+	EFilterInput *input = E_FILTER_INPUT (element);
+	const gchar *text;
+
+	g_list_foreach (input->values, (GFunc) g_free, NULL);
+	g_list_free (input->values);
+
+	text = gtk_entry_get_text (entry);
+	input->values = g_list_append (NULL, g_strdup (text));
+}
+
+static void
+filter_input_finalize (GObject *object)
+{
+	EFilterInput *input = E_FILTER_INPUT (object);
+
+	xmlFree (input->type);
+
+	g_list_foreach (input->values, (GFunc)g_free, NULL);
+	g_list_free (input->values);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+filter_input_validate (EFilterElement *element,
+                       GtkWindow *error_parent)
+{
+	EFilterInput *input = E_FILTER_INPUT (element);
+	gboolean valid = TRUE;
+
+	if (input->values && !strcmp (input->type, "regex")) {
+		const gchar *pattern;
+		regex_t regexpat;
+		gint regerr;
+
+		pattern = input->values->data;
+
+		if ((regerr = regcomp (&regexpat, pattern, REG_EXTENDED | REG_NEWLINE | REG_ICASE))) {
+			gsize reglen;
+			gchar *regmsg;
+
+			/* regerror gets called twice to get the full error string
+			   length to do proper posix error reporting */
+			reglen = regerror (regerr, &regexpat, 0, 0);
+			regmsg = g_malloc0 (reglen + 1);
+			regerror (regerr, &regexpat, regmsg, reglen);
+
+			e_error_run (error_parent, "filter:bad-regexp", pattern, regmsg, NULL);
+			g_free (regmsg);
+
+			valid = FALSE;
+		}
+
+		regfree (&regexpat);
+	}
+
+	return valid;
+}
+
+static gint
+filter_input_eq (EFilterElement *element_a,
+                 EFilterElement *element_b)
+{
+	EFilterInput *input_a = E_FILTER_INPUT (element_a);
+	EFilterInput *input_b = E_FILTER_INPUT (element_b);
+	GList *link_a;
+	GList *link_b;
+
+	/* Chain up to parent's eq() method. */
+	if (!E_FILTER_ELEMENT_CLASS (parent_class)->eq (element_a, element_b))
+		return FALSE;
+
+	if (g_strcmp0 (input_a->type, input_b->type) != 0)
+		return FALSE;
+
+	link_a = input_a->values;
+	link_b = input_b->values;
+
+	while (link_a != NULL && link_b != NULL) {
+		if (g_strcmp0 (link_a->data, link_b->data) != 0)
+			return FALSE;
+
+		link_a = g_list_next (link_a);
+		link_b = g_list_next (link_b);
+	}
+
+	if (link_a != NULL || link_b != NULL)
+		return FALSE;
+
+	return TRUE;
+}
+
+static xmlNodePtr
+filter_input_xml_encode (EFilterElement *element)
+{
+	EFilterInput *input = E_FILTER_INPUT (element);
+	xmlNodePtr value;
+	GList *link;
+	const gchar *type;
+
+	type = input->type ? input->type : "string";
+
+	value = xmlNewNode (NULL, (xmlChar *) "value");
+	xmlSetProp (value, (xmlChar *) "name", (xmlChar *) element->name);
+	xmlSetProp (value, (xmlChar *) "type", (xmlChar *) type);
+
+	for (link = input->values; link != NULL; link = g_list_next (link)) {
+		xmlChar *str = link->data;
+		xmlNodePtr cur;
+
+                cur = xmlNewChild (value, NULL, (xmlChar *)type, NULL);
+
+		str = xmlEncodeEntitiesReentrant (NULL, str);
+		xmlNodeSetContent (cur, str);
+		xmlFree (str);
+	}
+
+	return value;
+}
+
+static gint
+filter_input_xml_decode (EFilterElement *element, xmlNodePtr node)
+{
+	EFilterInput *input = (EFilterInput *)element;
+	gchar *name, *str, *type;
+	xmlNodePtr child;
+
+	g_list_foreach (input->values, (GFunc) g_free, NULL);
+	g_list_free (input->values);
+	input->values = NULL;
+
+	name = (gchar *) xmlGetProp (node, (xmlChar *) "name");
+	type = (gchar *) xmlGetProp (node, (xmlChar *) "type");
+
+	xmlFree (element->name);
+	element->name = name;
+
+	xmlFree (input->type);
+	input->type = type;
+
+	child = node->children;
+	while (child != NULL) {
+		if (!strcmp ((gchar *)child->name, type)) {
+			if (!(str = (gchar *)xmlNodeGetContent (child)))
+				str = (gchar *)xmlStrdup ((xmlChar *)"");
+
+			input->values = g_list_append (input->values, g_strdup (str));
+			xmlFree (str);
+		} else if (child->type == XML_ELEMENT_NODE) {
+			g_warning (
+				"Unknown node type '%s' encountered "
+				"decoding a %s\n", child->name, type);
+		}
+		child = child->next;
+	}
+
+	return 0;
+}
+
+static GtkWidget *
+filter_input_get_widget (EFilterElement *element)
+{
+	EFilterInput *input = E_FILTER_INPUT (element);
+	GtkWidget *entry;
+
+	entry = gtk_entry_new ();
+	if (input->values && input->values->data)
+		gtk_entry_set_text (
+			GTK_ENTRY (entry), input->values->data);
+
+	g_signal_connect (
+		entry, "changed",
+		G_CALLBACK (filter_input_entry_changed), element);
+
+	return entry;
+}
+
+static void
+filter_input_format_sexp (EFilterElement *element,
+                          GString *out)
+{
+	EFilterInput *input = E_FILTER_INPUT (element);
+	GList *link;
+
+	for (link = input->values; link != NULL; link = g_list_next (link))
+		e_sexp_encode_string (out, link->data);
+}
+
+static void
+filter_input_class_init (EFilterInputClass *class)
+{
+	GObjectClass *object_class;
+	EFilterElementClass *filter_element_class;
+
+	parent_class = g_type_class_peek_parent (class);
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = filter_input_finalize;
+
+	filter_element_class = E_FILTER_ELEMENT_CLASS (class);
+	filter_element_class->validate = filter_input_validate;
+	filter_element_class->eq = filter_input_eq;
+	filter_element_class->xml_encode = filter_input_xml_encode;
+	filter_element_class->xml_decode = filter_input_xml_decode;
+	filter_element_class->get_widget = filter_input_get_widget;
+	filter_element_class->format_sexp = filter_input_format_sexp;
+}
+
+static void
+filter_input_init (EFilterInput *input)
+{
+	input->values = g_list_prepend (NULL, g_strdup (""));
+}
+
+GType
+e_filter_input_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EFilterInputClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) filter_input_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EFilterInput),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) filter_input_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			E_TYPE_FILTER_ELEMENT, "EFilterInput", &type_info, 0);
+	}
+
+	return type;
+}
+
+/**
+ * filter_input_new:
+ *
+ * Create a new EFilterInput object.
+ *
+ * Return value: A new #EFilterInput object.
+ **/
+EFilterInput *
+e_filter_input_new (void)
+{
+	return g_object_new (E_TYPE_FILTER_INPUT, NULL);
+}
+
+EFilterInput *
+e_filter_input_new_type_name (const gchar *type)
+{
+	EFilterInput *input;
+
+	input = e_filter_input_new ();
+	input->type = (gchar *) xmlStrdup ((xmlChar *) type);
+
+	return input;
+}
+
+void
+e_filter_input_set_value (EFilterInput *input,
+                          const gchar *value)
+{
+	g_return_if_fail (E_IS_FILTER_INPUT (input));
+
+	g_list_foreach (input->values, (GFunc) g_free, NULL);
+	g_list_free (input->values);
+
+	input->values = g_list_append (NULL, g_strdup (value));
+}
diff --git a/filter/e-filter-input.h b/filter/e-filter-input.h
new file mode 100644
index 0000000..07239c9
--- /dev/null
+++ b/filter/e-filter-input.h
@@ -0,0 +1,74 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_FILTER_INPUT_H
+#define E_FILTER_INPUT_H
+
+#include "e-filter-element.h"
+
+/* Standard GObject macros */
+#define E_TYPE_FILTER_INPUT \
+	(e_filter_input_get_type ())
+#define E_FILTER_INPUT(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_FILTER_INPUT, EFilterInput))
+#define E_FILTER_INPUT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_FILTER_INPUT, EFilterInputClass))
+#define E_IS_FILTER_INPUT(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_FILTER_INPUT))
+#define E_IS_FILTER_INPUT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_FILTER_INPUT))
+#define E_FILTER_INPUT_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_FILTER_INPUT, EFilterInputClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EFilterInput EFilterInput;
+typedef struct _EFilterInputClass EFilterInputClass;
+typedef struct _EFilterInputPrivate EFilterInputPrivate;
+
+struct _EFilterInput {
+	EFilterElement parent;
+	EFilterInputPrivate *priv;
+
+	gchar *type;		/* name of type */
+	GList *values;		/* strings */
+};
+
+struct _EFilterInputClass {
+	EFilterElementClass parent_class;
+};
+
+GType		e_filter_input_get_type		(void);
+EFilterInput *	e_filter_input_new		(void);
+EFilterInput *	e_filter_input_new_type_name	(const gchar *type);
+void		e_filter_input_set_value	(EFilterInput *input,
+						 const gchar *value);
+
+G_END_DECLS
+
+#endif /* E_FILTER_INPUT_H */
diff --git a/filter/e-filter-int.c b/filter/e-filter-int.c
new file mode 100644
index 0000000..f3fef9d
--- /dev/null
+++ b/filter/e-filter-int.c
@@ -0,0 +1,261 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <gtk/gtk.h>
+
+#include <libedataserver/e-sexp.h>
+
+#include "e-filter-int.h"
+
+static gpointer parent_class;
+
+static void
+filter_int_spin_changed (GtkSpinButton *spin_button,
+                         EFilterElement *element)
+{
+	EFilterInt *filter_int = E_FILTER_INT (element);
+
+	filter_int->val = gtk_spin_button_get_value_as_int (spin_button);
+}
+
+static void
+filter_int_finalize (GObject *object)
+{
+	EFilterInt *filter_int = E_FILTER_INT (object);
+
+	g_free (filter_int->type);
+
+	/* Chain up to parent's finalize() method. */
+        G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gint
+filter_int_eq (EFilterElement *element_a,
+               EFilterElement *element_b)
+{
+	EFilterInt *filter_int_a = E_FILTER_INT (element_a);
+	EFilterInt *filter_int_b = E_FILTER_INT (element_b);
+
+	/* Chain up to parent's eq() method. */
+	if (!E_FILTER_ELEMENT_CLASS (parent_class)->eq (element_a, element_b))
+		return FALSE;
+
+	return (filter_int_a->val == filter_int_b->val);
+}
+
+static EFilterElement *
+filter_int_clone (EFilterElement *element)
+{
+	EFilterInt *filter_int = E_FILTER_INT (element);
+	EFilterInt *clone;
+
+	clone = e_filter_int_new_type (
+		filter_int->type, filter_int->min, filter_int->max);
+	clone->val = filter_int->val;
+
+	E_FILTER_ELEMENT (clone)->name = g_strdup (element->name);
+
+	return E_FILTER_ELEMENT (clone);
+}
+
+static xmlNodePtr
+filter_int_xml_encode (EFilterElement *element)
+{
+	EFilterInt *filter_int = E_FILTER_INT (element);
+	xmlNodePtr value;
+	gchar intval[32];
+	const gchar *type;
+
+	type = filter_int->type ? filter_int->type : "integer";
+
+	value = xmlNewNode (NULL, (xmlChar *)"value");
+	xmlSetProp (value, (xmlChar *) "name", (xmlChar *) element->name);
+	xmlSetProp (value, (xmlChar *) "type", (xmlChar *) type);
+
+	sprintf (intval, "%d", filter_int->val);
+	xmlSetProp (value, (xmlChar *)type, (xmlChar *)intval);
+
+	return value;
+}
+
+static gint
+filter_int_xml_decode (EFilterElement *element,
+                       xmlNodePtr node)
+{
+	EFilterInt *filter_int = E_FILTER_INT (element);
+	gchar *name, *type;
+	gchar *intval;
+
+	name = (gchar *)xmlGetProp (node, (xmlChar *)"name");
+	xmlFree (element->name);
+	element->name = name;
+
+	type = (gchar *)xmlGetProp (node, (xmlChar *)"type");
+	g_free (filter_int->type);
+	filter_int->type = g_strdup (type);
+	xmlFree (type);
+
+	intval = (gchar *)xmlGetProp (node, (xmlChar *)(filter_int->type ? filter_int->type : "integer"));
+	if (intval) {
+		filter_int->val = atoi (intval);
+		xmlFree (intval);
+	} else {
+		filter_int->val = 0;
+	}
+
+	return 0;
+}
+
+static GtkWidget *
+filter_int_get_widget (EFilterElement *element)
+{
+	EFilterInt *filter_int = E_FILTER_INT (element);
+	GtkWidget *widget;
+	GtkObject *adjustment;
+
+	adjustment = gtk_adjustment_new (
+		0.0, (gfloat) filter_int->min,
+		(gfloat) filter_int->max, 1.0, 1.0, 0);
+	widget = gtk_spin_button_new (
+		GTK_ADJUSTMENT (adjustment),
+		filter_int->max > filter_int->min + 1000 ? 5.0 : 1.0, 0);
+	gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (widget), TRUE);
+
+	if (filter_int->val)
+		gtk_spin_button_set_value (
+			GTK_SPIN_BUTTON (widget), (gfloat) filter_int->val);
+
+	g_signal_connect (
+		widget, "value-changed",
+		G_CALLBACK (filter_int_spin_changed), element);
+
+	return widget;
+}
+
+static void
+filter_int_format_sexp (EFilterElement *element,
+                        GString *out)
+{
+	EFilterInt *filter_int = E_FILTER_INT (element);
+
+	if (filter_int->val < 0)
+		/* See #364731 #457523 C6*/
+		g_string_append_printf (out, "(- %d)", (filter_int->val * -1));
+	else
+		g_string_append_printf (out, "%d", filter_int->val);
+}
+
+static void
+filter_int_class_init (EFilterIntClass *class)
+{
+	GObjectClass *object_class;
+	EFilterElementClass *filter_element_class;
+
+	parent_class = g_type_class_peek_parent (class);
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = filter_int_finalize;
+
+	filter_element_class = E_FILTER_ELEMENT_CLASS (class);
+	filter_element_class->eq = filter_int_eq;
+	filter_element_class->clone = filter_int_clone;
+	filter_element_class->xml_encode = filter_int_xml_encode;
+	filter_element_class->xml_decode = filter_int_xml_decode;
+	filter_element_class->get_widget = filter_int_get_widget;
+	filter_element_class->format_sexp = filter_int_format_sexp;
+}
+
+static void
+filter_int_init (EFilterInt *filter_int)
+{
+	filter_int->min = 0;
+	filter_int->max = G_MAXINT;
+}
+
+GType
+e_filter_int_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EFilterIntClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) filter_int_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EFilterInt),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) filter_int_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			E_TYPE_FILTER_ELEMENT, "EFilterInt", &type_info, 0);
+	}
+
+	return type;
+}
+
+/**
+ * filter_int_new:
+ *
+ * Create a new EFilterInt object.
+ *
+ * Return value: A new #EFilterInt object.
+ **/
+EFilterInt *
+e_filter_int_new (void)
+{
+	return g_object_new (E_TYPE_FILTER_INT, NULL);
+}
+
+EFilterInt *
+e_filter_int_new_type (const gchar *type,
+                       gint min,
+                       gint max)
+{
+	EFilterInt *filter_int;
+
+	filter_int = e_filter_int_new ();
+
+	filter_int->type = g_strdup (type);
+	filter_int->min = min;
+	filter_int->max = max;
+
+	return filter_int;
+}
+
+void
+e_filter_int_set_value (EFilterInt *filter_int,
+                        gint value)
+{
+	g_return_if_fail (E_IS_FILTER_INT (filter_int));
+
+	filter_int->val = value;
+}
diff --git a/filter/e-filter-int.h b/filter/e-filter-int.h
new file mode 100644
index 0000000..c9f613c
--- /dev/null
+++ b/filter/e-filter-int.h
@@ -0,0 +1,77 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_FILTER_INT_H
+#define E_FILTER_INT_H
+
+#include "e-filter-element.h"
+
+/* Standard GObject macros */
+#define E_TYPE_FILTER_INT \
+	(e_filter_int_get_type ())
+#define E_FILTER_INT(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_FILTER_INT, EFilterInt))
+#define E_FILTER_INT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_FILTER_INT, EFilterIntClass))
+#define E_IS_FILTER_INT(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_FILTER_INT))
+#define E_IS_FILTER_INT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_FILTER_INT))
+#define E_FILTER_INT_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_FILTER_INT, EFilterIntClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EFilterInt EFilterInt;
+typedef struct _EFilterIntClass EFilterIntClass;
+typedef struct _EFilterIntPrivate EFilterIntPrivate;
+
+struct _EFilterInt {
+	EFilterElement parent;
+	EFilterIntPrivate *priv;
+
+	gchar *type;
+	gint val;
+	gint min;
+	gint max;
+};
+
+struct _EFilterIntClass {
+	EFilterElementClass parent_class;
+};
+
+GType		e_filter_int_get_type		(void);
+EFilterInt *	e_filter_int_new		(void);
+EFilterInt *	e_filter_int_new_type		(const gchar *type,
+						 gint min,
+						 gint max);
+void		e_filter_int_set_value		(EFilterInt *f_int,
+						 gint value);
+
+G_END_DECLS
+
+#endif /* E_FILTER_INT_H */
diff --git a/filter/e-filter-option.c b/filter/e-filter-option.c
new file mode 100644
index 0000000..3765238
--- /dev/null
+++ b/filter/e-filter-option.c
@@ -0,0 +1,514 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <gmodule.h>
+
+#include <libedataserver/e-sexp.h>
+
+#include "e-filter-option.h"
+#include "e-filter-part.h"
+
+static gpointer parent_class;
+
+static void
+free_option (struct _filter_option *opt)
+{
+	g_free (opt->title);
+	g_free (opt->value);
+	g_free (opt->code);
+	g_free (opt);
+}
+
+static struct _filter_option *
+find_option (EFilterOption *option,
+             const gchar *name)
+{
+	GList *link;
+
+	for (link = option->options; link != NULL; link = g_list_next (link)) {
+		struct _filter_option *opt = link->data;
+
+		if (strcmp (name, opt->value) == 0)
+			return opt;
+	}
+
+	return NULL;
+}
+
+static void
+filter_option_combobox_changed (GtkComboBox *combo_box,
+                                EFilterElement *element)
+{
+	EFilterOption *option = E_FILTER_OPTION (element);
+	gint active;
+
+	active = gtk_combo_box_get_active (combo_box);
+	option->current = g_list_nth_data (option->options, active);
+}
+
+static GSList *
+filter_option_get_dynamic_options (EFilterOption *option)
+{
+	GModule *module;
+	GSList *(*get_func)(void);
+	GSList *res = NULL;
+
+	if (!option || !option->dynamic_func)
+		return res;
+
+	module = g_module_open (NULL, G_MODULE_BIND_LAZY);
+
+	if (g_module_symbol (module, option->dynamic_func, (gpointer) &get_func)) {
+		res = get_func ();
+	} else {
+		g_warning ("optionlist dynamic fill function '%s' not found", option->dynamic_func);
+	}
+
+	g_module_close (module);
+
+	return res;
+}
+
+static void
+filter_option_finalize (GObject *object)
+{
+	EFilterOption *option = E_FILTER_OPTION (object);
+
+	g_list_foreach (option->options, (GFunc) free_option, NULL);
+	g_list_free (option->options);
+
+	g_free (option->dynamic_func);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gint
+filter_option_eq (EFilterElement *element_a,
+                  EFilterElement *element_b)
+{
+	EFilterOption *option_a = E_FILTER_OPTION (element_a);
+	EFilterOption *option_b = E_FILTER_OPTION (element_b);
+
+	/* Chain up to parent's eq() method. */
+	if (!E_FILTER_ELEMENT_CLASS (parent_class)->eq (element_a, element_b))
+		return FALSE;
+
+	if (option_a->current == NULL && option_b->current == NULL)
+		return TRUE;
+
+	if (option_a->current == NULL || option_b->current == NULL)
+		return FALSE;
+
+	return (g_strcmp0 (option_a->current->value, option_b->current->value) == 0);
+}
+
+static void
+filter_option_xml_create (EFilterElement *element,
+                          xmlNodePtr node)
+{
+	EFilterOption *option = E_FILTER_OPTION (element);
+	xmlNodePtr n, work;
+
+	/* Chain up to parent's xml_create() method. */
+	E_FILTER_ELEMENT_CLASS (parent_class)->xml_create (element, node);
+
+	n = node->children;
+	while (n) {
+		if (!strcmp ((gchar *)n->name, "option")) {
+			gchar *tmp, *value, *title = NULL, *code = NULL;
+
+			value = (gchar *)xmlGetProp (n, (xmlChar *)"value");
+			work = n->children;
+			while (work) {
+				if (!strcmp ((gchar *)work->name, "title") || !strcmp ((gchar *)work->name, "_title")) {
+					if (!title) {
+						if (!(tmp = (gchar *)xmlNodeGetContent (work)))
+							tmp = (gchar *)xmlStrdup ((xmlChar *)"");
+
+						title = g_strdup (tmp);
+						xmlFree (tmp);
+					}
+				} else if (!strcmp ((gchar *)work->name, "code")) {
+					if (!code) {
+						if (!(tmp = (gchar *)xmlNodeGetContent (work)))
+							tmp = (gchar *)xmlStrdup ((xmlChar *)"");
+
+						code = g_strdup (tmp);
+						xmlFree (tmp);
+					}
+				}
+				work = work->next;
+			}
+
+			e_filter_option_add (option, value, title, code, FALSE);
+			xmlFree (value);
+			g_free (title);
+			g_free (code);
+		} else if (g_str_equal ((gchar *)n->name, "dynamic")) {
+			if (option->dynamic_func) {
+				g_warning ("Only one 'dynamic' node is acceptable in the optionlist '%s'", element->name);
+			} else {
+				/* Expecting only one <dynamic func="cb" /> in the option list,
+				   The 'cb' should be of this prototype:
+				   GSList *cb (void);
+				   returning GSList of struct _filter_option, all newly allocated, because it'll
+				   be freed with g_free and g_slist_free. 'is_dynamic' member is ignored here.
+				*/
+				xmlChar *fn;
+
+				fn = xmlGetProp (n, (xmlChar *)"func");
+				if (fn && *fn) {
+					GSList *items, *i;
+					struct _filter_option *op;
+
+					option->dynamic_func = g_strdup ((const gchar *)fn);
+
+					/* get options now, to have them available when reading saved rules */
+					items = filter_option_get_dynamic_options (option);
+					for (i = items; i; i = i->next) {
+						op = i->data;
+
+						if (op) {
+							e_filter_option_add (option, op->value, op->title, op->code, TRUE);
+							free_option (op);
+						}
+					}
+
+					g_slist_free (items);
+				} else {
+					g_warning ("Missing 'func' attribute within '%s' node in optionlist '%s'", n->name, element->name);
+				}
+
+				xmlFree (fn);
+			}
+		} else if (n->type == XML_ELEMENT_NODE) {
+			g_warning ("Unknown xml node within optionlist: %s\n", n->name);
+		}
+		n = n->next;
+	}
+}
+
+static xmlNodePtr
+filter_option_xml_encode (EFilterElement *element)
+{
+	EFilterOption *option = E_FILTER_OPTION (element);
+	xmlNodePtr value;
+
+	value = xmlNewNode (NULL, (xmlChar *) "value");
+	xmlSetProp (value, (xmlChar *) "name", (xmlChar *) element->name);
+	xmlSetProp (value, (xmlChar *) "type", (xmlChar *) option->type);
+	if (option->current)
+		xmlSetProp (value, (xmlChar *) "value", (xmlChar *)option->current->value);
+
+	return value;
+}
+
+static gint
+filter_option_xml_decode (EFilterElement *element,
+                          xmlNodePtr node)
+{
+	EFilterOption *option = E_FILTER_OPTION (element);
+	gchar *value;
+
+	xmlFree (element->name);
+	element->name = (gchar *)xmlGetProp (node, (xmlChar *)"name");
+
+	value = (gchar *)xmlGetProp (node, (xmlChar *)"value");
+	if (value) {
+		option->current = find_option (option, value);
+		xmlFree (value);
+	} else {
+		option->current = NULL;
+	}
+
+	return 0;
+}
+
+static EFilterElement *
+filter_option_clone (EFilterElement *element)
+{
+	EFilterOption *option = E_FILTER_OPTION (element);
+	EFilterOption *clone_option;
+	EFilterElement *clone;
+	GList *link;
+
+	/* Chain up to parent's clone() method. */
+	clone = E_FILTER_ELEMENT_CLASS (parent_class)->clone (element);
+
+	clone_option = E_FILTER_OPTION (clone);
+
+	for (link = option->options; link != NULL; link = g_list_next (link)) {
+		struct _filter_option *op = link->data;
+		struct _filter_option *newop;
+
+		newop = e_filter_option_add (
+			clone_option, op->value,
+			op->title, op->code, op->is_dynamic);
+		if (option->current == op)
+			clone_option->current = newop;
+	}
+
+	clone_option->dynamic_func = g_strdup (option->dynamic_func);
+
+	return clone;
+}
+
+static GtkWidget *
+filter_option_get_widget (EFilterElement *element)
+{
+	EFilterOption *option = E_FILTER_OPTION (element);
+	GtkWidget *combobox;
+	GList *l;
+	struct _filter_option *op;
+	gint index = 0, current = 0;
+
+	if (option->dynamic_func) {
+		/* it is dynamically filled, thus remove all dynamics and put there the fresh ones */
+		GSList *items, *i;
+		GList *old_ops;
+		struct _filter_option *old_cur;
+
+		old_ops = option->options;
+		old_cur = option->current;
+		l = old_ops;
+
+		/* start with an empty list */
+		option->current = NULL;
+		option->options = NULL;
+
+		for (l = option->options; l; l = l->next) {
+			op = l->data;
+
+			if (op->is_dynamic) {
+				break;
+			} else {
+				e_filter_option_add (option, op->value, op->title, op->code, FALSE);
+			}
+		}
+
+		items = filter_option_get_dynamic_options (option);
+		for (i = items; i; i = i->next) {
+			op = i->data;
+
+			if (op) {
+				e_filter_option_add (option, op->value, op->title, op->code, TRUE);
+				free_option (op);
+			}
+		}
+
+		g_slist_free (items);
+
+		/* maybe some static left after those dynamic, add them too */
+		for (; l; l = l->next) {
+			op = l->data;
+
+			if (!op->is_dynamic)
+				e_filter_option_add (option, op->value, op->title, op->code, FALSE);
+		}
+
+		if (old_cur)
+			e_filter_option_set_current (option, old_cur->value);
+
+		/* free old list */
+		g_list_foreach (old_ops, (GFunc)free_option, NULL);
+		g_list_free (old_ops);
+	}
+
+	combobox = gtk_combo_box_new_text ();
+	l = option->options;
+	while (l) {
+		op = l->data;
+		gtk_combo_box_append_text (GTK_COMBO_BOX (combobox), _(op->title));
+
+		if (op == option->current)
+			current = index;
+
+		l = g_list_next (l);
+		index++;
+	}
+
+	g_signal_connect (
+		combobox, "changed",
+		G_CALLBACK (filter_option_combobox_changed), element);
+
+	gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), current);
+
+	return combobox;
+}
+
+static void
+filter_option_build_code (EFilterElement *element,
+                          GString *out,
+                          EFilterPart *part)
+{
+	EFilterOption *option = E_FILTER_OPTION (element);
+
+	if (option->current && option->current->code)
+		e_filter_part_expand_code (part, option->current->code, out);
+}
+
+static void
+filter_option_format_sexp (EFilterElement *element,
+                           GString *out)
+{
+	EFilterOption *option = E_FILTER_OPTION (element);
+
+	if (option->current)
+		e_sexp_encode_string (out, option->current->value);
+}
+
+static void
+filter_option_class_init (EFilterOptionClass *class)
+{
+	GObjectClass *object_class;
+	EFilterElementClass *filter_element_class;
+
+	parent_class = g_type_class_peek_parent (class);
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = filter_option_finalize;
+
+	filter_element_class = E_FILTER_ELEMENT_CLASS (class);
+	filter_element_class->eq = filter_option_eq;
+	filter_element_class->xml_create = filter_option_xml_create;
+	filter_element_class->xml_encode = filter_option_xml_encode;
+	filter_element_class->xml_decode = filter_option_xml_decode;
+	filter_element_class->clone = filter_option_clone;
+	filter_element_class->get_widget = filter_option_get_widget;
+	filter_element_class->build_code = filter_option_build_code;
+	filter_element_class->format_sexp = filter_option_format_sexp;
+}
+
+static void
+filter_option_init (EFilterOption *option)
+{
+	option->type = "option";
+	option->dynamic_func = NULL;
+}
+
+GType
+e_filter_option_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EFilterOptionClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) filter_option_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EFilterOption),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) filter_option_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			E_TYPE_FILTER_ELEMENT, "EFilterOption", &type_info, 0);
+	}
+
+	return type;
+}
+
+/**
+ * filter_option_new:
+ *
+ * Create a new EFilterOption object.
+ *
+ * Return value: A new #EFilterOption object.
+ **/
+EFilterOption *
+e_filter_option_new (void)
+{
+	return g_object_new (E_TYPE_FILTER_OPTION, NULL);
+}
+
+void
+e_filter_option_set_current (EFilterOption *option,
+                             const gchar *name)
+{
+	g_return_if_fail (E_IS_FILTER_OPTION (option));
+
+	option->current = find_option (option, name);
+}
+
+/* used by implementers to add additional options */
+struct _filter_option *
+e_filter_option_add (EFilterOption *option,
+                     const gchar *value,
+                     const gchar *title,
+                     const gchar *code,
+                     gboolean is_dynamic)
+{
+	struct _filter_option *op;
+
+	g_return_val_if_fail (E_IS_FILTER_OPTION (option), NULL);
+	g_return_val_if_fail (find_option (option, value) == NULL, NULL);
+
+	op = g_malloc (sizeof (*op));
+	op->title = g_strdup (title);
+	op->value = g_strdup (value);
+	op->code = g_strdup (code);
+	op->is_dynamic = is_dynamic;
+
+	option->options = g_list_append (option->options, op);
+
+	if (option->current == NULL)
+		option->current = op;
+
+	return op;
+}
+
+const gchar *
+e_filter_option_get_current (EFilterOption *option)
+{
+	g_return_val_if_fail (E_IS_FILTER_OPTION (option), NULL);
+
+	if (option->current == NULL)
+		return NULL;
+
+	return option->current->value;
+}
+
+void
+e_filter_option_remove_all (EFilterOption *option)
+{
+	g_return_if_fail (E_IS_FILTER_OPTION (option));
+
+	g_list_foreach (option->options, (GFunc) free_option, NULL);
+	g_list_free (option->options);
+
+	option->options = NULL;
+	option->current = NULL;
+}
diff --git a/filter/e-filter-option.h b/filter/e-filter-option.h
new file mode 100644
index 0000000..c42efe2
--- /dev/null
+++ b/filter/e-filter-option.h
@@ -0,0 +1,92 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_FILTER_OPTION_H
+#define E_FILTER_OPTION_H
+
+#include "e-filter-element.h"
+
+/* Standard GObject macros */
+#define E_TYPE_FILTER_OPTION \
+	(e_filter_option_get_type ())
+#define E_FILTER_OPTION(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_FILTER_OPTION, EFilterOption))
+#define E_FILTER_OPTION_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_FILTER_OPTION, EFilterOptionClass))
+#define E_IS_FILTER_OPTION(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_FILTER_OPTION))
+#define E_IS_FILTER_OPTION_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_FILTER_OPTION))
+#define E_FILTER_OPTION_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_FILTER_OPTION, EFilterOptionClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EFilterOption EFilterOption;
+typedef struct _EFilterOptionClass EFilterOptionClass;
+typedef struct _EFilterOptionPrivate EFilterOptionPrivate;
+
+struct _filter_option {
+	gchar *title;		/* button title */
+	gchar *value;		/* value, if it has one */
+	gchar *code;		/* used to string code segments together */
+
+	gboolean is_dynamic;	/* whether is the option dynamic, FALSE if static */
+};
+
+struct _EFilterOption {
+	EFilterElement parent;
+	EFilterOptionPrivate *priv;
+
+	const gchar *type;	/* static memory, type name written to xml */
+
+	GList *options;
+	struct _filter_option *current;
+	gchar *dynamic_func;	/* name of the dynamic fill func, called in get_widget */
+};
+
+struct _EFilterOptionClass {
+	EFilterElementClass parent_class;
+};
+
+GType		e_filter_option_get_type	(void);
+EFilterOption *	e_filter_option_new		(void);
+void		e_filter_option_set_current	(EFilterOption *option,
+						 const gchar *name);
+const gchar *	e_filter_option_get_current	(EFilterOption *option);
+struct _filter_option *
+		e_filter_option_add		(EFilterOption *option,
+						 const gchar *name,
+						 const gchar *title,
+						 const gchar *code,
+						 gboolean is_dynamic);
+void		e_filter_option_remove_all	(EFilterOption *option);
+
+G_END_DECLS
+
+#endif /* E_FILTER_OPTION_H */
diff --git a/filter/e-filter-part.c b/filter/e-filter-part.c
new file mode 100644
index 0000000..37e2bf6
--- /dev/null
+++ b/filter/e-filter-part.c
@@ -0,0 +1,532 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jepartrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include "e-filter-file.h"
+#include "e-filter-part.h"
+#include "e-rule-context.h"
+
+static gpointer parent_class;
+
+static void
+filter_part_finalize (GObject *object)
+{
+	EFilterPart *part = E_FILTER_PART (object);
+
+	g_list_foreach (part->elements, (GFunc) g_object_unref, NULL);
+	g_list_free (part->elements);
+
+	g_free (part->name);
+	g_free (part->title);
+	g_free (part->code);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+filter_part_class_init (EFilterPartClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = filter_part_finalize;
+}
+
+GType
+e_filter_part_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EFilterPartClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) filter_part_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL, /* class_data */
+			sizeof (EFilterPart),
+			0,    /* n_preallocs */
+			(GInstanceInitFunc) NULL,
+			NULL  /* value_table */
+		};
+
+		type = g_type_register_static (
+			G_TYPE_OBJECT, "EFilterPart", &type_info, 0);
+	}
+
+	return type;
+}
+
+/**
+ * e_filter_part_new:
+ *
+ * Create a new EFilterPart object.
+ *
+ * Return value: A new #EFilterPart object.
+ **/
+EFilterPart *
+e_filter_part_new (void)
+{
+	return g_object_new (E_TYPE_FILTER_PART, NULL);
+}
+
+gboolean
+e_filter_part_validate (EFilterPart *part,
+                        GtkWindow *error_parent)
+{
+	GList *link;
+
+	g_return_val_if_fail (E_IS_FILTER_PART (part), FALSE);
+
+	/* The part is valid if all of its elements are valid. */
+	for (link = part->elements; link != NULL; link = g_list_next (link)) {
+		EFilterElement *element = link->data;
+
+		if (!e_filter_element_validate (element, error_parent))
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+gint
+e_filter_part_eq (EFilterPart *part_a,
+                  EFilterPart *part_b)
+{
+	GList *link_a, *link_b;
+
+	g_return_val_if_fail (E_IS_FILTER_PART (part_a), FALSE);
+	g_return_val_if_fail (E_IS_FILTER_PART (part_b), FALSE);
+
+	if (g_strcmp0 (part_a->name, part_b->name) != 0)
+		return FALSE;
+
+	if (g_strcmp0 (part_a->title, part_b->title) != 0)
+		return FALSE;
+
+	if (g_strcmp0 (part_a->code, part_b->code) != 0)
+		return FALSE;
+
+	link_a = part_a->elements;
+	link_b = part_b->elements;
+
+	while (link_a != NULL && link_b != NULL) {
+		EFilterElement *element_a = link_a->data;
+		EFilterElement *element_b = link_b->data;
+
+		if (!e_filter_element_eq (element_a, element_b))
+			return FALSE;
+
+		link_a = g_list_next (link_a);
+		link_b = g_list_next (link_b);
+	}
+
+	if (link_a != NULL || link_b != NULL)
+		return FALSE;
+
+	return TRUE;
+}
+
+gint
+e_filter_part_xml_create (EFilterPart *part,
+                          xmlNodePtr node,
+                          ERuleContext *context)
+{
+	xmlNodePtr n;
+	gchar *type, *str;
+	EFilterElement *el;
+
+	g_return_val_if_fail (E_IS_FILTER_PART (part), FALSE);
+	g_return_val_if_fail (node != NULL, FALSE);
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), FALSE);
+
+	str = (gchar *)xmlGetProp (node, (xmlChar *)"name");
+	part->name = g_strdup (str);
+	if (str)
+		xmlFree (str);
+
+	n = node->children;
+	while (n) {
+		if (!strcmp ((gchar *)n->name, "input")) {
+			type = (gchar *)xmlGetProp (n, (xmlChar *)"type");
+			if (type != NULL
+			    && (el = e_rule_context_new_element (context, type)) != NULL) {
+				e_filter_element_xml_create (el, n);
+				xmlFree (type);
+				part->elements = g_list_append (part->elements, el);
+			} else {
+				g_warning ("Invalid xml format, missing/unknown input type");
+			}
+		} else if (!strcmp ((gchar *)n->name, "title") || !strcmp ((gchar *)n->name, "_title")) {
+			if (!part->title) {
+				str = (gchar *)xmlNodeGetContent (n);
+				part->title = g_strdup (str);
+				if (str)
+					xmlFree (str);
+			}
+		} else if (!strcmp ((gchar *)n->name, "code")) {
+			if (!part->code) {
+				str = (gchar *)xmlNodeGetContent (n);
+				part->code = g_strdup (str);
+				if (str)
+					xmlFree (str);
+			}
+		} else if (n->type == XML_ELEMENT_NODE) {
+			g_warning ("Unknown part element in xml: %s\n", n->name);
+		}
+		n = n->next;
+	}
+
+	return 0;
+}
+
+xmlNodePtr
+e_filter_part_xml_encode (EFilterPart *part)
+{
+	xmlNodePtr node;
+	GList *link;
+
+	g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);
+
+	node = xmlNewNode (NULL, (xmlChar *)"part");
+	xmlSetProp (node, (xmlChar *)"name", (xmlChar *)part->name);
+
+	for (link = part->elements; link != NULL; link = g_list_next (link)) {
+		EFilterElement *element = link->data;
+		xmlNodePtr value;
+
+		value = e_filter_element_xml_encode (element);
+		xmlAddChild (node, value);
+	}
+
+	return node;
+}
+
+gint
+e_filter_part_xml_decode (EFilterPart *part,
+                          xmlNodePtr node)
+{
+	xmlNodePtr child;
+
+	g_return_val_if_fail (E_IS_FILTER_PART (part), -1);
+	g_return_val_if_fail (node != NULL, -1);
+
+	for (child = node->children; child != NULL; child = child->next) {
+		EFilterElement *element;
+		xmlChar *name;
+
+		if (strcmp ((gchar *) child->name, "value") != 0)
+			continue;
+
+		name = xmlGetProp (child, (xmlChar *) "name");
+		element = e_filter_part_find_element (part, (gchar *) name);
+		xmlFree (name);
+
+		if (element != NULL)
+			e_filter_element_xml_decode (element, child);
+	}
+
+	return 0;
+}
+
+EFilterPart *
+e_filter_part_clone (EFilterPart *part)
+{
+	EFilterPart *clone;
+	GList *link;
+
+	g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);
+
+	clone = g_object_new (G_OBJECT_TYPE (part), NULL, NULL);
+	clone->name = g_strdup (part->name);
+	clone->title = g_strdup (part->title);
+	clone->code = g_strdup (part->code);
+
+	for (link = part->elements; link != NULL; link = g_list_next (link)) {
+		EFilterElement *element = link->data;
+		EFilterElement *clone_element;
+
+		clone_element = e_filter_element_clone (element);
+		clone->elements = g_list_append (clone->elements, clone_element);
+	}
+
+	return clone;
+}
+
+/* only copies values of matching parts in the right order */
+void
+e_filter_part_copy_values (EFilterPart *dst_part,
+                           EFilterPart *src_part)
+{
+	GList *dst_link, *src_link;
+
+	g_return_if_fail (E_IS_FILTER_PART (dst_part));
+	g_return_if_fail (E_IS_FILTER_PART (src_part));
+
+	/* NOTE: we go backwards, it just works better that way */
+
+	/* for each source type, search the dest type for
+	   a matching type in the same order */
+	src_link = g_list_last (src_part->elements);
+	dst_link = g_list_last (dst_part->elements);
+
+	while (src_link != NULL && dst_link != NULL) {
+		EFilterElement *src_element = src_link->data;
+		GList *link = dst_link;
+
+		while (link != NULL) {
+			EFilterElement *dst_element = link->data;
+			GType dst_type = G_OBJECT_TYPE (dst_element);
+			GType src_type = G_OBJECT_TYPE (src_element);
+
+			if (dst_type == src_type) {
+				e_filter_element_copy_value (
+					dst_element, src_element);
+				dst_link = g_list_previous (link);
+				break;
+			}
+
+			link = g_list_previous (link);
+		}
+
+		src_link = g_list_previous (src_link);
+	}
+}
+
+EFilterElement *
+e_filter_part_find_element (EFilterPart *part,
+                            const gchar *name)
+{
+	GList *link;
+
+	g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);
+
+	if (name == NULL)
+		return NULL;
+
+	for (link = part->elements; link != NULL; link = g_list_next (link)) {
+		EFilterElement *element = link->data;
+
+		if (g_strcmp0 (element->name, name) == 0)
+			return element;
+	}
+
+	return NULL;
+}
+
+GtkWidget *
+e_filter_part_get_widget (EFilterPart *part)
+{
+	GtkWidget *hbox;
+	GList *link;
+
+	g_return_val_if_fail (E_IS_FILTER_PART (part), NULL);
+
+	hbox = gtk_hbox_new (FALSE, 3);
+
+	for (link = part->elements; link != NULL; link = g_list_next (link)) {
+		EFilterElement *element = link->data;
+		GtkWidget *widget;
+
+		widget = e_filter_element_get_widget (element);
+		if (widget != NULL)
+			gtk_box_pack_start (
+				GTK_BOX (hbox), widget,
+				E_IS_FILTER_FILE (element),
+				E_IS_FILTER_FILE (element), 3);
+	}
+
+	gtk_widget_show_all (hbox);
+
+	return hbox;
+}
+
+/**
+ * e_filter_part_build_code:
+ * @part:
+ * @out:
+ *
+ * Outputs the code of a part.
+ **/
+void
+e_filter_part_build_code (EFilterPart *part,
+                          GString *out)
+{
+	GList *link;
+
+	g_return_if_fail (E_IS_FILTER_PART (part));
+	g_return_if_fail (out != NULL);
+
+	if (part->code != NULL)
+		e_filter_part_expand_code (part, part->code, out);
+
+	for (link = part->elements; link != NULL; link = g_list_next (link)) {
+		EFilterElement *element = link->data;
+		e_filter_element_build_code (element, out, part);
+	}
+}
+
+/**
+ * e_filter_part_build_code_list:
+ * @l:
+ * @out:
+ *
+ * Construct a list of the filter parts code into
+ * a single string.
+ **/
+void
+e_filter_part_build_code_list (GList *list,
+                               GString *out)
+{
+	GList *link;
+
+	g_return_if_fail (out != NULL);
+
+	for (link = list; link != NULL; link = g_list_next (link)) {
+		EFilterPart *part = link->data;
+
+		e_filter_part_build_code (part, out);
+		g_string_append (out, "\n  ");
+	}
+}
+
+/**
+ * e_filter_part_find_list:
+ * @l:
+ * @name:
+ *
+ * Find a filter part stored in a list.
+ *
+ * Return value:
+ **/
+EFilterPart *
+e_filter_part_find_list (GList *list,
+                         const gchar *name)
+{
+	GList *link;
+
+	g_return_val_if_fail (name != NULL, NULL);
+
+	for (link = list; link != NULL; link = g_list_next (link)) {
+		EFilterPart *part = link->data;
+
+		if (!g_strcmp0 (part->name, name) == 0)
+			return part;
+	}
+
+	return NULL;
+}
+
+/**
+ * e_filter_part_next_list:
+ * @l:
+ * @last: The last item retrieved, or NULL to start
+ * from the beginning of the list.
+ *
+ * Iterate through a filter part list.
+ *
+ * Return value: The next value in the list, or NULL if the
+ * list is expired.
+ **/
+EFilterPart *
+e_filter_part_next_list (GList *list,
+                         EFilterPart *last)
+{
+	GList *link = list;
+
+	if (last != NULL) {
+		link = g_list_find (list, last);
+		if (link == NULL)
+			link = list;
+		else
+			link = link->next;
+	}
+
+	return (link != NULL) ? link->data : NULL;
+}
+
+/**
+ * e_filter_part_expand_code:
+ * @part:
+ * @str:
+ * @out:
+ *
+ * Expands the variables in string @str based on the values of the part.
+ **/
+void
+e_filter_part_expand_code (EFilterPart *part,
+                           const gchar *source,
+                           GString *out)
+{
+	const gchar *newstart, *start, *end;
+	gchar *name = alloca (32);
+	gint len, namelen = 32;
+
+	g_return_if_fail (E_IS_FILTER_PART (part));
+	g_return_if_fail (source != NULL);
+	g_return_if_fail (out != NULL);
+
+	start = source;
+
+	while (start && (newstart = strstr (start, "${"))
+		&& (end = strstr (newstart+2, "}")) ) {
+		EFilterElement *element;
+
+		len = end - newstart - 2;
+		if (len + 1 > namelen) {
+			namelen = (len + 1) * 2;
+			name = g_alloca (namelen);
+		}
+		memcpy (name, newstart+2, len);
+		name[len] = 0;
+
+		element = e_filter_part_find_element (part, name);
+		if (element != NULL) {
+			g_string_append_printf (out, "%.*s", (gint)(newstart-start), start);
+			e_filter_element_format_sexp (element, out);
+#if 0
+		} else if ((val = g_hash_table_lookup (part->globals, name))) {
+			g_string_append_printf (out, "%.*s", newstart-start, start);
+			e_sexp_encode_string (out, val);
+#endif
+		} else {
+			g_string_append_printf (out, "%.*s", (gint)(end-start+1), start);
+		}
+		start = end + 1;
+	}
+
+	g_string_append (out, start);
+}
diff --git a/filter/e-filter-part.h b/filter/e-filter-part.h
new file mode 100644
index 0000000..697cf8f
--- /dev/null
+++ b/filter/e-filter-part.h
@@ -0,0 +1,104 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_FILTER_PART_H
+#define E_FILTER_PART_H
+
+#include <gtk/gtk.h>
+#include "e-filter-input.h"
+
+/* Standard GObject macros */
+#define E_TYPE_FILTER_PART \
+	(e_filter_part_get_type ())
+#define E_FILTER_PART(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_FILTER_PART, EFilterPart))
+#define E_FILTER_PART_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_FILTER_PART, EFilterPartClass))
+#define E_IS_FILTER_PART(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_FILTER_PART))
+#define E_IS_FILTER_PART_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_FILTER_PART))
+#define E_FILTER_PART_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_FILTER_PART, EFilterPartClass))
+
+G_BEGIN_DECLS
+
+struct _ERuleContext;
+
+typedef struct _EFilterPart EFilterPart;
+typedef struct _EFilterPartClass EFilterPartClass;
+typedef struct _EFilterPartPrivate EFilterPartPrivate;
+
+struct _EFilterPart {
+	GObject parent;
+	EFilterPartPrivate *priv;
+
+	gchar *name;
+	gchar *title;
+	gchar *code;
+	GList *elements;
+};
+
+struct _EFilterPartClass {
+	GObjectClass parent_class;
+};
+
+GType		e_filter_part_get_type		(void);
+EFilterPart *	e_filter_part_new		(void);
+gboolean	e_filter_part_validate		(EFilterPart *part,
+						 GtkWindow *error_parent);
+gint		e_filter_part_eq		(EFilterPart *part_a,
+						 EFilterPart *part_b);
+gint		e_filter_part_xml_create	(EFilterPart *part,
+						 xmlNodePtr node,
+						 struct _ERuleContext *rc);
+xmlNodePtr	e_filter_part_xml_encode	(EFilterPart *fe);
+gint		e_filter_part_xml_decode	(EFilterPart *fe,
+						 xmlNodePtr node);
+EFilterPart *	e_filter_part_clone		(EFilterPart *part);
+void		e_filter_part_copy_values	(EFilterPart *dst_part,
+						 EFilterPart *src_part);
+EFilterElement *e_filter_part_find_element	(EFilterPart *part,
+						 const gchar *name);
+GtkWidget *	e_filter_part_get_widget	(EFilterPart *part);
+void		e_filter_part_build_code	(EFilterPart *part,
+						 GString *out);
+void		e_filter_part_expand_code	(EFilterPart *part,
+						 const gchar *str,
+						 GString *out);
+
+void		e_filter_part_build_code_list	(GList *list,
+						 GString *out);
+EFilterPart *	e_filter_part_find_list		(GList *list,
+						 const gchar *name);
+EFilterPart *	e_filter_part_next_list		(GList *list,
+						 EFilterPart *last);
+
+G_END_DECLS
+
+#endif /* E_FILTER_PART_H */
diff --git a/filter/e-filter-rule.c b/filter/e-filter-rule.c
new file mode 100644
index 0000000..f60230d
--- /dev/null
+++ b/filter/e-filter-rule.c
@@ -0,0 +1,1116 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *		Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include "e-util/e-error.h"
+
+#include "e-filter-rule.h"
+#include "e-rule-context.h"
+
+#define E_FILTER_RULE_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_FILTER_RULE, EFilterRulePrivate))
+
+typedef struct _FilterPartData FilterPartData;
+typedef struct _FilterRuleData FilterRuleData;
+
+struct _EFilterRulePrivate {
+	gint frozen;
+};
+
+struct _FilterPartData {
+	EFilterRule *rule;
+	ERuleContext *context;
+	EFilterPart *part;
+	GtkWidget *partwidget;
+	GtkWidget *container;
+};
+
+struct _FilterRuleData {
+	EFilterRule *rule;
+	ERuleContext *context;
+	GtkWidget *parts;
+};
+
+enum {
+	CHANGED,
+	LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static void
+filter_rule_grouping_changed_cb (GtkComboBox *combo_box,
+                                 EFilterRule *rule)
+{
+	rule->grouping = gtk_combo_box_get_active (combo_box);
+}
+
+static void
+filter_rule_threading_changed_cb (GtkComboBox *combo_box,
+                                  EFilterRule *rule)
+{
+	rule->threading = gtk_combo_box_get_active (combo_box);
+}
+
+static void
+part_combobox_changed (GtkComboBox *combobox,
+                       FilterPartData *data)
+{
+	EFilterPart *part = NULL;
+	EFilterPart *newpart;
+	gint index, i;
+
+	index = gtk_combo_box_get_active (combobox);
+	for (i = 0, part = e_rule_context_next_part (data->context, part); part && i < index; i++, part = e_rule_context_next_part (data->context, part)) {
+		/* traverse until reached index */
+	}
+
+	g_return_if_fail (part != NULL);
+	g_return_if_fail (i == index);
+
+	/* dont update if we haven't changed */
+	if (!strcmp (part->title, data->part->title))
+		return;
+
+	/* here we do a widget shuffle, throw away the old widget/rulepart,
+	   and create another */
+	if (data->partwidget)
+		gtk_container_remove (GTK_CONTAINER (data->container), data->partwidget);
+
+	newpart = e_filter_part_clone (part);
+	e_filter_part_copy_values (newpart, data->part);
+	e_filter_rule_replace_part (data->rule, data->part, newpart);
+	g_object_unref (data->part);
+	data->part = newpart;
+	data->partwidget = e_filter_part_get_widget (newpart);
+	if (data->partwidget)
+		gtk_box_pack_start (GTK_BOX (data->container), data->partwidget, TRUE, TRUE, 0);
+}
+
+static GtkWidget *
+get_rule_part_widget (ERuleContext *context,
+                      EFilterPart *newpart,
+                      EFilterRule *rule)
+{
+	EFilterPart *part = NULL;
+	GtkWidget *combobox;
+	GtkWidget *hbox;
+	GtkWidget *p;
+	gint index = 0, current = 0;
+	FilterPartData *data;
+
+	data = g_malloc0 (sizeof (*data));
+	data->rule = rule;
+	data->context = context;
+	data->part = newpart;
+
+	hbox = gtk_hbox_new (FALSE, 0);
+	/* only set to automatically clean up the memory */
+	g_object_set_data_full ((GObject *) hbox, "data", data, g_free);
+
+	p = e_filter_part_get_widget (newpart);
+
+	data->partwidget = p;
+	data->container = hbox;
+
+	combobox = gtk_combo_box_new_text ();
+
+	/* sigh, this is a little ugly */
+	while ((part = e_rule_context_next_part (context, part))) {
+		gtk_combo_box_append_text (GTK_COMBO_BOX (combobox), _(part->title));
+
+		if (!strcmp (newpart->title, part->title))
+			current = index;
+
+		index++;
+	}
+
+	gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), current);
+	g_signal_connect (combobox, "changed", G_CALLBACK (part_combobox_changed), data);
+	gtk_widget_show (combobox);
+
+	gtk_box_pack_start (GTK_BOX (hbox), combobox, FALSE, FALSE, 0);
+	if (p)
+		gtk_box_pack_start (GTK_BOX (hbox), p, TRUE, TRUE, 0);
+
+	gtk_widget_show_all (hbox);
+
+	return hbox;
+}
+
+static void
+less_parts (GtkWidget *button,
+            FilterRuleData *data)
+{
+	EFilterPart *part;
+	GtkWidget *rule;
+	FilterPartData *part_data;
+
+	if (g_list_length (data->rule->parts) < 1)
+		return;
+
+	rule = g_object_get_data ((GObject *) button, "rule");
+	part_data = g_object_get_data ((GObject *) rule, "data");
+
+	g_return_if_fail (part_data != NULL);
+
+	part = part_data->part;
+
+	/* remove the part from the list */
+	e_filter_rule_remove_part (data->rule, part);
+	g_object_unref (part);
+
+	/* and from the display */
+	gtk_container_remove (GTK_CONTAINER (data->parts), rule);
+	gtk_container_remove (GTK_CONTAINER (data->parts), button);
+}
+
+static void
+attach_rule (GtkWidget *rule,
+             FilterRuleData *data,
+             EFilterPart *part, gint row)
+{
+	GtkWidget *remove;
+
+	gtk_table_attach (GTK_TABLE (data->parts), rule, 0, 1, row, row + 1,
+			  GTK_EXPAND | GTK_FILL, 0, 0, 0);
+
+	remove = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
+	g_object_set_data ((GObject *) remove, "rule", rule);
+	g_signal_connect (remove, "clicked", G_CALLBACK (less_parts), data);
+	gtk_table_attach (GTK_TABLE (data->parts), remove, 1, 2, row, row + 1,
+			  0, 0, 0, 0);
+
+	gtk_widget_show (remove);
+}
+
+static void
+do_grab_focus_cb (GtkWidget *widget,
+                  gpointer data)
+{
+	gboolean *done = (gboolean *) data;
+
+	if (*done)
+		return;
+
+	if (widget && GTK_WIDGET_CAN_FOCUS (widget)) {
+		*done = TRUE;
+		gtk_widget_grab_focus (widget);
+	}
+}
+
+static void
+more_parts (GtkWidget *button,
+            FilterRuleData *data)
+{
+	EFilterPart *new;
+
+	/* first make sure that the last part is ok */
+	if (data->rule->parts) {
+		EFilterPart *part;
+		GList *l;
+
+		l = g_list_last (data->rule->parts);
+		part = l->data;
+		if (!e_filter_part_validate (part, GTK_WINDOW (gtk_widget_get_toplevel (button))))
+			return;
+	}
+
+	/* create a new rule entry, use the first type of rule */
+	new = e_rule_context_next_part (data->context, NULL);
+	if (new) {
+		GtkWidget *w;
+		gint rows;
+
+		new = e_filter_part_clone (new);
+		e_filter_rule_add_part (data->rule, new);
+		w = get_rule_part_widget (data->context, new, data->rule);
+
+		rows = GTK_TABLE (data->parts)->nrows;
+		gtk_table_resize (GTK_TABLE (data->parts), rows + 1, 2);
+		attach_rule (w, data, new, rows);
+
+		if (GTK_IS_CONTAINER (w)) {
+			gboolean done = FALSE;
+
+			gtk_container_foreach (GTK_CONTAINER (w), do_grab_focus_cb, &done);
+		} else
+			gtk_widget_grab_focus (w);
+
+		/* also scroll down to see new part */
+		w = (GtkWidget*) g_object_get_data (G_OBJECT (button), "scrolled-window");
+		if (w) {
+			GtkAdjustment *adjustment;
+
+			adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (w));
+			if (adjustment) {
+				gdouble upper;
+
+				upper = gtk_adjustment_get_upper (adjustment);
+				gtk_adjustment_set_value (adjustment, upper);
+			}
+
+		}
+	}
+}
+
+static void
+name_changed (GtkEntry *entry,
+              EFilterRule *rule)
+{
+	g_free (rule->name);
+	rule->name = g_strdup (gtk_entry_get_text (entry));
+}
+
+GtkWidget *
+e_filter_rule_get_widget (EFilterRule *rule,
+                          ERuleContext *context)
+{
+	EFilterRuleClass *class;
+
+	g_return_val_if_fail (E_IS_FILTER_RULE (rule), NULL);
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
+
+	class = E_FILTER_RULE_GET_CLASS (rule);
+	g_return_val_if_fail (class->get_widget != NULL, NULL);
+
+	return class->get_widget (rule, context);
+}
+
+static void
+filter_rule_load_set (xmlNodePtr node,
+                      EFilterRule *rule,
+                      ERuleContext *context)
+{
+	xmlNodePtr work;
+	gchar *rulename;
+	EFilterPart *part;
+
+	work = node->children;
+	while (work) {
+		if (!strcmp ((gchar *)work->name, "part")) {
+			rulename = (gchar *)xmlGetProp (work, (xmlChar *)"name");
+			part = e_rule_context_find_part (context, rulename);
+			if (part) {
+				part = e_filter_part_clone (part);
+				e_filter_part_xml_decode (part, work);
+				e_filter_rule_add_part (rule, part);
+			} else {
+				g_warning ("cannot find rule part '%s'\n", rulename);
+			}
+			xmlFree (rulename);
+		} else if (work->type == XML_ELEMENT_NODE) {
+			g_warning ("Unknown xml node in part: %s", work->name);
+		}
+		work = work->next;
+	}
+}
+
+static void
+filter_rule_finalize (GObject *object)
+{
+	EFilterRule *rule = E_FILTER_RULE (object);
+
+	g_free (rule->name);
+	g_free (rule->source);
+
+	g_list_foreach (rule->parts, (GFunc) g_object_unref, NULL);
+	g_list_free (rule->parts);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gint
+filter_rule_validate (EFilterRule *rule,
+                      GtkWindow *error_parent)
+{
+	gint valid = TRUE;
+	GList *parts;
+
+	if (!rule->name || !*rule->name) {
+		e_error_run (error_parent, "filter:no-name", NULL);
+
+		return FALSE;
+	}
+
+	/* validate rule parts */
+	parts = rule->parts;
+	valid = parts != NULL;
+	while (parts && valid) {
+		valid = e_filter_part_validate ((EFilterPart *) parts->data, error_parent);
+		parts = parts->next;
+	}
+
+	return valid;
+}
+
+static gint
+filter_rule_eq (EFilterRule *rule_a,
+                EFilterRule *rule_b)
+{
+	GList *link_a;
+	GList *link_b;
+
+	if (rule_a->enabled != rule_b->enabled)
+		return FALSE;
+
+	if (rule_a->grouping != rule_b->grouping)
+		return FALSE;
+
+	if (rule_a->threading != rule_b->threading)
+		return FALSE;
+
+	if (g_strcmp0 (rule_a->name, rule_b->name) != 0)
+		return FALSE;
+
+	if (g_strcmp0 (rule_a->source, rule_b->source) != 0)
+		return FALSE;
+
+	link_a = rule_a->parts;
+	link_b = rule_b->parts;
+
+	while (link_a != NULL && link_b != NULL) {
+		EFilterPart *part_a = link_a->data;
+		EFilterPart *part_b = link_b->data;
+
+		if (!e_filter_part_eq (part_a, part_b))
+			return FALSE;
+
+		link_a = g_list_next (link_a);
+		link_b = g_list_next (link_b);
+	}
+
+	if (link_a != NULL || link_b != NULL)
+		return FALSE;
+
+	return TRUE;
+}
+
+static xmlNodePtr
+filter_rule_xml_encode (EFilterRule *rule)
+{
+	xmlNodePtr node, set, work;
+	GList *l;
+
+	node = xmlNewNode (NULL, (xmlChar *)"rule");
+
+	xmlSetProp (node, (xmlChar *)"enabled", (xmlChar *)(rule->enabled ? "true" : "false"));
+
+	switch (rule->grouping) {
+	case E_FILTER_GROUP_ALL:
+		xmlSetProp (node, (xmlChar *)"grouping", (xmlChar *)"all");
+		break;
+	case E_FILTER_GROUP_ANY:
+		xmlSetProp (node, (xmlChar *)"grouping", (xmlChar *)"any");
+		break;
+	}
+
+	switch (rule->threading) {
+	case E_FILTER_THREAD_NONE:
+		break;
+	case E_FILTER_THREAD_ALL:
+		xmlSetProp (node, (xmlChar *)"threading", (xmlChar *)"all");
+		break;
+	case E_FILTER_THREAD_REPLIES:
+		xmlSetProp (node, (xmlChar *)"threading", (xmlChar *)"replies");
+		break;
+	case E_FILTER_THREAD_REPLIES_PARENTS:
+		xmlSetProp (node, (xmlChar *)"threading", (xmlChar *)"replies_parents");
+		break;
+	case E_FILTER_THREAD_SINGLE:
+		xmlSetProp (node, (xmlChar *)"threading", (xmlChar *)"single");
+		break;
+	}
+
+	if (rule->source) {
+		xmlSetProp (node, (xmlChar *)"source", (xmlChar *)rule->source);
+	} else {
+		/* set to the default filter type */
+		xmlSetProp (node, (xmlChar *)"source", (xmlChar *)"incoming");
+	}
+
+	if (rule->name) {
+		gchar *escaped = g_markup_escape_text (rule->name, -1);
+
+		work = xmlNewNode (NULL, (xmlChar *)"title");
+		xmlNodeSetContent (work, (xmlChar *)escaped);
+		xmlAddChild (node, work);
+
+		g_free (escaped);
+	}
+
+	set = xmlNewNode (NULL, (xmlChar *)"partset");
+	xmlAddChild (node, set);
+	l = rule->parts;
+	while (l) {
+		work = e_filter_part_xml_encode ((EFilterPart *) l->data);
+		xmlAddChild (set, work);
+		l = l->next;
+	}
+
+	return node;
+}
+
+static gint
+filter_rule_xml_decode (EFilterRule *rule,
+                        xmlNodePtr node,
+                        ERuleContext *context)
+{
+	xmlNodePtr work;
+	gchar *grouping;
+	gchar *source;
+
+	g_free (rule->name);
+	rule->name = NULL;
+
+	grouping = (gchar *)xmlGetProp (node, (xmlChar *)"enabled");
+	if (!grouping)
+		rule->enabled = TRUE;
+	else {
+		rule->enabled = strcmp (grouping, "false") != 0;
+		xmlFree (grouping);
+	}
+
+	grouping = (gchar *)xmlGetProp (node, (xmlChar *)"grouping");
+	if (!strcmp (grouping, "any"))
+		rule->grouping = E_FILTER_GROUP_ANY;
+	else
+		rule->grouping = E_FILTER_GROUP_ALL;
+	xmlFree (grouping);
+
+	rule->threading = E_FILTER_THREAD_NONE;
+	if (context->flags & E_RULE_CONTEXT_THREADING
+	    && (grouping = (gchar *)xmlGetProp (node, (xmlChar *)"threading"))) {
+		if (!strcmp (grouping, "all"))
+			rule->threading = E_FILTER_THREAD_ALL;
+		else if (!strcmp (grouping, "replies"))
+			rule->threading = E_FILTER_THREAD_REPLIES;
+		else if (!strcmp (grouping, "replies_parents"))
+			rule->threading = E_FILTER_THREAD_REPLIES_PARENTS;
+		else if (!strcmp (grouping, "single"))
+			rule->threading = E_FILTER_THREAD_SINGLE;
+		xmlFree (grouping);
+	}
+
+	g_free (rule->source);
+	source = (gchar *)xmlGetProp (node, (xmlChar *)"source");
+	if (source) {
+		rule->source = g_strdup (source);
+		xmlFree (source);
+	} else {
+		/* default filter type */
+		rule->source = g_strdup ("incoming");
+	}
+
+	work = node->children;
+	while (work) {
+		if (!strcmp ((gchar *)work->name, "partset")) {
+			filter_rule_load_set (work, rule, context);
+		} else if (!strcmp ((gchar *)work->name, "title") || !strcmp ((gchar *)work->name, "_title")) {
+			if (!rule->name) {
+				gchar *str, *decstr = NULL;
+
+				str = (gchar *)xmlNodeGetContent (work);
+				if (str) {
+					decstr = g_strdup (_(str));
+					xmlFree (str);
+				}
+				rule->name = decstr;
+			}
+		}
+		work = work->next;
+	}
+
+	return 0;
+}
+
+static void
+filter_rule_build_code (EFilterRule *rule,
+                        GString *out)
+{
+	switch (rule->threading) {
+	case E_FILTER_THREAD_NONE:
+		break;
+	case E_FILTER_THREAD_ALL:
+		g_string_append (out, " (match-threads \"all\" ");
+		break;
+	case E_FILTER_THREAD_REPLIES:
+		g_string_append (out, " (match-threads \"replies\" ");
+		break;
+	case E_FILTER_THREAD_REPLIES_PARENTS:
+		g_string_append (out, " (match-threads \"replies_parents\" ");
+		break;
+	case E_FILTER_THREAD_SINGLE:
+		g_string_append (out, " (match-threads \"single\" ");
+		break;
+	}
+
+	switch (rule->grouping) {
+	case E_FILTER_GROUP_ALL:
+		g_string_append (out, " (and\n  ");
+		break;
+	case E_FILTER_GROUP_ANY:
+		g_string_append (out, " (or\n  ");
+		break;
+	default:
+		g_warning ("Invalid grouping");
+	}
+
+	e_filter_part_build_code_list (rule->parts, out);
+	g_string_append (out, ")\n");
+
+	if (rule->threading != E_FILTER_THREAD_NONE)
+		g_string_append (out, ")\n");
+}
+
+static void
+filter_rule_copy (EFilterRule *dest, EFilterRule *src)
+{
+	GList *node;
+
+	dest->enabled = src->enabled;
+
+	g_free (dest->name);
+	dest->name = g_strdup (src->name);
+
+	g_free (dest->source);
+	dest->source = g_strdup (src->source);
+
+	dest->grouping = src->grouping;
+	dest->threading = src->threading;
+
+	if (dest->parts) {
+		g_list_foreach (dest->parts, (GFunc) g_object_unref, NULL);
+		g_list_free (dest->parts);
+		dest->parts = NULL;
+	}
+
+	node = src->parts;
+	while (node) {
+		EFilterPart *part;
+
+		part = e_filter_part_clone (node->data);
+		dest->parts = g_list_append (dest->parts, part);
+		node = node->next;
+	}
+}
+
+static GtkWidget *
+filter_rule_get_widget (EFilterRule *rule,
+                        ERuleContext *context)
+{
+	GtkWidget *hbox, *vbox, *parts, *inruleame;
+	GtkWidget *add, *label, *name, *w;
+	GtkWidget *combobox;
+	GtkWidget *scrolledwindow;
+	GtkObject *hadj, *vadj;
+	GList *l;
+	gchar *text;
+	EFilterPart *part;
+	FilterRuleData *data;
+	gint rows, i;
+
+	/* this stuff should probably be a table, but the
+	   rule parts need to be a vbox */
+	vbox = gtk_vbox_new (FALSE, 6);
+
+	label = gtk_label_new_with_mnemonic (_("R_ule name:"));
+	name = gtk_entry_new ();
+	gtk_label_set_mnemonic_widget ((GtkLabel *)label, name);
+
+	if (!rule->name) {
+		rule->name = g_strdup (_("Untitled"));
+		gtk_entry_set_text (GTK_ENTRY (name), rule->name);
+		/* FIXME: do we want the following code in the future? */
+		/*gtk_editable_select_region (GTK_EDITABLE (name), 0, -1);*/
+	} else {
+		gtk_entry_set_text (GTK_ENTRY (name), rule->name);
+	}
+
+	g_signal_connect (
+		name, "realize",
+		G_CALLBACK (gtk_widget_grab_focus), name);
+
+	hbox = gtk_hbox_new (FALSE, 12);
+	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (hbox), name, TRUE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+	g_signal_connect (name, "changed", G_CALLBACK (name_changed), rule);
+	gtk_widget_show (label);
+	gtk_widget_show (hbox);
+
+	hbox = gtk_hbox_new (FALSE, 12);
+	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+	gtk_widget_show (hbox);
+
+	text = g_strdup_printf ("<b>%s</b>", _("Find items that meet the following conditions"));
+	label = gtk_label_new (text);
+	gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+	gtk_widget_show (label);
+	g_free (text);
+
+	hbox = gtk_hbox_new (FALSE, 12);
+	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
+	gtk_widget_show (hbox);
+
+	label = gtk_label_new ("");
+	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+	gtk_widget_show (label);
+
+	inruleame = gtk_vbox_new (FALSE, 6);
+	gtk_box_pack_start (GTK_BOX (hbox), inruleame, TRUE, TRUE, 0);
+
+	/* this is the parts table, it should probably be inside a scrolling list */
+	rows = g_list_length (rule->parts);
+	parts = gtk_table_new (rows, 2, FALSE);
+
+	/* data for the parts part of the display */
+	data = g_malloc0 (sizeof (*data));
+	data->context = context;
+	data->rule = rule;
+	data->parts = parts;
+
+	/* only set to automatically clean up the memory */
+	g_object_set_data_full ((GObject *) vbox, "data", data, g_free);
+
+	hbox = gtk_hbox_new (FALSE, 3);
+
+	add = gtk_button_new_with_mnemonic (_("A_dd Condition"));
+	gtk_button_set_image (GTK_BUTTON (add), gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON));
+	g_signal_connect (add, "clicked", G_CALLBACK (more_parts), data);
+	gtk_box_pack_start (GTK_BOX (hbox), add, FALSE, FALSE, 0);
+
+	if (context->flags & E_RULE_CONTEXT_GROUPING) {
+		const gchar *thread_types[] = { N_("If all conditions are met"), N_("If any conditions are met") };
+
+		label = gtk_label_new_with_mnemonic (_("_Find items:"));
+		combobox = gtk_combo_box_new_text ();
+
+		for (i=0;i<2;i++) {
+			gtk_combo_box_append_text (GTK_COMBO_BOX (combobox), _(thread_types[i]));
+		}
+
+		gtk_label_set_mnemonic_widget ((GtkLabel *)label, combobox);
+		gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), rule->grouping);
+		gtk_widget_show (combobox);
+
+		gtk_box_pack_end (GTK_BOX (hbox), combobox, FALSE, FALSE, 0);
+		gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+		g_signal_connect (
+			combobox, "changed",
+			G_CALLBACK (filter_rule_grouping_changed_cb), rule);
+	}
+
+	if (context->flags & E_RULE_CONTEXT_THREADING) {
+		const gchar *thread_types[] = { N_("None"), N_("All related"), N_("Replies"), N_("Replies and parents"), N_("No reply or parent") };
+
+		label = gtk_label_new_with_mnemonic (_("I_nclude threads"));
+		combobox = gtk_combo_box_new_text ();
+
+		for (i=0;i<5;i++) {
+			gtk_combo_box_append_text (GTK_COMBO_BOX (combobox), _(thread_types[i]));
+		}
+
+		gtk_label_set_mnemonic_widget ((GtkLabel *)label, combobox);
+		gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), rule->threading);
+		gtk_widget_show (combobox);
+
+		gtk_box_pack_end (GTK_BOX (hbox), combobox, FALSE, FALSE, 0);
+		gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+		g_signal_connect (
+			combobox, "changed",
+			G_CALLBACK (filter_rule_threading_changed_cb), rule);
+	}
+
+	gtk_box_pack_start (GTK_BOX (inruleame), hbox, FALSE, FALSE, 3);
+
+	l = rule->parts;
+	i = 0;
+	while (l) {
+		part = l->data;
+		w = get_rule_part_widget (context, part, rule);
+		attach_rule (w, data, part, i++);
+		l = g_list_next (l);
+	}
+
+	hadj = gtk_adjustment_new (0.0, 0.0, 1.0, 1.0, 1.0, 1.0);
+	vadj = gtk_adjustment_new (0.0, 0.0, 1.0, 1.0, 1.0, 1.0);
+	scrolledwindow = gtk_scrolled_window_new (GTK_ADJUSTMENT (hadj), GTK_ADJUSTMENT (vadj));
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
+					GTK_POLICY_AUTOMATIC,
+					GTK_POLICY_AUTOMATIC);
+
+	gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolledwindow), parts);
+
+	gtk_box_pack_start (GTK_BOX (inruleame), scrolledwindow, TRUE, TRUE, 3);
+
+	gtk_widget_show_all (vbox);
+
+	g_object_set_data (G_OBJECT (add), "scrolled-window", scrolledwindow);
+
+	return vbox;
+}
+
+static void
+filter_rule_class_init (EFilterRuleClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EFilterRulePrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = filter_rule_finalize;
+
+	class->validate = filter_rule_validate;
+	class->eq = filter_rule_eq;
+	class->xml_encode = filter_rule_xml_encode;
+	class->xml_decode = filter_rule_xml_decode;
+	class->build_code = filter_rule_build_code;
+	class->copy = filter_rule_copy;
+	class->get_widget = filter_rule_get_widget;
+
+	signals[CHANGED] = g_signal_new (
+		"changed",
+		E_TYPE_FILTER_RULE,
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (EFilterRuleClass, changed),
+		NULL,
+		NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+}
+
+static void
+filter_rule_init (EFilterRule *rule)
+{
+	rule->priv = E_FILTER_RULE_GET_PRIVATE (rule);
+	rule->enabled = TRUE;
+}
+
+GType
+e_filter_rule_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EFilterRuleClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) filter_rule_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EFilterRule),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) filter_rule_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			G_TYPE_OBJECT, "EFilterRule", &type_info, 0);
+	}
+
+	return type;
+}
+
+/**
+ * filter_rule_new:
+ *
+ * Create a new EFilterRule object.
+ *
+ * Return value: A new #EFilterRule object.
+ **/
+EFilterRule *
+e_filter_rule_new (void)
+{
+	return g_object_new (E_TYPE_FILTER_RULE, NULL);
+}
+
+EFilterRule *
+e_filter_rule_clone (EFilterRule *rule)
+{
+	EFilterRule *clone;
+
+	g_return_val_if_fail (E_IS_FILTER_RULE (rule), NULL);
+
+	clone = g_object_new (G_OBJECT_TYPE (rule), NULL);
+	e_filter_rule_copy (clone, rule);
+
+	return clone;
+}
+
+void
+e_filter_rule_set_name (EFilterRule *rule,
+                        const gchar *name)
+{
+	g_return_if_fail (E_IS_FILTER_RULE (rule));
+
+	if (g_strcmp0 (rule->name, name) == 0)
+		return;
+
+	g_free (rule->name);
+	rule->name = g_strdup (name);
+
+	e_filter_rule_emit_changed (rule);
+}
+
+void
+e_filter_rule_set_source (EFilterRule *rule,
+                          const gchar *source)
+{
+	g_return_if_fail (E_IS_FILTER_RULE (rule));
+
+	if (g_strcmp0 (rule->source, source) == 0)
+		return;
+
+	g_free (rule->source);
+	rule->source = g_strdup (source);
+
+	e_filter_rule_emit_changed (rule);
+}
+
+gint
+e_filter_rule_validate (EFilterRule *rule,
+                        GtkWindow *error_parent)
+{
+	EFilterRuleClass *class;
+
+	g_return_val_if_fail (E_IS_FILTER_RULE (rule), FALSE);
+
+	class = E_FILTER_RULE_GET_CLASS (rule);
+	g_return_val_if_fail (class->validate != NULL, FALSE);
+
+	return class->validate (rule, error_parent);
+}
+
+gint
+e_filter_rule_eq (EFilterRule *rule_a,
+                  EFilterRule *rule_b)
+{
+	EFilterRuleClass *class;
+
+	g_return_val_if_fail (E_IS_FILTER_RULE (rule_a), FALSE);
+	g_return_val_if_fail (E_IS_FILTER_RULE (rule_b), FALSE);
+
+	class = E_FILTER_RULE_GET_CLASS (rule_a);
+	g_return_val_if_fail (class->eq != NULL, FALSE);
+
+	if (G_OBJECT_TYPE (rule_a) != G_OBJECT_TYPE (rule_b))
+		return FALSE;
+
+	return class->eq (rule_a, rule_b);
+}
+
+xmlNodePtr
+e_filter_rule_xml_encode (EFilterRule *rule)
+{
+	EFilterRuleClass *class;
+
+	g_return_val_if_fail (E_IS_FILTER_RULE (rule), NULL);
+
+	class = E_FILTER_RULE_GET_CLASS (rule);
+	g_return_val_if_fail (class->xml_encode != NULL, NULL);
+
+	return class->xml_encode (rule);
+}
+
+gint
+e_filter_rule_xml_decode (EFilterRule *rule,
+                          xmlNodePtr node,
+                          ERuleContext *context)
+{
+	EFilterRuleClass *class;
+	gint result;
+
+	g_return_val_if_fail (E_IS_FILTER_RULE (rule), FALSE);
+	g_return_val_if_fail (node != NULL, FALSE);
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), FALSE);
+
+	class = E_FILTER_RULE_GET_CLASS (rule);
+	g_return_val_if_fail (class->xml_decode != NULL, FALSE);
+
+	rule->priv->frozen++;
+	result = class->xml_decode (rule, node, context);
+	rule->priv->frozen--;
+
+	e_filter_rule_emit_changed (rule);
+
+	return result;
+}
+
+void
+e_filter_rule_copy (EFilterRule *dst_rule,
+                    EFilterRule *src_rule)
+{
+	EFilterRuleClass *class;
+
+	g_return_if_fail (E_IS_FILTER_RULE (dst_rule));
+	g_return_if_fail (E_IS_FILTER_RULE (src_rule));
+
+	class = E_FILTER_RULE_GET_CLASS (dst_rule);
+	g_return_if_fail (class->copy != NULL);
+
+	class->copy (dst_rule, src_rule);
+
+	e_filter_rule_emit_changed (dst_rule);
+}
+
+void
+e_filter_rule_add_part (EFilterRule *rule,
+                        EFilterPart *part)
+{
+	g_return_if_fail (E_IS_FILTER_RULE (rule));
+	g_return_if_fail (E_IS_FILTER_PART (part));
+
+	rule->parts = g_list_append (rule->parts, part);
+
+	e_filter_rule_emit_changed (rule);
+}
+
+void
+e_filter_rule_remove_part (EFilterRule *rule,
+                           EFilterPart *part)
+{
+	g_return_if_fail (E_IS_FILTER_RULE (rule));
+	g_return_if_fail (E_IS_FILTER_PART (part));
+
+	rule->parts = g_list_remove (rule->parts, part);
+
+	e_filter_rule_emit_changed (rule);
+}
+
+void
+e_filter_rule_replace_part (EFilterRule *rule,
+                            EFilterPart *old_part,
+                            EFilterPart *new_part)
+{
+	GList *link;
+
+	g_return_if_fail (E_IS_FILTER_RULE (rule));
+	g_return_if_fail (E_IS_FILTER_PART (old_part));
+	g_return_if_fail (E_IS_FILTER_PART (new_part));
+
+	link = g_list_find (rule->parts, old_part);
+	if (link != NULL)
+		link->data = new_part;
+	else
+		rule->parts = g_list_append (rule->parts, new_part);
+
+	e_filter_rule_emit_changed (rule);
+}
+
+void
+e_filter_rule_build_code (EFilterRule *rule,
+                          GString *out)
+{
+	EFilterRuleClass *class;
+
+	g_return_if_fail (E_IS_FILTER_RULE (rule));
+	g_return_if_fail (out != NULL);
+
+	class = E_FILTER_RULE_GET_CLASS (rule);
+	g_return_if_fail (class->build_code != NULL);
+
+	class->build_code (rule, out);
+}
+
+void
+e_filter_rule_emit_changed (EFilterRule *rule)
+{
+	g_return_if_fail (E_IS_FILTER_RULE (rule));
+
+	if (rule->priv->frozen == 0)
+		g_signal_emit (rule, signals[CHANGED], 0);
+}
+
+EFilterRule *
+e_filter_rule_next_list (GList *list,
+                         EFilterRule *last,
+                         const gchar *source)
+{
+	GList *link = list;
+
+	if (last != NULL) {
+		link = g_list_find (link, last);
+		if (link == NULL)
+			link = list;
+		else
+			link = g_list_next (link);
+	}
+
+	if (source != NULL) {
+		while (link != NULL) {
+			EFilterRule *rule = link->data;
+
+			if (g_strcmp0 (rule->source, source) == 0)
+				break;
+
+			link = g_list_next (link);
+		}
+	}
+
+	return (link != NULL) ? link->data : NULL;
+}
+
+EFilterRule *
+e_filter_rule_find_list (GList * list,
+                         const gchar *name,
+                         const gchar *source)
+{
+	GList *link;
+
+	g_return_val_if_fail (name != NULL, FALSE);
+
+	for (link = list; link != NULL; link = g_list_next (link)) {
+		EFilterRule *rule = link->data;
+
+		if (strcmp (rule->name, name) == 0)
+			if (source == NULL || (rule->source != NULL && strcmp (rule->source, source) == 0))
+				return rule;
+	}
+
+	return NULL;
+}
+
+#ifdef FOR_TRANSLATIONS_ONLY
+
+static gchar *list[] = {
+  N_("Incoming"), N_("Outgoing")
+};
+#endif
diff --git a/filter/e-filter-rule.h b/filter/e-filter-rule.h
new file mode 100644
index 0000000..c84cdef
--- /dev/null
+++ b/filter/e-filter-rule.h
@@ -0,0 +1,161 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_FILTER_RULE_H
+#define E_FILTER_RULE_H
+
+#include <glib-object.h>
+
+#include "e-filter-part.h"
+
+/* Standard GObject macros */
+#define E_TYPE_FILTER_RULE \
+	(e_filter_rule_get_type ())
+#define E_FILTER_RULE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_FILTER_RULE, EFilterRule))
+#define E_FILTER_RULE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_FILTER_RULE, EFilterRuleClass))
+#define E_IS_FILTER_RULE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_FILTER_RULE))
+#define E_IS_FILTER_RULE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_FILTER_RULE))
+#define E_FILTER_RULE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_FILTER_RULE, EFilterRuleClass))
+
+G_BEGIN_DECLS
+
+struct _RuleContext;
+
+typedef struct _EFilterRule EFilterRule;
+typedef struct _EFilterRuleClass EFilterRuleClass;
+typedef struct _EFilterRulePrivate EFilterRulePrivate;
+
+enum _filter_grouping_t {
+	E_FILTER_GROUP_ALL,	/* all rules must match */
+	E_FILTER_GROUP_ANY	/* any rule must match */
+};
+
+/* threading, if the context supports it */
+enum _filter_threading_t {
+	E_FILTER_THREAD_NONE,	/* don't add any thread matching */
+	E_FILTER_THREAD_ALL,	/* add all possible threads */
+	E_FILTER_THREAD_REPLIES,	/* add only replies */
+	E_FILTER_THREAD_REPLIES_PARENTS,	/* replies plus parents */
+	E_FILTER_THREAD_SINGLE	/* messages with no replies or parents */
+};
+
+#define E_FILTER_SOURCE_INCOMING "incoming" /* performed on incoming email */
+#define E_FILTER_SOURCE_DEMAND   "demand"   /* performed on the selected folder
+					     * when the user asks for it */
+#define E_FILTER_SOURCE_OUTGOING  "outgoing"/* performed on outgoing mail */
+#define E_FILTER_SOURCE_JUNKTEST  "junktest"/* perform only junktest on incoming mail */
+
+struct _EFilterRule {
+	GObject parent_object;
+	EFilterRulePrivate *priv;
+
+	gchar *name;
+	gchar *source;
+
+	enum _filter_grouping_t grouping;
+	enum _filter_threading_t threading;
+
+	guint system:1;	/* this is a system rule, cannot be edited/deleted */
+	GList *parts;
+
+	gboolean enabled;
+};
+
+struct _EFilterRuleClass {
+	GObjectClass parent_class;
+
+	/* virtual methods */
+	gint		(*validate)		(EFilterRule *rule,
+						 GtkWindow *error_parent);
+	gint		(*eq)			(EFilterRule *rule_a,
+						 EFilterRule *rule_b);
+
+	xmlNodePtr	(*xml_encode)		(EFilterRule *rule);
+	gint		(*xml_decode)		(EFilterRule *rule,
+						 xmlNodePtr node,
+						 struct _ERuleContext *context);
+
+	void		(*build_code)		(EFilterRule *rule,
+						 GString *out);
+
+	void		(*copy)			(EFilterRule *dst_rule,
+						 EFilterRule *src_rule);
+
+	GtkWidget *	(*get_widget)		(EFilterRule *rule,
+						 struct _ERuleContext *context);
+
+	/* signals */
+	void		(*changed)		(EFilterRule *rule);
+};
+
+GType		e_filter_rule_get_type		(void);
+EFilterRule *	e_filter_rule_new		(void);
+EFilterRule *	e_filter_rule_clone		(EFilterRule *rule);
+void		e_filter_rule_set_name		(EFilterRule *rule,
+						 const gchar *name);
+void		e_filter_rule_set_source	(EFilterRule *rule,
+						 const gchar *source);
+gint		e_filter_rule_validate		(EFilterRule *rule,
+						 GtkWindow *error_parent);
+gint		e_filter_rule_eq		(EFilterRule *rule_a,
+						 EFilterRule *rule_b);
+xmlNodePtr	e_filter_rule_xml_encode	(EFilterRule *rule);
+gint		e_filter_rule_xml_decode	(EFilterRule *rule,
+						 xmlNodePtr node,
+						 struct _ERuleContext *context);
+void		e_filter_rule_copy		(EFilterRule *dst_rule,
+						 EFilterRule *src_rule);
+void		e_filter_rule_add_part		(EFilterRule *rule,
+						 EFilterPart *part);
+void		e_filter_rule_remove_part	(EFilterRule *rule,
+						 EFilterPart *part);
+void		e_filter_rule_replace_part	(EFilterRule *rule,
+						 EFilterPart *old_part,
+						 EFilterPart *new_part);
+GtkWidget *	e_filter_rule_get_widget	(EFilterRule *rule,
+						 struct _ERuleContext *context);
+void		e_filter_rule_build_code	(EFilterRule *rule,
+						 GString *out);
+void		e_filter_rule_emit_changed	(EFilterRule *rule);
+
+/* static functions */
+EFilterRule *	e_filter_rule_next_list		(GList *list,
+						 EFilterRule *last,
+						 const gchar *source);
+EFilterRule *	e_filter_rule_find_list		(GList *list,
+						 const gchar *name,
+						 const gchar *source);
+
+G_END_DECLS
+
+#endif /* E_FILTER_RULE_H */
diff --git a/filter/e-rule-context.c b/filter/e-rule-context.c
new file mode 100644
index 0000000..648011b
--- /dev/null
+++ b/filter/e-rule-context.c
@@ -0,0 +1,988 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <gtk/gtk.h>
+
+#include <glib/gi18n.h>
+
+#include <libedataserver/e-xml-utils.h>
+
+#include "e-util/e-error.h"
+#include "e-util/e-xml-utils.h"
+
+#include "e-filter-code.h"
+#include "e-filter-color.h"
+#include "e-filter-datespec.h"
+#include "e-filter-file.h"
+#include "e-filter-input.h"
+#include "e-filter-int.h"
+#include "e-filter-option.h"
+#include "e-filter-rule.h"
+#include "e-rule-context.h"
+
+#define E_RULE_CONTEXT_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_RULE_CONTEXT, ERuleContextPrivate))
+
+struct _ERuleContextPrivate {
+	gint frozen;
+};
+
+enum {
+	RULE_ADDED,
+	RULE_REMOVED,
+	CHANGED,
+	LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+struct _revert_data {
+	GHashTable *rules;
+	gint rank;
+};
+
+static void
+rule_context_set_error (ERuleContext *context,
+                        gchar *error)
+{
+	g_free (context->error);
+	context->error = error;
+}
+
+static void
+new_rule_response (GtkWidget *dialog,
+                   gint button,
+                   ERuleContext *context)
+{
+	if (button == GTK_RESPONSE_OK) {
+		EFilterRule *rule = g_object_get_data ((GObject *) dialog, "rule");
+		gchar *user = g_object_get_data ((GObject *) dialog, "path");
+
+		if (!e_filter_rule_validate (rule, GTK_WINDOW (dialog))) {
+			/* no need to popup a dialog because the validate code does that. */
+			return;
+		}
+
+		if (e_rule_context_find_rule (context, rule->name, rule->source)) {
+			e_error_run ((GtkWindow *)dialog, "filter:bad-name-notunique", rule->name, NULL);
+
+			return;
+		}
+
+		g_object_ref (rule);
+		e_rule_context_add_rule (context, rule);
+		if (user)
+			e_rule_context_save (context, user);
+	}
+
+	gtk_widget_destroy (dialog);
+}
+
+static void
+revert_rule_remove (gpointer key,
+                    EFilterRule *rule,
+                    ERuleContext *context)
+{
+	e_rule_context_remove_rule (context, rule);
+	g_object_unref (rule);
+}
+
+static void
+revert_source_remove (gpointer key,
+                      struct _revert_data *rest_data,
+                      ERuleContext *context)
+{
+	g_hash_table_foreach (
+		rest_data->rules, (GHFunc) revert_rule_remove, context);
+	g_hash_table_destroy (rest_data->rules);
+	g_free (rest_data);
+}
+
+static guint
+source_hashf (const gchar *a)
+{
+	return (a != NULL) ? g_str_hash (a) : 0;
+}
+
+static gint
+source_eqf (const gchar *a,
+            const gchar *b)
+{
+	return (g_strcmp0 (a, b) == 0);
+}
+
+static void
+free_part_set (struct _part_set_map *map)
+{
+	g_free (map->name);
+	g_free (map);
+}
+
+static void
+free_rule_set (struct _rule_set_map *map)
+{
+	g_free (map->name);
+	g_free (map);
+}
+
+static void
+rule_context_finalize (GObject *obj)
+{
+	ERuleContext *context =(ERuleContext *) obj;
+
+	g_list_foreach (context->rule_set_list, (GFunc)free_rule_set, NULL);
+	g_list_free (context->rule_set_list);
+	g_hash_table_destroy (context->rule_set_map);
+
+	g_list_foreach (context->part_set_list, (GFunc)free_part_set, NULL);
+	g_list_free (context->part_set_list);
+	g_hash_table_destroy (context->part_set_map);
+
+	g_free (context->error);
+
+	g_list_foreach (context->parts, (GFunc)g_object_unref, NULL);
+	g_list_free (context->parts);
+
+	g_list_foreach (context->rules, (GFunc)g_object_unref, NULL);
+	g_list_free (context->rules);
+
+	G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static gint
+rule_context_load (ERuleContext *context,
+                   const gchar *system,
+                   const gchar *user)
+{
+	xmlNodePtr set, rule, root;
+	xmlDocPtr systemdoc, userdoc;
+	struct _part_set_map *part_map;
+	struct _rule_set_map *rule_map;
+
+	rule_context_set_error (context, NULL);
+
+	systemdoc = e_xml_parse_file (system);
+	if (systemdoc == NULL) {
+		rule_context_set_error (context, g_strdup_printf ("Unable to load system rules '%s': %s",
+							     system, g_strerror (errno)));
+		return -1;
+	}
+
+	root = xmlDocGetRootElement (systemdoc);
+	if (root == NULL || strcmp ((gchar *)root->name, "filterdescription")) {
+		rule_context_set_error (context, g_strdup_printf ("Unable to load system rules '%s': Invalid format", system));
+		xmlFreeDoc (systemdoc);
+		return -1;
+	}
+	/* doesn't matter if this doens't exist */
+	userdoc = NULL;
+	if (g_file_test (user, G_FILE_TEST_IS_REGULAR))
+		userdoc = e_xml_parse_file (user);
+
+	/* now parse structure */
+	/* get rule parts */
+	set = root->children;
+	while (set) {
+		part_map = g_hash_table_lookup (context->part_set_map, set->name);
+		if (part_map) {
+			rule = set->children;
+			while (rule) {
+				if (!strcmp ((gchar *)rule->name, "part")) {
+					EFilterPart *part = E_FILTER_PART (g_object_new (part_map->type, NULL, NULL));
+
+					if (e_filter_part_xml_create (part, rule, context) == 0) {
+						part_map->append (context, part);
+					} else {
+						g_object_unref (part);
+						g_warning ("Cannot load filter part");
+					}
+				}
+				rule = rule->next;
+			}
+		} else if ((rule_map = g_hash_table_lookup (context->rule_set_map, set->name))) {
+			rule = set->children;
+			while (rule) {
+				if (!strcmp ((gchar *)rule->name, "rule")) {
+					EFilterRule *part = E_FILTER_RULE (g_object_new (rule_map->type, NULL, NULL));
+
+					if (e_filter_rule_xml_decode (part, rule, context) == 0) {
+						part->system = TRUE;
+						rule_map->append (context, part);
+					} else {
+						g_object_unref (part);
+						g_warning ("Cannot load filter part");
+					}
+				}
+				rule = rule->next;
+			}
+		}
+		set = set->next;
+	}
+
+	/* now load actual rules */
+	if (userdoc) {
+		root = xmlDocGetRootElement (userdoc);
+		set = root?root->children:NULL;
+		while (set) {
+			rule_map = g_hash_table_lookup (context->rule_set_map, set->name);
+			if (rule_map) {
+				rule = set->children;
+				while (rule) {
+					if (!strcmp ((gchar *)rule->name, "rule")) {
+						EFilterRule *part = E_FILTER_RULE (g_object_new (rule_map->type, NULL, NULL));
+
+						if (e_filter_rule_xml_decode (part, rule, context) == 0) {
+							rule_map->append (context, part);
+						} else {
+							g_object_unref (part);
+							g_warning ("Cannot load filter part");
+						}
+					}
+					rule = rule->next;
+				}
+			}
+			set = set->next;
+		}
+	}
+
+	xmlFreeDoc (userdoc);
+	xmlFreeDoc (systemdoc);
+
+	return 0;
+}
+
+static gint
+rule_context_save (ERuleContext *context,
+                   const gchar *user)
+{
+	xmlDocPtr doc;
+	xmlNodePtr root, rules, work;
+	GList *l;
+	EFilterRule *rule;
+	struct _rule_set_map *map;
+	gint ret;
+
+	doc = xmlNewDoc ((xmlChar *)"1.0");
+	/* FIXME: set character encoding to UTF-8? */
+	root = xmlNewDocNode (doc, NULL, (xmlChar *)"filteroptions", NULL);
+	xmlDocSetRootElement (doc, root);
+	l = context->rule_set_list;
+	while (l) {
+		map = l->data;
+		rules = xmlNewDocNode (doc, NULL, (xmlChar *)map->name, NULL);
+		xmlAddChild (root, rules);
+		rule = NULL;
+		while ((rule = map->next (context, rule, NULL))) {
+			if (!rule->system) {
+				work = e_filter_rule_xml_encode (rule);
+				xmlAddChild (rules, work);
+			}
+		}
+		l = g_list_next (l);
+	}
+
+	ret = e_xml_save_file (user, doc);
+
+	xmlFreeDoc (doc);
+
+	return ret;
+}
+
+static gint
+rule_context_revert (ERuleContext *context,
+                     const gchar *user)
+{
+	xmlNodePtr set, rule;
+	/*struct _part_set_map *part_map;*/
+	struct _rule_set_map *rule_map;
+	struct _revert_data *rest_data;
+	GHashTable *source_hash;
+	xmlDocPtr userdoc;
+	EFilterRule *frule;
+
+	rule_context_set_error (context, NULL);
+
+	userdoc = e_xml_parse_file (user);
+	if (userdoc == NULL)
+		/* clear out anythign we have? */
+		return 0;
+
+	source_hash = g_hash_table_new ((GHashFunc)source_hashf, (GCompareFunc)source_eqf);
+
+	/* setup stuff we have now */
+	/* Note that we assume there is only 1 set of rules in a given rule context,
+	   although other parts of the code dont assume this */
+	frule = NULL;
+	while ((frule = e_rule_context_next_rule (context, frule, NULL))) {
+		rest_data = g_hash_table_lookup (source_hash, frule->source);
+		if (rest_data == NULL) {
+			rest_data = g_malloc0 (sizeof (*rest_data));
+			rest_data->rules = g_hash_table_new (g_str_hash, g_str_equal);
+			g_hash_table_insert (source_hash, frule->source, rest_data);
+		}
+		g_hash_table_insert (rest_data->rules, frule->name, frule);
+	}
+
+	/* make what we have, match what we load */
+	set = xmlDocGetRootElement (userdoc);
+	set = set?set->children:NULL;
+	while (set) {
+		rule_map = g_hash_table_lookup (context->rule_set_map, set->name);
+		if (rule_map) {
+			rule = set->children;
+			while (rule) {
+				if (!strcmp ((gchar *)rule->name, "rule")) {
+					EFilterRule *part = E_FILTER_RULE (g_object_new (rule_map->type, NULL, NULL));
+
+					if (e_filter_rule_xml_decode (part, rule, context) == 0) {
+						/* use the revert data to keep track of the right rank of this rule part */
+						rest_data = g_hash_table_lookup (source_hash, part->source);
+						if (rest_data == NULL) {
+							rest_data = g_malloc0 (sizeof (*rest_data));
+							rest_data->rules = g_hash_table_new (g_str_hash, g_str_equal);
+							g_hash_table_insert (source_hash, part->source, rest_data);
+						}
+						frule = g_hash_table_lookup (rest_data->rules, part->name);
+						if (frule) {
+							if (context->priv->frozen == 0 && !e_filter_rule_eq (frule, part))
+								e_filter_rule_copy (frule, part);
+
+							g_object_unref (part);
+							e_rule_context_rank_rule (context, frule, frule->source, rest_data->rank);
+							g_hash_table_remove (rest_data->rules, frule->name);
+						} else {
+							e_rule_context_add_rule (context, part);
+							e_rule_context_rank_rule (context, part, part->source, rest_data->rank);
+						}
+						rest_data->rank++;
+					} else {
+						g_object_unref (part);
+						g_warning ("Cannot load filter part");
+					}
+				}
+				rule = rule->next;
+			}
+		}
+		set = set->next;
+	}
+
+	xmlFreeDoc (userdoc);
+
+	/* remove any we still have that weren't in the file */
+	g_hash_table_foreach (source_hash, (GHFunc)revert_source_remove, context);
+	g_hash_table_destroy (source_hash);
+
+	return 0;
+}
+
+static EFilterElement *
+rule_context_new_element (ERuleContext *context,
+                          const gchar *type)
+{
+	if (!strcmp (type, "string")) {
+		return (EFilterElement *) e_filter_input_new ();
+	} else if (!strcmp (type, "address")) {
+		/* FIXME: temporary ... need real address type */
+		return (EFilterElement *) e_filter_input_new_type_name (type);
+	} else if (!strcmp (type, "code")) {
+		return (EFilterElement *) e_filter_code_new (FALSE);
+	} else if (!strcmp (type, "rawcode")) {
+		return (EFilterElement *) e_filter_code_new (TRUE);
+	} else if (!strcmp (type, "colour")) {
+		return (EFilterElement *) e_filter_color_new ();
+	} else if (!strcmp (type, "optionlist")) {
+		return (EFilterElement *) e_filter_option_new ();
+	} else if (!strcmp (type, "datespec")) {
+		return (EFilterElement *) e_filter_datespec_new ();
+	} else if (!strcmp (type, "command")) {
+		return (EFilterElement *) e_filter_file_new_type_name (type);
+	} else if (!strcmp (type, "file")) {
+		return (EFilterElement *) e_filter_file_new_type_name (type);
+	} else if (!strcmp (type, "integer")) {
+		return (EFilterElement *) e_filter_int_new ();
+	} else if (!strcmp (type, "regex")) {
+		return (EFilterElement *) e_filter_input_new_type_name (type);
+	}else if (!strcmp (type, "completedpercent")) {
+                 return (EFilterElement *) e_filter_int_new_type ("completedpercent", 0,100);
+
+	} else {
+		g_warning ("Unknown filter type '%s'", type);
+		return NULL;
+	}
+}
+
+static void
+rule_context_class_init (ERuleContextClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (ERuleContextPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = rule_context_finalize;
+
+	class->load = rule_context_load;
+	class->save = rule_context_save;
+	class->revert = rule_context_revert;
+	class->new_element = rule_context_new_element;
+
+	signals[RULE_ADDED] = g_signal_new (
+		"rule-added",
+		E_TYPE_RULE_CONTEXT,
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (ERuleContextClass, rule_added),
+		NULL,
+		NULL,
+		g_cclosure_marshal_VOID__POINTER,
+		G_TYPE_NONE, 1,
+		G_TYPE_POINTER);
+
+	signals[RULE_REMOVED] = g_signal_new (
+		"rule-removed",
+		E_TYPE_RULE_CONTEXT,
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (ERuleContextClass, rule_removed),
+		NULL,
+		NULL,
+		g_cclosure_marshal_VOID__POINTER,
+		G_TYPE_NONE, 1,
+		G_TYPE_POINTER);
+
+	signals[CHANGED] = g_signal_new (
+		"changed",
+		E_TYPE_RULE_CONTEXT,
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (ERuleContextClass, changed),
+		NULL,
+		NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+}
+
+static void
+rule_context_init (ERuleContext *context)
+{
+	context->priv = E_RULE_CONTEXT_GET_PRIVATE (context);
+
+	context->part_set_map = g_hash_table_new (g_str_hash, g_str_equal);
+	context->rule_set_map = g_hash_table_new (g_str_hash, g_str_equal);
+
+	context->flags = E_RULE_CONTEXT_GROUPING;
+}
+
+GType
+e_rule_context_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (ERuleContextClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) rule_context_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (ERuleContext),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) rule_context_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			G_TYPE_OBJECT, "ERuleContext", &type_info, 0);
+	}
+
+	return type;
+}
+
+/**
+ * e_rule_context_new:
+ *
+ * Create a new ERuleContext object.
+ *
+ * Return value: A new #ERuleContext object.
+ **/
+ERuleContext *
+e_rule_context_new (void)
+{
+	return g_object_new (E_TYPE_RULE_CONTEXT, NULL);
+}
+
+void
+e_rule_context_add_part_set (ERuleContext *context,
+                             const gchar *setname,
+                             GType part_type,
+                             ERuleContextPartFunc append,
+                             ERuleContextNextPartFunc next)
+{
+	struct _part_set_map *map;
+
+	g_return_if_fail (E_IS_RULE_CONTEXT (context));
+	g_return_if_fail (setname != NULL);
+	g_return_if_fail (append != NULL);
+	g_return_if_fail (next != NULL);
+
+	g_return_if_fail (g_hash_table_lookup (context->part_set_map, setname) == NULL);
+
+	map = g_malloc0 (sizeof (*map));
+	map->type = part_type;
+	map->append = append;
+	map->next = next;
+	map->name = g_strdup (setname);
+	g_hash_table_insert (context->part_set_map, map->name, map);
+	context->part_set_list = g_list_append (context->part_set_list, map);
+}
+
+void
+e_rule_context_add_rule_set (ERuleContext *context,
+                             const gchar *setname,
+                             GType rule_type,
+                             ERuleContextRuleFunc append,
+                             ERuleContextNextRuleFunc next)
+{
+	struct _rule_set_map *map;
+
+	g_return_if_fail (E_IS_RULE_CONTEXT (context));
+	g_return_if_fail (setname != NULL);
+	g_return_if_fail (append != NULL);
+	g_return_if_fail (next != NULL);
+
+	g_return_if_fail (g_hash_table_lookup (context->rule_set_map, setname) == NULL);
+
+	map = g_malloc0 (sizeof (*map));
+	map->type = rule_type;
+	map->append = append;
+	map->next = next;
+	map->name = g_strdup (setname);
+	g_hash_table_insert (context->rule_set_map, map->name, map);
+	context->rule_set_list = g_list_append (context->rule_set_list, map);
+}
+
+/**
+ * e_rule_context_load:
+ * @f:
+ * @system:
+ * @user:
+ *
+ * Load a rule context from a system and user description file.
+ *
+ * Return value:
+ **/
+gint
+e_rule_context_load (ERuleContext *context,
+                     const gchar *system,
+                     const gchar *user)
+{
+	ERuleContextClass *class;
+	gint result;
+
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), -1);
+	g_return_val_if_fail (system != NULL, -1);
+	g_return_val_if_fail (user != NULL, -1);
+
+	class = E_RULE_CONTEXT_GET_CLASS (context);
+	g_return_val_if_fail (class->load != NULL, -1);
+
+	context->priv->frozen++;
+	result = class->load (context, system, user);
+	context->priv->frozen--;
+
+	return result;
+}
+
+/**
+ * e_rule_context_save:
+ * @f:
+ * @user:
+ *
+ * Save a rule context to disk.
+ *
+ * Return value:
+ **/
+gint
+e_rule_context_save (ERuleContext *context,
+                     const gchar *user)
+{
+	ERuleContextClass *class;
+
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), -1);
+	g_return_val_if_fail (user != NULL, -1);
+
+	class = E_RULE_CONTEXT_GET_CLASS (context);
+	g_return_val_if_fail (class->save != NULL, -1);
+
+	return class->save (context, user);
+}
+
+/**
+ * e_rule_context_revert:
+ * @f:
+ * @user:
+ *
+ * Reverts a rule context from a user description file.  Assumes the
+ * system description file is unchanged from when it was loaded.
+ *
+ * Return value:
+ **/
+gint
+e_rule_context_revert (ERuleContext *context,
+                       const gchar *user)
+{
+	ERuleContextClass *class;
+
+	g_return_val_if_fail (E_RULE_CONTEXT (context), 0);
+	g_return_val_if_fail (user != NULL, 0);
+
+	class = E_RULE_CONTEXT_GET_CLASS (context);
+	g_return_val_if_fail (class->revert != NULL, 0);
+
+	return class->revert (context, user);
+}
+
+EFilterPart *
+e_rule_context_find_part (ERuleContext *context,
+                          const gchar *name)
+{
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
+	g_return_val_if_fail (name != NULL, NULL);
+
+	return e_filter_part_find_list (context->parts, name);
+}
+
+EFilterPart *
+e_rule_context_create_part (ERuleContext *context,
+                            const gchar *name)
+{
+	EFilterPart *part;
+
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
+	g_return_val_if_fail (name != NULL, NULL);
+
+	part = e_rule_context_find_part (context, name);
+
+	if (part == NULL)
+		return NULL;
+
+	return e_filter_part_clone (part);
+}
+
+EFilterPart *
+e_rule_context_next_part (ERuleContext *context,
+                          EFilterPart *last)
+{
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
+
+	return e_filter_part_next_list (context->parts, last);
+}
+
+EFilterRule *
+e_rule_context_next_rule (ERuleContext *context,
+                          EFilterRule *last,
+                          const gchar *source)
+{
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
+
+	return e_filter_rule_next_list (context->rules, last, source);
+}
+
+EFilterRule *
+e_rule_context_find_rule (ERuleContext *context,
+                          const gchar *name,
+                          const gchar *source)
+{
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
+	g_return_val_if_fail (name != NULL, NULL);
+
+	return e_filter_rule_find_list (context->rules, name, source);
+}
+
+void
+e_rule_context_add_part (ERuleContext *context,
+                         EFilterPart *part)
+{
+	g_return_if_fail (E_IS_RULE_CONTEXT (context));
+	g_return_if_fail (E_IS_FILTER_PART (part));
+
+	context->parts = g_list_append (context->parts, part);
+}
+
+void
+e_rule_context_add_rule (ERuleContext *context,
+                         EFilterRule *rule)
+{
+	g_return_if_fail (E_IS_RULE_CONTEXT (context));
+	g_return_if_fail (E_IS_FILTER_RULE (rule));
+
+	context->rules = g_list_append (context->rules, rule);
+
+	if (context->priv->frozen == 0) {
+		g_signal_emit (context, signals[RULE_ADDED], 0, rule);
+		g_signal_emit (context, signals[CHANGED], 0);
+	}
+}
+
+/* add a rule, with a gui, asking for confirmation first ... optionally save to path */
+void
+e_rule_context_add_rule_gui (ERuleContext *context,
+                             EFilterRule *rule,
+                             const gchar *title,
+                             const gchar *path)
+{
+	GtkDialog *dialog;
+	GtkWidget *widget;
+	GtkWidget *content_area;
+
+	g_return_if_fail (E_IS_RULE_CONTEXT (context));
+	g_return_if_fail (E_IS_FILTER_RULE (rule));
+
+	widget = e_filter_rule_get_widget (rule, context);
+	gtk_widget_show (widget);
+
+	dialog =(GtkDialog *) gtk_dialog_new ();
+	gtk_dialog_add_buttons (dialog,
+			       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+			       GTK_STOCK_OK, GTK_RESPONSE_OK,
+			       NULL);
+	gtk_dialog_set_has_separator (dialog, FALSE);
+
+	gtk_window_set_title ((GtkWindow *) dialog, title);
+	gtk_window_set_default_size ((GtkWindow *) dialog, 600, 400);
+	gtk_window_set_resizable ((GtkWindow *) dialog, TRUE);
+
+	content_area = gtk_dialog_get_content_area (dialog);
+	gtk_box_pack_start (GTK_BOX (content_area), widget, TRUE, TRUE, 0);
+
+	g_object_set_data_full ((GObject *) dialog, "rule", rule, g_object_unref);
+	if (path)
+		g_object_set_data_full ((GObject *) dialog, "path", g_strdup (path), g_free);
+
+	g_signal_connect (dialog, "response", G_CALLBACK (new_rule_response), context);
+
+	g_object_ref (context);
+
+	g_object_set_data_full ((GObject *) dialog, "context", context, g_object_unref);
+
+	gtk_widget_show ((GtkWidget *) dialog);
+}
+
+void
+e_rule_context_remove_rule (ERuleContext *context,
+                            EFilterRule *rule)
+{
+	g_return_if_fail (E_IS_RULE_CONTEXT (context));
+	g_return_if_fail (E_IS_FILTER_RULE (rule));
+
+	context->rules = g_list_remove (context->rules, rule);
+
+	if (context->priv->frozen == 0) {
+		g_signal_emit (context, signals[RULE_REMOVED], 0, rule);
+		g_signal_emit (context, signals[CHANGED], 0);
+	}
+}
+
+void
+e_rule_context_rank_rule (ERuleContext *context,
+                          EFilterRule *rule,
+                          const gchar *source,
+                          gint rank)
+{
+	GList *node;
+	gint i = 0, index = 0;
+
+	g_return_if_fail (E_IS_RULE_CONTEXT (context));
+	g_return_if_fail (E_IS_FILTER_RULE (rule));
+
+	if (e_rule_context_get_rank_rule (context, rule, source) == rank)
+		return;
+
+	context->rules = g_list_remove (context->rules, rule);
+	node = context->rules;
+	while (node) {
+		EFilterRule *r = node->data;
+
+		if (i == rank) {
+			context->rules = g_list_insert (context->rules, rule, index);
+			if (context->priv->frozen == 0)
+				g_signal_emit (context, signals[CHANGED], 0);
+
+			return;
+		}
+
+		index++;
+		if (source == NULL || (r->source && strcmp (r->source, source) == 0))
+			i++;
+
+		node = node->next;
+	}
+
+	context->rules = g_list_append (context->rules, rule);
+	if (context->priv->frozen == 0)
+		g_signal_emit (context, signals[CHANGED], 0);
+}
+
+gint
+e_rule_context_get_rank_rule (ERuleContext *context,
+                              EFilterRule *rule,
+                              const gchar *source)
+{
+	GList *node;
+	gint i = 0;
+
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), -1);
+	g_return_val_if_fail (E_IS_FILTER_RULE (rule), -1);
+
+	node = context->rules;
+	while (node) {
+		EFilterRule *r = node->data;
+
+		if (r == rule)
+			return i;
+
+		if (source == NULL || (r->source && strcmp (r->source, source) == 0))
+			i++;
+
+		node = node->next;
+	}
+
+	return -1;
+}
+
+EFilterRule *
+e_rule_context_find_rank_rule (ERuleContext *context,
+                               gint rank,
+                               const gchar *source)
+{
+	GList *node;
+	gint i = 0;
+
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
+
+	node = context->rules;
+	while (node) {
+		EFilterRule *r = node->data;
+
+		if (source == NULL || (r->source && strcmp (r->source, source) == 0)) {
+			if (rank == i)
+				return r;
+			i++;
+		}
+
+		node = node->next;
+	}
+
+	return NULL;
+}
+
+GList *
+e_rule_context_rename_uri (ERuleContext *context,
+                           const gchar *old_uri,
+                           const gchar *new_uri,
+                           GCompareFunc compare)
+{
+	ERuleContextClass *class;
+
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
+	g_return_val_if_fail (old_uri != NULL, NULL);
+	g_return_val_if_fail (new_uri != NULL, NULL);
+	g_return_val_if_fail (compare != NULL, NULL);
+
+	class = E_RULE_CONTEXT_GET_CLASS (context);
+
+	/* This method is optional. */
+	if (class->rename_uri == NULL)
+		return NULL;
+
+	return class->rename_uri (context, old_uri, new_uri, compare);
+}
+
+GList *
+e_rule_context_delete_uri (ERuleContext *context,
+                           const gchar *uri,
+                           GCompareFunc compare)
+{
+	ERuleContextClass *class;
+
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
+	g_return_val_if_fail (uri != NULL, NULL);
+	g_return_val_if_fail (compare != NULL, NULL);
+
+	class = E_RULE_CONTEXT_GET_CLASS (context);
+
+	/* This method is optional. */
+	if (class->delete_uri == NULL)
+		return NULL;
+
+	return class->delete_uri (context, uri, compare);
+}
+
+void
+e_rule_context_free_uri_list (ERuleContext *context,
+                              GList *uris)
+{
+	g_return_if_fail (E_IS_RULE_CONTEXT (context));
+
+	/* TODO: should be virtual */
+
+	g_list_foreach (uris, (GFunc) g_free, NULL);
+	g_list_free (uris);
+}
+
+/**
+ * e_rule_context_new_element:
+ * @context:
+ * @name:
+ *
+ * create a new filter element based on name.
+ *
+ * Return value:
+ **/
+EFilterElement *
+e_rule_context_new_element (ERuleContext *context,
+                            const gchar *name)
+{
+	ERuleContextClass *class;
+
+	g_return_val_if_fail (E_IS_RULE_CONTEXT (context), NULL);
+	g_return_val_if_fail (name != NULL, NULL);
+
+	class = E_RULE_CONTEXT_GET_CLASS (context);
+	g_return_val_if_fail (class->new_element != NULL, NULL);
+
+	return class->new_element (context, name);
+}
diff --git a/filter/e-rule-context.h b/filter/e-rule-context.h
new file mode 100644
index 0000000..102faef
--- /dev/null
+++ b/filter/e-rule-context.h
@@ -0,0 +1,215 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_RULE_CONTEXT_H
+#define E_RULE_CONTEXT_H
+
+#include <glib-object.h>
+#include <libxml/parser.h>
+
+#include "e-filter-part.h"
+#include "e-filter-rule.h"
+
+/* Standard GObject macros */
+#define E_TYPE_RULE_CONTEXT \
+	(e_rule_context_get_type ())
+#define E_RULE_CONTEXT(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_RULE_CONTEXT, ERuleContext))
+#define E_RULE_CONTEXT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_RULE_CONTEXT, ERuleContextClass))
+#define E_IS_RULE_CONTEXT(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_RULE_CONTEXT))
+#define E_IS_RULE_CONTEXT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_RULE_CONTEXT))
+#define E_RULE_CONTEXT_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_RULE_CONTEXT, ERuleContextClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ERuleContext ERuleContext;
+typedef struct _ERuleContextClass ERuleContextClass;
+typedef struct _ERuleContextPrivate ERuleContextPrivate;
+
+/* backend capabilities, this is a hack since we don't support nested rules */
+enum {
+	E_RULE_CONTEXT_GROUPING  = 1 << 0,
+	E_RULE_CONTEXT_THREADING = 1 << 1
+};
+
+typedef void	(*ERuleContextRegisterFunc)	(ERuleContext *context,
+						 EFilterRule *rule,
+						 gpointer user_data);
+typedef void	(*ERuleContextPartFunc)		(ERuleContext *context,
+						 EFilterPart *part);
+typedef void	(*ERuleContextRuleFunc)		(ERuleContext *context,
+						 EFilterRule *part);
+typedef EFilterPart *
+		(*ERuleContextNextPartFunc)	(ERuleContext *context,
+						 EFilterPart *part);
+typedef EFilterRule *
+		(*ERuleContextNextRuleFunc)	(ERuleContext *context,
+						 EFilterRule *rule,
+						 const gchar *source);
+
+struct _ERuleContext {
+	GObject parent;
+	ERuleContextPrivate *priv;
+
+	gchar *error;		/* string version of error */
+
+	guint32 flags;		/* capability flags */
+
+	GList *parts;
+	GList *rules;
+
+	GHashTable *part_set_map; /* map set types to part types */
+	GList *part_set_list;
+	GHashTable *rule_set_map; /* map set types to rule types */
+	GList *rule_set_list;
+};
+
+struct _ERuleContextClass {
+	GObjectClass parent_class;
+
+	/* methods */
+	gint		(*load)			(ERuleContext *context,
+						 const gchar *system,
+						 const gchar *user);
+	gint		(*save)			(ERuleContext *context,
+						 const gchar *user);
+	gint		(*revert)		(ERuleContext *context,
+						 const gchar *user);
+
+	GList *		(*delete_uri)		(ERuleContext *context,
+						 const gchar *uri,
+						 GCompareFunc compare_func);
+	GList *		(*rename_uri)		(ERuleContext *context,
+						 const gchar *old_uri,
+						 const gchar *new_uri,
+						 GCompareFunc compare_func);
+
+	EFilterElement *(*new_element)		(ERuleContext *context,
+						 const gchar *name);
+
+	/* signals */
+	void		(*rule_added)		(ERuleContext *context,
+						 EFilterRule *rule);
+	void		(*rule_removed)		(ERuleContext *context,
+						 EFilterRule *rule);
+	void		(*changed)		(ERuleContext *context);
+};
+
+struct _part_set_map {
+	gchar *name;
+	GType type;
+	ERuleContextPartFunc append;
+	ERuleContextNextPartFunc next;
+};
+
+struct _rule_set_map {
+	gchar *name;
+	GType type;
+	ERuleContextRuleFunc append;
+	ERuleContextNextRuleFunc next;
+};
+
+GType		e_rule_context_get_type		(void);
+ERuleContext *	e_rule_context_new		(void);
+
+gint		e_rule_context_load		(ERuleContext *context,
+						 const gchar *system,
+						 const gchar *user);
+gint		e_rule_context_save		(ERuleContext *context,
+						 const gchar *user);
+gint		e_rule_context_revert		(ERuleContext *context,
+						 const gchar *user);
+
+void		e_rule_context_add_part		(ERuleContext *context,
+						 EFilterPart *part);
+EFilterPart *	e_rule_context_find_part	(ERuleContext *context,
+						 const gchar *name);
+EFilterPart *	e_rule_context_create_part	(ERuleContext *context,
+						 const gchar *name);
+EFilterPart *	e_rule_context_next_part	(ERuleContext *context,
+						 EFilterPart *last);
+
+EFilterRule *	e_rule_context_next_rule	(ERuleContext *context,
+						 EFilterRule *last,
+						 const gchar *source);
+EFilterRule *	e_rule_context_find_rule	(ERuleContext *context,
+						 const gchar *name,
+						 const gchar *source);
+EFilterRule *	e_rule_context_find_rank_rule	(ERuleContext *context,
+						 gint rank,
+						 const gchar *source);
+void		e_rule_context_add_rule		(ERuleContext *context,
+						 EFilterRule *rule);
+void		e_rule_context_add_rule_gui	(ERuleContext *context,
+						 EFilterRule *rule,
+						 const gchar *title,
+						 const gchar *path);
+void		e_rule_context_remove_rule	(ERuleContext *context,
+						 EFilterRule *rule);
+
+void		e_rule_context_rank_rule	(ERuleContext *context,
+						 EFilterRule *rule,
+						 const gchar *source,
+						 gint rank);
+gint		e_rule_context_get_rank_rule	(ERuleContext *context,
+						 EFilterRule *rule,
+						 const gchar *source);
+
+void		e_rule_context_add_part_set	(ERuleContext *context,
+						 const gchar *setname,
+						 GType part_type,
+						 ERuleContextPartFunc append,
+						 ERuleContextNextPartFunc next);
+void		e_rule_context_add_rule_set	(ERuleContext *context,
+						 const gchar *setname,
+						 GType rule_type,
+						 ERuleContextRuleFunc append,
+						 ERuleContextNextRuleFunc next);
+
+EFilterElement *e_rule_context_new_element	(ERuleContext *context,
+						 const gchar *name);
+
+GList *		e_rule_context_delete_uri	(ERuleContext *context,
+						 const gchar *uri,
+						 GCompareFunc compare);
+GList *		e_rule_context_rename_uri	(ERuleContext *context,
+						 const gchar *old_uri,
+						 const gchar *new_uri,
+						 GCompareFunc compare);
+
+void		e_rule_context_free_uri_list	(ERuleContext *context,
+						 GList *uris);
+
+G_END_DECLS
+
+#endif /* E_RULE_CONTEXT_H */
diff --git a/filter/e-rule-editor.c b/filter/e-rule-editor.c
new file mode 100644
index 0000000..59b0d5d
--- /dev/null
+++ b/filter/e-rule-editor.c
@@ -0,0 +1,912 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* for getenv only, remove when getenv need removed */
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib/gi18n.h>
+
+#include "e-util/e-error.h"
+#include "e-util/e-util-private.h"
+
+#include "e-rule-editor.h"
+
+#define E_RULE_EDITOR_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_RULE_EDITOR, ERuleEditorPrivate))
+
+static gint enable_undo = 0;
+
+enum {
+	BUTTON_ADD,
+	BUTTON_EDIT,
+	BUTTON_DELETE,
+	BUTTON_TOP,
+	BUTTON_UP,
+	BUTTON_DOWN,
+	BUTTON_BOTTOM,
+	BUTTON_LAST
+};
+
+struct _ERuleEditorPrivate {
+	GtkButton *buttons[BUTTON_LAST];
+};
+
+static gpointer parent_class;
+
+static void
+rule_editor_add_undo (ERuleEditor *editor,
+                      gint type,
+                      EFilterRule *rule,
+                      gint rank,
+                      gint newrank)
+{
+        ERuleEditorUndo *undo;
+
+        if (!editor->undo_active && enable_undo) {
+                undo = g_malloc0 (sizeof (*undo));
+                undo->rule = rule;
+                undo->type = type;
+                undo->rank = rank;
+                undo->newrank = newrank;
+
+                undo->next = editor->undo_log;
+                editor->undo_log = undo;
+        } else {
+                g_object_unref (rule);
+        }
+}
+
+static void
+rule_editor_play_undo (ERuleEditor *editor)
+{
+	ERuleEditorUndo *undo, *next;
+	EFilterRule *rule;
+
+	editor->undo_active = TRUE;
+	undo = editor->undo_log;
+	editor->undo_log = NULL;
+	while (undo) {
+		next = undo->next;
+		switch (undo->type) {
+		case E_RULE_EDITOR_LOG_EDIT:
+			rule = e_rule_context_find_rank_rule (editor->context, undo->rank, undo->rule->source);
+			if (rule) {
+				e_filter_rule_copy (rule, undo->rule);
+			} else {
+				g_warning ("Could not find the right rule to undo against?");
+			}
+			break;
+		case E_RULE_EDITOR_LOG_ADD:
+			rule = e_rule_context_find_rank_rule (editor->context, undo->rank, undo->rule->source);
+			if (rule)
+				e_rule_context_remove_rule (editor->context, rule);
+			break;
+		case E_RULE_EDITOR_LOG_REMOVE:
+			g_object_ref (undo->rule);
+			e_rule_context_add_rule (editor->context, undo->rule);
+			e_rule_context_rank_rule (editor->context, undo->rule, editor->source, undo->rank);
+			break;
+		case E_RULE_EDITOR_LOG_RANK:
+			rule = e_rule_context_find_rank_rule (editor->context, undo->newrank, undo->rule->source);
+			if (rule)
+				e_rule_context_rank_rule (editor->context, rule, editor->source, undo->rank);
+			break;
+		}
+
+		g_object_unref (undo->rule);
+		g_free (undo);
+		undo = next;
+	}
+	editor->undo_active = FALSE;
+}
+
+static void
+dialog_rule_changed (EFilterRule *fr, GtkWidget *dialog)
+{
+	g_return_if_fail (dialog != NULL);
+
+	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, fr && fr->parts);
+}
+
+static void
+add_editor_response (GtkWidget *dialog, gint button, ERuleEditor *editor)
+{
+	GtkTreeSelection *selection;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+
+	if (button == GTK_RESPONSE_OK) {
+		if (!e_filter_rule_validate (editor->edit, GTK_WINDOW (dialog))) {
+			/* no need to popup a dialog because the validate code does that. */
+			return;
+		}
+
+		if (e_rule_context_find_rule (editor->context, editor->edit->name, editor->edit->source)) {
+			e_error_run ((GtkWindow *)dialog, "filter:bad-name-notunique", editor->edit->name, NULL);
+			return;
+		}
+
+		g_object_ref (editor->edit);
+
+		gtk_list_store_append (editor->model, &iter);
+		gtk_list_store_set (editor->model, &iter, 0, editor->edit->name, 1, editor->edit, 2, editor->edit->enabled, -1);
+		selection = gtk_tree_view_get_selection (editor->list);
+		gtk_tree_selection_select_iter (selection, &iter);
+
+		/* scroll to the newly added row */
+		path = gtk_tree_model_get_path ((GtkTreeModel *) editor->model, &iter);
+		gtk_tree_view_scroll_to_cell (editor->list, path, NULL, TRUE, 1.0, 0.0);
+		gtk_tree_path_free (path);
+
+		editor->current = editor->edit;
+		e_rule_context_add_rule (editor->context, editor->current);
+
+		g_object_ref (editor->current);
+		rule_editor_add_undo (editor, E_RULE_EDITOR_LOG_ADD, editor->current,
+				      e_rule_context_get_rank_rule (editor->context, editor->current, editor->current->source), 0);
+	}
+
+	gtk_widget_destroy (dialog);
+}
+
+static void
+editor_destroy (ERuleEditor *editor,
+                GObject *deadbeef)
+{
+	if (editor->edit) {
+		g_object_unref (editor->edit);
+		editor->edit = NULL;
+	}
+
+	editor->dialog = NULL;
+
+	gtk_widget_set_sensitive (GTK_WIDGET (editor), TRUE);
+	e_rule_editor_set_sensitive (editor);
+}
+
+static gboolean
+update_selected_rule (ERuleEditor *editor)
+{
+	GtkTreeSelection *selection;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+
+	selection = gtk_tree_view_get_selection (editor->list);
+	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+		gtk_tree_model_get (GTK_TREE_MODEL (editor->model), &iter, 1, &editor->current, -1);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void
+cursor_changed (GtkTreeView *treeview, ERuleEditor *editor)
+{
+	if (update_selected_rule(editor)) {
+		g_return_if_fail (editor->current);
+
+		e_rule_editor_set_sensitive (editor);
+	}
+}
+
+static void
+editor_response (GtkWidget *dialog, gint button, ERuleEditor *editor)
+{
+	if (button == GTK_RESPONSE_CANCEL) {
+		if (enable_undo)
+			rule_editor_play_undo (editor);
+		else {
+			ERuleEditorUndo *undo, *next;
+
+			undo = editor->undo_log;
+			editor->undo_log = NULL;
+			while (undo) {
+				next = undo->next;
+				g_object_unref (undo->rule);
+				g_free (undo);
+				undo = next;
+			}
+		}
+	}
+}
+
+static void
+rule_add (GtkWidget *widget, ERuleEditor *editor)
+{
+	GtkWidget *rules;
+	GtkWidget *content_area;
+
+	if (editor->edit != NULL)
+		return;
+
+	editor->edit = e_rule_editor_create_rule (editor);
+	e_filter_rule_set_source (editor->edit, editor->source);
+	rules = e_filter_rule_get_widget (editor->edit, editor->context);
+
+	editor->dialog = gtk_dialog_new ();
+	gtk_dialog_add_buttons ((GtkDialog *) editor->dialog,
+				GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+				GTK_STOCK_OK, GTK_RESPONSE_OK,
+				NULL);
+	gtk_dialog_set_has_separator ((GtkDialog *) editor->dialog, FALSE);
+
+	gtk_window_set_title ((GtkWindow *) editor->dialog, _("Add Rule"));
+	gtk_window_set_default_size (GTK_WINDOW (editor->dialog), 650, 400);
+	gtk_window_set_resizable (GTK_WINDOW (editor->dialog), TRUE);
+	gtk_window_set_transient_for ((GtkWindow *) editor->dialog, (GtkWindow *) editor);
+	gtk_container_set_border_width ((GtkContainer *) editor->dialog, 6);
+
+	content_area = gtk_dialog_get_content_area (GTK_DIALOG (editor->dialog));
+	gtk_box_pack_start (GTK_BOX (content_area), rules, TRUE, TRUE, 3);
+
+	g_signal_connect (editor->dialog, "response", G_CALLBACK (add_editor_response), editor);
+	g_object_weak_ref ((GObject *) editor->dialog, (GWeakNotify) editor_destroy, editor);
+
+	g_signal_connect (editor->edit, "changed", G_CALLBACK (dialog_rule_changed), editor->dialog);
+	dialog_rule_changed (editor->edit, editor->dialog);
+
+	gtk_widget_set_sensitive (GTK_WIDGET (editor), FALSE);
+
+	gtk_widget_show (editor->dialog);
+}
+
+static void
+edit_editor_response (GtkWidget *dialog, gint button, ERuleEditor *editor)
+{
+	EFilterRule *rule;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	gint pos;
+
+	if (button == GTK_RESPONSE_OK) {
+		if (!e_filter_rule_validate (editor->edit, GTK_WINDOW (dialog))) {
+			/* no need to popup a dialog because the validate code does that. */
+			return;
+		}
+
+		rule = e_rule_context_find_rule (editor->context, editor->edit->name, editor->edit->source);
+		if (rule != NULL && rule != editor->current) {
+			e_error_run ((GtkWindow *)dialog, "filter:bad-name-notunique", rule->name, NULL);
+
+			return;
+		}
+
+		pos = e_rule_context_get_rank_rule (editor->context, editor->current, editor->source);
+		if (pos != -1) {
+			path = gtk_tree_path_new ();
+			gtk_tree_path_append_index (path, pos);
+			gtk_tree_model_get_iter (GTK_TREE_MODEL (editor->model), &iter, path);
+			gtk_tree_path_free (path);
+
+			gtk_list_store_set (editor->model, &iter, 0, editor->edit->name, -1);
+
+			rule_editor_add_undo (editor, E_RULE_EDITOR_LOG_EDIT, e_filter_rule_clone (editor->current),
+					      pos, 0);
+
+			/* replace the old rule with the new rule */
+			e_filter_rule_copy (editor->current, editor->edit);
+		}
+	}
+
+	gtk_widget_destroy (dialog);
+}
+
+static void
+rule_edit (GtkWidget *widget, ERuleEditor *editor)
+{
+	GtkWidget *rules;
+	GtkWidget *content_area;
+
+	update_selected_rule(editor);
+
+	if (editor->current == NULL || editor->edit != NULL)
+		return;
+
+	editor->edit = e_filter_rule_clone (editor->current);
+
+	rules = e_filter_rule_get_widget (editor->edit, editor->context);
+
+	editor->dialog = gtk_dialog_new ();
+	gtk_dialog_add_buttons ((GtkDialog *) editor->dialog,
+				GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+				GTK_STOCK_OK, GTK_RESPONSE_OK,
+				NULL);
+	gtk_dialog_set_has_separator ((GtkDialog *) editor->dialog, FALSE);
+
+	gtk_window_set_title ((GtkWindow *) editor->dialog, _("Edit Rule"));
+	gtk_window_set_default_size (GTK_WINDOW (editor->dialog), 650, 400);
+	gtk_window_set_resizable (GTK_WINDOW (editor->dialog), TRUE);
+	gtk_widget_set_parent_window (GTK_WIDGET (editor->dialog), GTK_WIDGET (editor)->window);
+	gtk_container_set_border_width ((GtkContainer *) editor->dialog, 6);
+
+	content_area = gtk_dialog_get_content_area (GTK_DIALOG (editor->dialog));
+	gtk_box_pack_start (GTK_BOX (content_area), rules, TRUE, TRUE, 3);
+
+	g_signal_connect (editor->dialog, "response", G_CALLBACK (edit_editor_response), editor);
+	g_object_weak_ref ((GObject *) editor->dialog, (GWeakNotify) editor_destroy, editor);
+
+	g_signal_connect (editor->edit, "changed", G_CALLBACK (dialog_rule_changed), editor->dialog);
+	dialog_rule_changed (editor->edit, editor->dialog);
+
+	gtk_widget_set_sensitive (GTK_WIDGET (editor), FALSE);
+
+	gtk_widget_show (editor->dialog);
+}
+
+static void
+rule_delete (GtkWidget *widget, ERuleEditor *editor)
+{
+	GtkTreeSelection *selection;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	gint pos, len;
+
+	update_selected_rule(editor);
+
+	pos = e_rule_context_get_rank_rule (editor->context, editor->current, editor->source);
+	if (pos != -1) {
+		e_rule_context_remove_rule (editor->context, editor->current);
+
+		path = gtk_tree_path_new ();
+		gtk_tree_path_append_index (path, pos);
+		gtk_tree_model_get_iter (GTK_TREE_MODEL (editor->model), &iter, path);
+		gtk_list_store_remove (editor->model, &iter);
+		gtk_tree_path_free (path);
+
+		rule_editor_add_undo (editor, E_RULE_EDITOR_LOG_REMOVE, editor->current,
+				      e_rule_context_get_rank_rule (editor->context, editor->current, editor->current->source), 0);
+#if 0
+		g_object_unref (editor->current);
+#endif
+		editor->current = NULL;
+
+		/* now select the next rule */
+		len = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (editor->model), NULL);
+		pos = pos >= len ? len - 1 : pos;
+
+		if (pos >= 0) {
+			path = gtk_tree_path_new ();
+			gtk_tree_path_append_index (path, pos);
+			gtk_tree_model_get_iter (GTK_TREE_MODEL (editor->model), &iter, path);
+			gtk_tree_path_free (path);
+
+			/* select the new row */
+			selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (editor->list));
+			gtk_tree_selection_select_iter (selection, &iter);
+
+			/* scroll to the selected row */
+			path = gtk_tree_model_get_path ((GtkTreeModel *) editor->model, &iter);
+			gtk_tree_view_scroll_to_cell (editor->list, path, NULL, FALSE, 0.0, 0.0);
+			gtk_tree_path_free (path);
+
+			/* update our selection state */
+			cursor_changed (editor->list, editor);
+			return;
+		}
+	}
+
+	e_rule_editor_set_sensitive (editor);
+}
+
+static void
+rule_move (ERuleEditor *editor, gint from, gint to)
+{
+	GtkTreeSelection *selection;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	EFilterRule *rule;
+
+	rule_editor_add_undo (
+		editor, E_RULE_EDITOR_LOG_RANK,
+		g_object_ref (editor->current),
+		e_rule_context_get_rank_rule (editor->context,
+		editor->current, editor->source), to);
+
+	e_rule_context_rank_rule (
+		editor->context, editor->current, editor->source, to);
+
+	path = gtk_tree_path_new ();
+	gtk_tree_path_append_index (path, from);
+	gtk_tree_model_get_iter (GTK_TREE_MODEL (editor->model), &iter, path);
+	gtk_tree_path_free (path);
+
+	gtk_tree_model_get (GTK_TREE_MODEL (editor->model), &iter, 1, &rule, -1);
+	g_return_if_fail (rule != NULL);
+
+	/* remove and then re-insert the row at the new location */
+	gtk_list_store_remove (editor->model, &iter);
+	gtk_list_store_insert (editor->model, &iter, to);
+
+	/* set the data on the row */
+	gtk_list_store_set (editor->model, &iter, 0, rule->name, 1, rule, 2, rule->enabled, -1);
+
+	/* select the row */
+	selection = gtk_tree_view_get_selection (editor->list);
+	gtk_tree_selection_select_iter (selection, &iter);
+
+	/* scroll to the selected row */
+	path = gtk_tree_model_get_path ((GtkTreeModel *) editor->model, &iter);
+	gtk_tree_view_scroll_to_cell (editor->list, path, NULL, FALSE, 0.0, 0.0);
+	gtk_tree_path_free (path);
+
+	e_rule_editor_set_sensitive (editor);
+}
+
+static void
+rule_top (GtkWidget *widget, ERuleEditor *editor)
+{
+	gint pos;
+
+	update_selected_rule(editor);
+
+	pos = e_rule_context_get_rank_rule (
+		editor->context, editor->current, editor->source);
+	if (pos > 0)
+		rule_move (editor, pos, 0);
+}
+
+static void
+rule_up (GtkWidget *widget, ERuleEditor *editor)
+{
+	gint pos;
+
+	update_selected_rule(editor);
+
+	pos = e_rule_context_get_rank_rule (
+		editor->context, editor->current, editor->source);
+	if (pos > 0)
+		rule_move (editor, pos, pos - 1);
+}
+
+static void
+rule_down (GtkWidget *widget, ERuleEditor *editor)
+{
+	gint pos;
+
+	update_selected_rule(editor);
+
+	pos = e_rule_context_get_rank_rule (
+		editor->context, editor->current, editor->source);
+	if (pos >= 0)
+		rule_move (editor, pos, pos + 1);
+}
+
+static void
+rule_bottom (GtkWidget *widget, ERuleEditor *editor)
+{
+	gint pos;
+	gint index = -1, count = 0;
+	EFilterRule *rule = NULL;
+
+	update_selected_rule(editor);
+
+	pos = e_rule_context_get_rank_rule (
+		editor->context, editor->current, editor->source);
+	/* There's probably a better/faster way to get the count of the list here */
+	while ((rule = e_rule_context_next_rule (editor->context, rule, editor->source))) {
+		if (rule == editor->current)
+			index = count;
+		count++;
+	}
+	count--;
+	if (pos >= 0)
+		rule_move (editor, pos, count);
+}
+
+static struct {
+	const gchar *name;
+	GCallback func;
+} edit_buttons[] = {
+	{ "rule_add",    G_CALLBACK (rule_add)    },
+	{ "rule_edit",   G_CALLBACK (rule_edit)   },
+	{ "rule_delete", G_CALLBACK (rule_delete) },
+	{ "rule_top",    G_CALLBACK (rule_top)    },
+	{ "rule_up",     G_CALLBACK (rule_up)     },
+	{ "rule_down",   G_CALLBACK (rule_down)   },
+	{ "rule_bottom", G_CALLBACK (rule_bottom) },
+};
+
+static void
+rule_editor_finalize (GObject *object)
+{
+	ERuleEditor *editor = E_RULE_EDITOR (object);
+	ERuleEditorUndo *undo, *next;
+
+	g_object_unref (editor->context);
+
+	undo = editor->undo_log;
+	while (undo) {
+		next = undo->next;
+		g_object_unref (undo->rule);
+		g_free (undo);
+		undo = next;
+	}
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+rule_editor_destroy (GtkObject *gtk_object)
+{
+	ERuleEditor *editor = E_RULE_EDITOR (gtk_object);
+
+	if (editor->dialog != NULL) {
+		gtk_widget_destroy (GTK_WIDGET (editor->dialog));
+		editor->dialog = NULL;
+	}
+
+	/* Chain up to parent's destroy() method. */
+	GTK_OBJECT_CLASS (parent_class)->destroy (gtk_object);
+}
+
+static void
+rule_editor_set_source (ERuleEditor *editor,
+                        const gchar *source)
+{
+	EFilterRule *rule = NULL;
+	GtkTreeIter iter;
+
+	gtk_list_store_clear (editor->model);
+
+	while ((rule = e_rule_context_next_rule (editor->context, rule, source)) != NULL) {
+		gtk_list_store_append (editor->model, &iter);
+		gtk_list_store_set (
+			editor->model, &iter,
+			0, rule->name, 1, rule, 2, rule->enabled, -1);
+	}
+
+	g_free (editor->source);
+	editor->source = g_strdup (source);
+	editor->current = NULL;
+	e_rule_editor_set_sensitive (editor);
+}
+
+static void
+rule_editor_set_sensitive (ERuleEditor *editor)
+{
+	EFilterRule *rule = NULL;
+	gint index = -1, count = 0;
+
+	while ((rule = e_rule_context_next_rule (editor->context, rule, editor->source))) {
+		if (rule == editor->current)
+			index = count;
+		count++;
+	}
+
+	count--;
+
+	gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->buttons[BUTTON_EDIT]), index != -1);
+	gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->buttons[BUTTON_DELETE]), index != -1);
+	gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->buttons[BUTTON_TOP]), index > 0);
+	gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->buttons[BUTTON_UP]), index > 0);
+	gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->buttons[BUTTON_DOWN]), index >= 0 && index < count);
+	gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->buttons[BUTTON_BOTTOM]), index >= 0 && index < count);
+}
+
+static EFilterRule *
+rule_editor_create_rule (ERuleEditor *editor)
+{
+	EFilterRule *rule;
+	EFilterPart *part;
+
+	/* create a rule with 1 part in it */
+	rule = e_filter_rule_new ();
+	part = e_rule_context_next_part (editor->context, NULL);
+	e_filter_rule_add_part (rule, e_filter_part_clone (part));
+
+	return rule;
+}
+
+static void
+rule_editor_class_init (ERuleEditorClass *class)
+{
+	GObjectClass *object_class;
+	GtkObjectClass *gtk_object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (ERuleEditorPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = rule_editor_finalize;
+
+	gtk_object_class = GTK_OBJECT_CLASS (class);
+	gtk_object_class->destroy = rule_editor_destroy;
+
+	class->set_source = rule_editor_set_source;
+	class->set_sensitive = rule_editor_set_sensitive;
+	class->create_rule = rule_editor_create_rule;
+
+	/* TODO: Remove when it works (or never will) */
+	enable_undo = getenv ("EVOLUTION_RULE_UNDO") != NULL;
+}
+
+static void
+rule_editor_init (ERuleEditor *editor)
+{
+	editor->priv = E_RULE_EDITOR_GET_PRIVATE (editor);
+}
+
+GType
+e_rule_editor_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (ERuleEditorClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) rule_editor_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (ERuleEditor),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) rule_editor_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			GTK_TYPE_DIALOG, "ERuleEditor", &type_info, 0);
+	}
+
+	return type;
+}
+
+/**
+ * rule_editor_new:
+ *
+ * Create a new ERuleEditor object.
+ *
+ * Return value: A new #ERuleEditor object.
+ **/
+ERuleEditor *
+e_rule_editor_new (ERuleContext *context,
+                   const gchar *source,
+                   const gchar *label)
+{
+	ERuleEditor *editor = (ERuleEditor *) g_object_new (E_TYPE_RULE_EDITOR, NULL);
+	GladeXML *gui;
+	gchar *filter_glade = g_build_filename (EVOLUTION_GLADEDIR,
+					       "filter.glade",
+					       NULL);
+
+	gui = glade_xml_new (filter_glade, "rule_editor", NULL);
+	g_free (filter_glade);
+	e_rule_editor_construct (editor, context, gui, source, label);
+	gtk_widget_hide (glade_xml_get_widget (gui, "label17"));
+	gtk_widget_hide (glade_xml_get_widget (gui, "filter_source_combobox"));
+	g_object_unref (gui);
+
+	return editor;
+}
+
+void
+e_rule_editor_set_sensitive (ERuleEditor *editor)
+{
+	ERuleEditorClass *class;
+
+	g_return_if_fail (E_IS_RULE_EDITOR (editor));
+
+	class = E_RULE_EDITOR_GET_CLASS (editor);
+	g_return_if_fail (class->set_sensitive != NULL);
+
+	class->set_sensitive (editor);
+}
+
+void
+e_rule_editor_set_source (ERuleEditor *editor,
+                          const gchar *source)
+{
+	ERuleEditorClass *class;
+
+	g_return_if_fail (E_IS_RULE_EDITOR (editor));
+
+	class = E_RULE_EDITOR_GET_CLASS (editor);
+	g_return_if_fail (class->set_source != NULL);
+
+	class->set_source (editor, source);
+}
+
+EFilterRule *
+e_rule_editor_create_rule (ERuleEditor *editor)
+{
+	ERuleEditorClass *class;
+
+	g_return_val_if_fail (E_IS_RULE_EDITOR (editor), NULL);
+
+	class = E_RULE_EDITOR_GET_CLASS (editor);
+	g_return_val_if_fail (class->create_rule != NULL, NULL);
+
+	return class->create_rule (editor);
+}
+
+static void
+double_click (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, ERuleEditor *editor)
+{
+	GtkTreeSelection *selection;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+
+	selection = gtk_tree_view_get_selection (editor->list);
+	if (gtk_tree_selection_get_selected (selection, &model, &iter))
+		gtk_tree_model_get (GTK_TREE_MODEL (editor->model), &iter, 1, &editor->current, -1);
+
+	if (editor->current)
+		rule_edit ((GtkWidget *) treeview, editor);
+}
+
+static void
+rule_able_toggled (GtkCellRendererToggle *renderer,
+                   gchar *arg1,
+                   gpointer user_data)
+{
+	GtkWidget *table = user_data;
+	GtkTreeSelection *selection;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+
+	path = gtk_tree_path_new_from_string (arg1);
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (table));
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (table));
+
+	if (gtk_tree_model_get_iter (model, &iter, path)) {
+		EFilterRule *rule = NULL;
+
+		gtk_tree_model_get (model, &iter, 1, &rule, -1);
+
+		if (rule) {
+			rule->enabled = !rule->enabled;
+			gtk_list_store_set (GTK_LIST_STORE (model), &iter, 2, rule->enabled, -1);
+		}
+	}
+
+	gtk_tree_path_free (path);
+}
+
+GtkWidget *
+rule_editor_treeview_new (gchar *widget_name,
+                          gchar *string1,
+                          gchar *string2,
+                          gint int1,
+                          gint int2);
+
+GtkWidget *
+rule_editor_treeview_new (gchar *widget_name,
+                          gchar *string1,
+                          gchar *string2,
+                          gint int1,
+                          gint int2)
+{
+	GtkWidget *table, *scrolled;
+	GtkTreeSelection *selection;
+	GtkCellRenderer *renderer;
+	GtkListStore *model;
+	GtkTreeViewColumn *column;
+
+	scrolled = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), GTK_SHADOW_IN);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+					GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+	model = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
+	table = gtk_tree_view_new_with_model ((GtkTreeModel *) model);
+	gtk_tree_view_set_headers_visible ((GtkTreeView *) table, FALSE);
+
+	renderer = gtk_cell_renderer_toggle_new ();
+	g_object_set (G_OBJECT (renderer), "activatable", TRUE, NULL);
+	gtk_tree_view_insert_column_with_attributes ((GtkTreeView *) table, -1,
+						     _("Enabled"), renderer,
+						     "active", 2, NULL);
+	g_signal_connect (renderer, "toggled", G_CALLBACK (rule_able_toggled), table);
+
+	/* hide enable column by default */
+	column = gtk_tree_view_get_column (GTK_TREE_VIEW (table), 0);
+	gtk_tree_view_column_set_visible (column, FALSE);
+
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_tree_view_insert_column_with_attributes ((GtkTreeView *) table, -1,
+						     _("Rule name"), renderer,
+						     "text", 0, NULL);
+
+	selection = gtk_tree_view_get_selection ((GtkTreeView *) table);
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+
+	gtk_container_add (GTK_CONTAINER (scrolled), table);
+
+	g_object_set_data ((GObject *) scrolled, "table", table);
+	g_object_set_data ((GObject *) scrolled, "model", model);
+
+	gtk_widget_show (scrolled);
+	gtk_widget_show (table);
+
+	g_object_unref (model);
+
+	return scrolled;
+}
+
+void
+e_rule_editor_construct (ERuleEditor *editor,
+                         ERuleContext *context,
+                         GladeXML *gui,
+                         const gchar *source,
+                         const gchar *label)
+{
+	GtkWidget *w;
+	GtkWidget *action_area;
+	GtkWidget *content_area;
+	gint i;
+	gchar *tmp;
+
+	g_return_if_fail (E_IS_RULE_EDITOR (editor));
+	g_return_if_fail (E_IS_RULE_CONTEXT (context));
+	g_return_if_fail (GLADE_IS_XML (gui));
+
+	editor->context = g_object_ref (context);
+
+	action_area = gtk_dialog_get_action_area (GTK_DIALOG (editor));
+	content_area = gtk_dialog_get_content_area (GTK_DIALOG (editor));
+
+	gtk_window_set_resizable ((GtkWindow *) editor, TRUE);
+	gtk_window_set_default_size ((GtkWindow *) editor, 350, 400);
+	gtk_widget_realize ((GtkWidget *) editor);
+	gtk_container_set_border_width (GTK_CONTAINER (action_area), 12);
+
+	w = glade_xml_get_widget(gui, "rule_editor");
+	gtk_box_pack_start (GTK_BOX (content_area), w, TRUE, TRUE, 3);
+
+	for (i = 0; i < BUTTON_LAST; i++) {
+		editor->priv->buttons[i] = (GtkButton *) (w = glade_xml_get_widget (gui, edit_buttons[i].name));
+		g_signal_connect (w, "clicked", edit_buttons[i].func, editor);
+	}
+
+	w = glade_xml_get_widget (gui, "rule_list");
+	editor->list = (GtkTreeView *) g_object_get_data ((GObject *) w, "table");
+	editor->model = (GtkListStore *) g_object_get_data ((GObject *) w, "model");
+
+	g_signal_connect (editor->list, "cursor-changed", G_CALLBACK (cursor_changed), editor);
+	g_signal_connect (editor->list, "row-activated", G_CALLBACK (double_click), editor);
+
+	w = glade_xml_get_widget (gui, "rule_label");
+	tmp = alloca(strlen(label)+8);
+	sprintf(tmp, "<b>%s</b>", label);
+	gtk_label_set_label((GtkLabel *)w, tmp);
+	gtk_label_set_mnemonic_widget ((GtkLabel *) w, (GtkWidget *) editor->list);
+
+	g_signal_connect (editor, "response", G_CALLBACK (editor_response), editor);
+	rule_editor_set_source (editor, source);
+
+	gtk_dialog_set_has_separator ((GtkDialog *) editor, FALSE);
+	gtk_dialog_add_buttons ((GtkDialog *) editor,
+				GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+				GTK_STOCK_OK, GTK_RESPONSE_OK,
+				NULL);
+}
diff --git a/filter/e-rule-editor.h b/filter/e-rule-editor.h
new file mode 100644
index 0000000..f7f2d2d
--- /dev/null
+++ b/filter/e-rule-editor.h
@@ -0,0 +1,122 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Not Zed <notzed lostzed mmc com au>
+ *      Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_RULE_EDITOR_H
+#define E_RULE_EDITOR_H
+
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include "e-rule-context.h"
+#include "e-filter-rule.h"
+
+/* Standard GObject macros */
+#define E_TYPE_RULE_EDITOR \
+	(e_rule_editor_get_type ())
+#define E_RULE_EDITOR(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_RULE_EDITOR, ERuleEditor))
+#define E_RULE_EDITOR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_RULE_EDITOR, ERuleEditorClass))
+#define E_IS_RULE_EDITOR(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_RULE_EDITOR))
+#define E_IS_RULE_EDITOR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_RULE_EDITOR))
+#define E_RULE_EDITOR_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_RULE_EDITOR, ERuleEditorClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ERuleEditor ERuleEditor;
+typedef struct _ERuleEditorClass ERuleEditorClass;
+typedef struct _ERuleEditorPrivate ERuleEditorPrivate;
+
+typedef struct _ERuleEditorUndo ERuleEditorUndo;
+
+struct _ERuleEditor {
+	GtkDialog parent;
+
+	GtkListStore *model;
+	GtkTreeView *list;
+
+	ERuleContext *context;
+	EFilterRule *current;
+	EFilterRule *edit;	/* for editing/adding rules, so we only do 1 at a time */
+
+	GtkWidget *dialog;
+
+	gchar *source;
+
+	ERuleEditorUndo *undo_log;	/* cancel/undo log */
+	guint undo_active:1; /* we're performing undo */
+
+	ERuleEditorPrivate *priv;
+};
+
+struct _ERuleEditorClass {
+	GtkDialogClass parent_class;
+
+	void		(*set_sensitive)	(ERuleEditor *editor);
+	void		(*set_source)		(ERuleEditor *editor,
+						 const gchar *source);
+
+	EFilterRule *	(*create_rule)		(ERuleEditor *editor);
+};
+
+enum {
+	E_RULE_EDITOR_LOG_EDIT,
+	E_RULE_EDITOR_LOG_ADD,
+	E_RULE_EDITOR_LOG_REMOVE,
+	E_RULE_EDITOR_LOG_RANK
+};
+
+struct _ERuleEditorUndo {
+	ERuleEditorUndo *next;
+
+	guint type;
+	EFilterRule *rule;
+	gint rank;
+	gint newrank;
+};
+
+GType		e_rule_editor_get_type		(void);
+ERuleEditor *	e_rule_editor_new		(ERuleContext *context,
+						 const gchar *source,
+						 const gchar *label);
+void		e_rule_editor_construct		(ERuleEditor *editor,
+						 ERuleContext *context,
+						 GladeXML *gui,
+						 const gchar *source,
+						 const gchar *label);
+void		e_rule_editor_set_source	(ERuleEditor *editor,
+						 const gchar *source);
+void		e_rule_editor_set_sensitive	(ERuleEditor *editor);
+EFilterRule *	e_rule_editor_create_rule	(ERuleEditor *editor);
+
+G_END_DECLS
+
+#endif /* E_RULE_EDITOR_H */
diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c
index 26c4052..3cfc3b3 100644
--- a/mail/e-mail-reader-utils.c
+++ b/mail/e-mail-reader-utils.c
@@ -30,7 +30,7 @@
 #include <camel/camel-vee-store.h>
 
 #include "e-util/e-error.h"
-#include "filter/filter-rule.h"
+#include "filter/e-filter-rule.h"
 
 #include "mail/e-mail-browser.h"
 #include "mail/em-composer-utils.h"
@@ -509,11 +509,11 @@ e_mail_reader_create_filter_from_selected (EMailReader *reader,
 	folder_uri = message_list->folder_uri;
 
 	if (em_utils_folder_is_sent (folder, folder_uri))
-		filter_source = FILTER_SOURCE_OUTGOING;
+		filter_source = E_FILTER_SOURCE_OUTGOING;
 	else if (em_utils_folder_is_outbox (folder, folder_uri))
-		filter_source = FILTER_SOURCE_OUTGOING;
+		filter_source = E_FILTER_SOURCE_OUTGOING;
 	else
-		filter_source = FILTER_SOURCE_INCOMING;
+		filter_source = E_FILTER_SOURCE_INCOMING;
 
 	uids = message_list_get_selected (message_list);
 
diff --git a/mail/em-filter-context.c b/mail/em-filter-context.c
index 4817d89..7c17e69 100644
--- a/mail/em-filter-context.c
+++ b/mail/em-filter-context.c
@@ -29,8 +29,8 @@
 
 #include "em-filter-context.h"
 #include "em-filter-rule.h"
-#include "filter/filter-option.h"
-#include "filter/filter-int.h"
+#include "filter/e-filter-option.h"
+#include "filter/e-filter-int.h"
 #include "em-filter-source-element.h"
 
 /* For poking into filter-folder guts */
@@ -42,11 +42,11 @@ static void em_filter_context_class_init(EMFilterContextClass *klass);
 static void em_filter_context_init(EMFilterContext *fc);
 static void em_filter_context_finalise(GObject *obj);
 
-static GList *filter_rename_uri(RuleContext *rc, const gchar *olduri, const gchar *newuri, GCompareFunc cmp);
-static GList *filter_delete_uri(RuleContext *rc, const gchar *uri, GCompareFunc cmp);
-static FilterElement *filter_new_element(RuleContext *rc, const gchar *name);
+static GList *filter_rename_uri(ERuleContext *rc, const gchar *olduri, const gchar *newuri, GCompareFunc cmp);
+static GList *filter_delete_uri(ERuleContext *rc, const gchar *uri, GCompareFunc cmp);
+static EFilterElement *filter_new_element(ERuleContext *rc, const gchar *name);
 
-static RuleContextClass *parent_class = NULL;
+static ERuleContextClass *parent_class = NULL;
 
 GType
 em_filter_context_get_type(void)
@@ -66,7 +66,7 @@ em_filter_context_get_type(void)
 			(GInstanceInitFunc) em_filter_context_init,
 		};
 
-		type = g_type_register_static(RULE_TYPE_CONTEXT, "EMFilterContext", &info, 0);
+		type = g_type_register_static(E_TYPE_RULE_CONTEXT, "EMFilterContext", &info, 0);
 	}
 
 	return type;
@@ -76,9 +76,9 @@ static void
 em_filter_context_class_init(EMFilterContextClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS(klass);
-	RuleContextClass *rc_class = RULE_CONTEXT_CLASS(klass);
+	ERuleContextClass *rc_class = E_RULE_CONTEXT_CLASS(klass);
 
-	parent_class = g_type_class_ref(RULE_TYPE_CONTEXT);
+	parent_class = g_type_class_ref(E_TYPE_RULE_CONTEXT);
 
 	object_class->finalize = em_filter_context_finalise;
 
@@ -91,14 +91,14 @@ em_filter_context_class_init(EMFilterContextClass *klass)
 static void
 em_filter_context_init(EMFilterContext *fc)
 {
-	rule_context_add_part_set((RuleContext *) fc, "partset", filter_part_get_type(),
-				   rule_context_add_part, rule_context_next_part);
-	rule_context_add_part_set((RuleContext *) fc, "actionset", filter_part_get_type(),
-				  (RCPartFunc) em_filter_context_add_action,
-				  (RCNextPartFunc) em_filter_context_next_action);
-
-	rule_context_add_rule_set((RuleContext *) fc, "ruleset", em_filter_rule_get_type(),
-				  (RCRuleFunc) rule_context_add_rule, rule_context_next_rule);
+	e_rule_context_add_part_set((ERuleContext *) fc, "partset", e_filter_part_get_type(),
+				   e_rule_context_add_part, e_rule_context_next_part);
+	e_rule_context_add_part_set((ERuleContext *) fc, "actionset", e_filter_part_get_type(),
+				  (ERuleContextPartFunc) em_filter_context_add_action,
+				  (ERuleContextNextPartFunc) em_filter_context_next_action);
+
+	e_rule_context_add_rule_set((ERuleContext *) fc, "ruleset", em_filter_rule_get_type(),
+				  (ERuleContextRuleFunc) e_rule_context_add_rule, e_rule_context_next_rule);
 }
 
 static void
@@ -126,44 +126,44 @@ em_filter_context_new(void)
 }
 
 void
-em_filter_context_add_action(EMFilterContext *fc, FilterPart *action)
+em_filter_context_add_action(EMFilterContext *fc, EFilterPart *action)
 {
 	d(printf("find action : "));
 	fc->actions = g_list_append(fc->actions, action);
 }
 
-FilterPart *
+EFilterPart *
 em_filter_context_find_action(EMFilterContext *fc, const gchar *name)
 {
 	d(printf("find action : "));
-	return filter_part_find_list(fc->actions, name);
+	return e_filter_part_find_list(fc->actions, name);
 }
 
-FilterPart *
+EFilterPart *
 em_filter_context_create_action(EMFilterContext *fc, const gchar *name)
 {
-	FilterPart *part;
+	EFilterPart *part;
 
 	if ((part = em_filter_context_find_action(fc, name)))
-		return filter_part_clone(part);
+		return e_filter_part_clone(part);
 
 	return NULL;
 }
 
-FilterPart *
-em_filter_context_next_action(EMFilterContext *fc, FilterPart *last)
+EFilterPart *
+em_filter_context_next_action(EMFilterContext *fc, EFilterPart *last)
 {
-	return filter_part_next_list(fc->actions, last);
+	return e_filter_part_next_list(fc->actions, last);
 }
 
 /* We search for any folders in our actions list that need updating, update them */
 static GList *
-filter_rename_uri(RuleContext *rc, const gchar *olduri, const gchar *newuri, GCompareFunc cmp)
+filter_rename_uri(ERuleContext *rc, const gchar *olduri, const gchar *newuri, GCompareFunc cmp)
 {
-	FilterRule *rule;
+	EFilterRule *rule;
 	GList *l, *el;
-	FilterPart *action;
-	FilterElement *element;
+	EFilterPart *action;
+	EFilterElement *element;
 	gint count = 0;
 	GList *changed = NULL;
 
@@ -172,7 +172,7 @@ filter_rename_uri(RuleContext *rc, const gchar *olduri, const gchar *newuri, GCo
 	/* For all rules, for all actions, for all elements, rename any folder elements */
 	/* Yes we could do this inside each part itself, but not today */
 	rule = NULL;
-	while ((rule = rule_context_next_rule(rc, rule, NULL))) {
+	while ((rule = e_rule_context_next_rule(rc, rule, NULL))) {
 		gint rulecount = 0;
 
 		d(printf("checking rule '%s'\n", rule->name));
@@ -206,7 +206,7 @@ filter_rename_uri(RuleContext *rc, const gchar *olduri, const gchar *newuri, GCo
 
 		if (rulecount) {
 			changed = g_list_append(changed, g_strdup(rule->name));
-			filter_rule_emit_changed(rule);
+			e_filter_rule_emit_changed(rule);
 		}
 
 		count += rulecount;
@@ -218,15 +218,15 @@ filter_rename_uri(RuleContext *rc, const gchar *olduri, const gchar *newuri, GCo
 }
 
 static GList *
-filter_delete_uri(RuleContext *rc, const gchar *uri, GCompareFunc cmp)
+filter_delete_uri(ERuleContext *rc, const gchar *uri, GCompareFunc cmp)
 {
 	/* We basically do similar to above, but when we find it,
 	   Remove the action, and if thats the last action, this might create an empty rule?  remove the rule? */
 
-	FilterRule *rule;
+	EFilterRule *rule;
 	GList *l, *el;
-	FilterPart *action;
-	FilterElement *element;
+	EFilterPart *action;
+	EFilterElement *element;
 	gint count = 0;
 	GList *deleted = NULL;
 
@@ -235,7 +235,7 @@ filter_delete_uri(RuleContext *rc, const gchar *uri, GCompareFunc cmp)
 	/* For all rules, for all actions, for all elements, check deleted folder elements */
 	/* Yes we could do this inside each part itself, but not today */
 	rule = NULL;
-	while ((rule = rule_context_next_rule(rc, rule, NULL))) {
+	while ((rule = e_rule_context_next_rule(rc, rule, NULL))) {
 		gint recorded = 0;
 
 		d(printf("checking rule '%s'\n", rule->name));
@@ -281,17 +281,17 @@ filter_delete_uri(RuleContext *rc, const gchar *uri, GCompareFunc cmp)
 	return deleted;
 }
 
-static FilterElement *
-filter_new_element(RuleContext *rc, const gchar *type)
+static EFilterElement *
+filter_new_element(ERuleContext *rc, const gchar *type)
 {
 	if (!strcmp(type, "folder")) {
-		return (FilterElement *) em_filter_folder_element_new();
+		return (EFilterElement *) em_filter_folder_element_new();
 	} else if (!strcmp(type, "system-flag")) {
-		return (FilterElement *) filter_option_new();
+		return (EFilterElement *) e_filter_option_new();
 	} else if (!strcmp(type, "score")) {
-		return (FilterElement *) filter_int_new_type("score", -3, 3);
+		return (EFilterElement *) e_filter_int_new_type("score", -3, 3);
 	} else if (!strcmp(type, "source")) {
-		return (FilterElement *) em_filter_source_element_new();
+		return (EFilterElement *) em_filter_source_element_new();
 	} else {
 		return parent_class->new_element(rc, type);
 	}
diff --git a/mail/em-filter-context.h b/mail/em-filter-context.h
index 31431b4..d5eda2a 100644
--- a/mail/em-filter-context.h
+++ b/mail/em-filter-context.h
@@ -25,7 +25,7 @@
 #ifndef _EM_FILTER_CONTEXT_H
 #define _EM_FILTER_CONTEXT_H
 
-#include "filter/rule-context.h"
+#include "filter/e-rule-context.h"
 
 #define EM_TYPE_FILTER_CONTEXT            (em_filter_context_get_type ())
 #define EM_FILTER_CONTEXT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), FILTER_TYPE_CONTEXT, EMFilterContext))
@@ -38,22 +38,22 @@ typedef struct _EMFilterContext EMFilterContext;
 typedef struct _EMFilterContextClass EMFilterContextClass;
 
 struct _EMFilterContext {
-	RuleContext parent_object;
+	ERuleContext parent_object;
 
 	GList *actions;
 };
 
 struct _EMFilterContextClass {
-	RuleContextClass parent_class;
+	ERuleContextClass parent_class;
 };
 
 GType em_filter_context_get_type (void);
 EMFilterContext *em_filter_context_new (void);
 
 /* methods */
-void em_filter_context_add_action (EMFilterContext *fc, FilterPart *action);
-FilterPart *em_filter_context_find_action (EMFilterContext *fc, const gchar *name);
-FilterPart *em_filter_context_create_action (EMFilterContext *fc, const gchar *name);
-FilterPart *em_filter_context_next_action (EMFilterContext *fc, FilterPart *last);
+void em_filter_context_add_action (EMFilterContext *fc, EFilterPart *action);
+EFilterPart *em_filter_context_find_action (EMFilterContext *fc, const gchar *name);
+EFilterPart *em_filter_context_create_action (EMFilterContext *fc, const gchar *name);
+EFilterPart *em_filter_context_next_action (EMFilterContext *fc, EFilterPart *last);
 
 #endif /* ! _EM_FILTER_CONTEXT_H */
diff --git a/mail/em-filter-editor.c b/mail/em-filter-editor.c
index f4271bf..c0e5725 100644
--- a/mail/em-filter-editor.c
+++ b/mail/em-filter-editor.c
@@ -36,20 +36,20 @@
 
 static gpointer parent_class;
 
-static FilterRule *
-filter_editor_create_rule (RuleEditor *rule_editor)
+static EFilterRule *
+filter_editor_create_rule (ERuleEditor *rule_editor)
 {
-	FilterRule *rule = filter_rule_new ();
-	FilterPart *part;
+	EFilterRule *rule = e_filter_rule_new ();
+	EFilterPart *part;
 
 	/* create a rule with 1 part & 1 action in it */
-	rule = (FilterRule *)em_filter_rule_new ();
-	part = rule_context_next_part (rule_editor->context, NULL);
-	filter_rule_add_part (rule, filter_part_clone (part));
+	rule = (EFilterRule *)em_filter_rule_new ();
+	part = e_rule_context_next_part (rule_editor->context, NULL);
+	e_filter_rule_add_part (rule, e_filter_part_clone (part));
 	part = em_filter_context_next_action (
 		(EMFilterContext *)rule_editor->context, NULL);
 	em_filter_rule_add_action (
-		(EMFilterRule *)rule, filter_part_clone (part));
+		(EMFilterRule *)rule, e_filter_part_clone (part));
 
 	return rule;
 }
@@ -57,11 +57,11 @@ filter_editor_create_rule (RuleEditor *rule_editor)
 static void
 filter_editor_class_init (EMFilterEditorClass *class)
 {
-	RuleEditorClass *rule_editor_class;
+	ERuleEditorClass *rule_editor_class;
 
 	parent_class = g_type_class_peek_parent (class);
 
-	rule_editor_class = RULE_EDITOR_CLASS (class);
+	rule_editor_class = E_RULE_EDITOR_CLASS (class);
 	rule_editor_class->create_rule = filter_editor_create_rule;
 }
 
@@ -98,7 +98,7 @@ em_filter_editor_get_type (void)
 		};
 
 		type = g_type_register_static (
-			RULE_TYPE_EDITOR, "EMFilterEditor", &type_info, 0);
+			E_TYPE_RULE_EDITOR, "EMFilterEditor", &type_info, 0);
 	}
 
 	return type;
@@ -158,7 +158,7 @@ select_source (GtkComboBox *combobox, EMFilterEditor *fe)
 	source = (gchar *) (g_slist_nth (sources, idx))->data;
 	g_return_if_fail (source);
 
-	rule_editor_set_source ((RuleEditor *)fe, source);
+	e_rule_editor_set_source ((ERuleEditor *)fe, source);
 }
 
 void
@@ -185,9 +185,9 @@ em_filter_editor_construct (EMFilterEditor *fe,
 	g_object_set_data_full (G_OBJECT (combobox), "sources", sources, free_sources);
 	gtk_widget_show (combobox);
 
-	rule_editor_construct ((RuleEditor *) fe, (RuleContext *) fc, gui, source_names[0].source, _("_Filter Rules"));
+	e_rule_editor_construct ((ERuleEditor *) fe, (ERuleContext *) fc, gui, source_names[0].source, _("_Filter Rules"));
 
 	/* Show the Enabled column, we support it here */
-	column = gtk_tree_view_get_column (GTK_TREE_VIEW (RULE_EDITOR (fe)->list), 0);
+	column = gtk_tree_view_get_column (GTK_TREE_VIEW (E_RULE_EDITOR (fe)->list), 0);
 	gtk_tree_view_column_set_visible (column, TRUE);
 }
diff --git a/mail/em-filter-editor.h b/mail/em-filter-editor.h
index c725fd9..e70b346 100644
--- a/mail/em-filter-editor.h
+++ b/mail/em-filter-editor.h
@@ -25,7 +25,7 @@
 #ifndef EM_FILTER_EDITOR_H
 #define EM_FILTER_EDITOR_H
 
-#include "filter/rule-editor.h"
+#include "filter/e-rule-editor.h"
 #include "em-filter-context.h"
 
 /* Standard GObject macros */
@@ -60,11 +60,11 @@ struct _EMFilterSource {
 };
 
 struct _EMFilterEditor {
-	RuleEditor parent;
+	ERuleEditor parent;
 };
 
 struct _EMFilterEditorClass {
-	RuleEditorClass parent_class;
+	ERuleEditorClass parent_class;
 };
 
 GType		em_filter_editor_get_type	(void);
diff --git a/mail/em-filter-folder-element.c b/mail/em-filter-folder-element.c
index 8e07ef9..b705bbd 100644
--- a/mail/em-filter-folder-element.c
+++ b/mail/em-filter-folder-element.c
@@ -34,26 +34,27 @@
 #include "em-filter-folder-element.h"
 #include "mail/em-folder-selection-button.h"
 #include "mail/em-utils.h"
+#include "filter/e-filter-part.h"
 #include "libedataserver/e-sexp.h"
 #include "e-util/e-error.h"
 
 #define d(x)
 
-static gboolean validate(FilterElement *fe, GtkWindow *error_parent);
-static gint folder_eq(FilterElement *fe, FilterElement *cm);
-static void xml_create(FilterElement *fe, xmlNodePtr node);
-static xmlNodePtr xml_encode(FilterElement *fe);
-static gint xml_decode(FilterElement *fe, xmlNodePtr node);
-static GtkWidget *get_widget(FilterElement *fe);
-static void build_code(FilterElement *fe, GString *out, struct _FilterPart *ff);
-static void format_sexp(FilterElement *, GString *);
-static void emff_copy_value(FilterElement *de, FilterElement *se);
+static gboolean validate(EFilterElement *fe, GtkWindow *error_parent);
+static gint folder_eq(EFilterElement *fe, EFilterElement *cm);
+static void xml_create(EFilterElement *fe, xmlNodePtr node);
+static xmlNodePtr xml_encode(EFilterElement *fe);
+static gint xml_decode(EFilterElement *fe, xmlNodePtr node);
+static GtkWidget *get_widget(EFilterElement *fe);
+static void build_code(EFilterElement *fe, GString *out, EFilterPart *ff);
+static void format_sexp(EFilterElement *, GString *);
+static void emff_copy_value(EFilterElement *de, EFilterElement *se);
 
 static void em_filter_folder_element_class_init(EMFilterFolderElementClass *class);
 static void em_filter_folder_element_init(EMFilterFolderElement *ff);
 static void em_filter_folder_element_finalise(GObject *obj);
 
-static FilterElementClass *parent_class = NULL;
+static EFilterElementClass *parent_class = NULL;
 
 GType
 em_filter_folder_element_get_type(void)
@@ -73,7 +74,7 @@ em_filter_folder_element_get_type(void)
 			(GInstanceInitFunc)em_filter_folder_element_init,
 		};
 
-		type = g_type_register_static(FILTER_TYPE_ELEMENT, "EMFilterFolderElement", &info, 0);
+		type = g_type_register_static(E_TYPE_FILTER_ELEMENT, "EMFilterFolderElement", &info, 0);
 	}
 
 	return type;
@@ -83,9 +84,9 @@ static void
 em_filter_folder_element_class_init(EMFilterFolderElementClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS(klass);
-	FilterElementClass *fe_class = FILTER_ELEMENT_CLASS(klass);
+	EFilterElementClass *fe_class = E_FILTER_ELEMENT_CLASS(klass);
 
-	parent_class = g_type_class_ref(FILTER_TYPE_ELEMENT);
+	parent_class = g_type_class_ref(E_TYPE_FILTER_ELEMENT);
 
 	object_class->finalize = em_filter_folder_element_finalise;
 
@@ -138,7 +139,7 @@ em_filter_folder_element_set_value(EMFilterFolderElement *ff, const gchar *uri)
 }
 
 static gboolean
-validate(FilterElement *fe, GtkWindow *error_parent)
+validate(EFilterElement *fe, GtkWindow *error_parent)
 {
 	EMFilterFolderElement *ff = (EMFilterFolderElement *)fe;
 
@@ -152,21 +153,21 @@ validate(FilterElement *fe, GtkWindow *error_parent)
 }
 
 static gint
-folder_eq(FilterElement *fe, FilterElement *cm)
+folder_eq(EFilterElement *fe, EFilterElement *cm)
 {
-        return FILTER_ELEMENT_CLASS(parent_class)->eq(fe, cm)
+        return E_FILTER_ELEMENT_CLASS(parent_class)->eq(fe, cm)
 		&& strcmp(((EMFilterFolderElement *)fe)->uri, ((EMFilterFolderElement *)cm)->uri)== 0;
 }
 
 static void
-xml_create(FilterElement *fe, xmlNodePtr node)
+xml_create(EFilterElement *fe, xmlNodePtr node)
 {
 	/* parent implementation */
-        FILTER_ELEMENT_CLASS(parent_class)->xml_create(fe, node);
+        E_FILTER_ELEMENT_CLASS(parent_class)->xml_create(fe, node);
 }
 
 static xmlNodePtr
-xml_encode(FilterElement *fe)
+xml_encode(EFilterElement *fe)
 {
 	xmlNodePtr value, work;
 	EMFilterFolderElement *ff = (EMFilterFolderElement *)fe;
@@ -187,7 +188,7 @@ xml_encode(FilterElement *fe)
 }
 
 static gint
-xml_decode(FilterElement *fe, xmlNodePtr node)
+xml_decode(EFilterElement *fe, xmlNodePtr node)
 {
 	EMFilterFolderElement *ff = (EMFilterFolderElement *)fe;
 	xmlNodePtr n;
@@ -240,7 +241,7 @@ folder_selected(EMFolderSelectionButton *button, EMFilterFolderElement *ff)
 }
 
 static GtkWidget *
-get_widget(FilterElement *fe)
+get_widget(EFilterElement *fe)
 {
 	EMFilterFolderElement *ff = (EMFilterFolderElement *)fe;
 	GtkWidget *button;
@@ -266,13 +267,13 @@ get_widget(FilterElement *fe)
 }
 
 static void
-build_code(FilterElement *fe, GString *out, struct _FilterPart *ff)
+build_code(EFilterElement *fe, GString *out, EFilterPart *ff)
 {
 	return;
 }
 
 static void
-format_sexp(FilterElement *fe, GString *out)
+format_sexp(EFilterElement *fe, GString *out)
 {
 	EMFilterFolderElement *ff = (EMFilterFolderElement *)fe;
 
@@ -280,7 +281,7 @@ format_sexp(FilterElement *fe, GString *out)
 }
 
 static void
-emff_copy_value(FilterElement *de, FilterElement *se)
+emff_copy_value(EFilterElement *de, EFilterElement *se)
 {
 	if (EM_IS_FILTER_FOLDER_ELEMENT(se)) {
 		((EMFilterFolderElement *)de)->store_camel_uri = ((EMFilterFolderElement *)se)->store_camel_uri;
diff --git a/mail/em-filter-folder-element.h b/mail/em-filter-folder-element.h
index 149d022..02fb34b 100644
--- a/mail/em-filter-folder-element.h
+++ b/mail/em-filter-folder-element.h
@@ -25,7 +25,7 @@
 #ifndef _EM_FILTER_FOLDER_ELEMENT_H
 #define _EM_FILTER_FOLDER_ELEMENT_H
 
-#include "filter/filter-element.h"
+#include "filter/e-filter-element.h"
 
 #define EM_FILTER_FOLDER_ELEMENT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), em_filter_folder_element_get_type(), EMFilterFolderElement))
 #define EM_FILTER_FOLDER_ELEMENT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), em_filter_folder_element_get_type(), EMFilterFolderElementClass))
@@ -37,14 +37,14 @@ typedef struct _EMFilterFolderElement EMFilterFolderElement;
 typedef struct _EMFilterFolderElementClass EMFilterFolderElementClass;
 
 struct _EMFilterFolderElement {
-	FilterElement parent_object;
+	EFilterElement parent_object;
 
 	gchar *uri;
 	gboolean store_camel_uri; /* true if uri should contain camel uri, otherwise contains evolution's uri with an Account ID */
 };
 
 struct _EMFilterFolderElementClass {
-	FilterElementClass parent_class;
+	EFilterElementClass parent_class;
 };
 
 GType em_filter_folder_element_get_type (void);
diff --git a/mail/em-filter-rule.c b/mail/em-filter-rule.c
index 8e95800..d655e80 100644
--- a/mail/em-filter-rule.c
+++ b/mail/em-filter-rule.c
@@ -35,19 +35,19 @@
 
 #define d(x)
 
-static gint validate(FilterRule *fr, GtkWindow *error_parent);
-static gint filter_eq(FilterRule *fr, FilterRule *cm);
-static xmlNodePtr xml_encode(FilterRule *fr);
-static gint xml_decode(FilterRule *fr, xmlNodePtr, RuleContext *rc);
-static void rule_copy(FilterRule *dest, FilterRule *src);
-/*static void build_code(FilterRule *, GString *out);*/
-static GtkWidget *get_widget(FilterRule *fr, RuleContext *rc);
+static gint validate(EFilterRule *fr, GtkWindow *error_parent);
+static gint filter_eq(EFilterRule *fr, EFilterRule *cm);
+static xmlNodePtr xml_encode(EFilterRule *fr);
+static gint xml_decode(EFilterRule *fr, xmlNodePtr, ERuleContext *rc);
+static void rule_copy(EFilterRule *dest, EFilterRule *src);
+/*static void build_code(EFilterRule *, GString *out);*/
+static GtkWidget *get_widget(EFilterRule *fr, ERuleContext *rc);
 
 static void em_filter_rule_class_init(EMFilterRuleClass *klass);
 static void em_filter_rule_init(EMFilterRule *ff);
 static void em_filter_rule_finalise(GObject *obj);
 
-static FilterRuleClass *parent_class = NULL;
+static EFilterRuleClass *parent_class = NULL;
 
 GType
 em_filter_rule_get_type(void)
@@ -67,7 +67,7 @@ em_filter_rule_get_type(void)
 			(GInstanceInitFunc)em_filter_rule_init,
 		};
 
-		type = g_type_register_static(FILTER_TYPE_RULE, "EMFilterRule", &info, 0);
+		type = g_type_register_static(E_TYPE_FILTER_RULE, "EMFilterRule", &info, 0);
 	}
 
 	return type;
@@ -77,9 +77,9 @@ static void
 em_filter_rule_class_init(EMFilterRuleClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS(klass);
-	FilterRuleClass *fr_class =(FilterRuleClass *)klass;
+	EFilterRuleClass *fr_class =(EFilterRuleClass *)klass;
 
-	parent_class = g_type_class_ref(FILTER_TYPE_RULE);
+	parent_class = g_type_class_ref(E_TYPE_FILTER_RULE);
 
 	object_class->finalize = em_filter_rule_finalise;
 
@@ -133,23 +133,23 @@ em_filter_rule_new(void)
 }
 
 void
-em_filter_rule_add_action(EMFilterRule *fr, FilterPart *fp)
+em_filter_rule_add_action(EMFilterRule *fr, EFilterPart *fp)
 {
 	fr->actions = g_list_append(fr->actions, fp);
 
-	filter_rule_emit_changed((FilterRule *)fr);
+	e_filter_rule_emit_changed((EFilterRule *)fr);
 }
 
 void
-em_filter_rule_remove_action(EMFilterRule *fr, FilterPart *fp)
+em_filter_rule_remove_action(EMFilterRule *fr, EFilterPart *fp)
 {
 	fr->actions = g_list_remove(fr->actions, fp);
 
-	filter_rule_emit_changed((FilterRule *)fr);
+	e_filter_rule_emit_changed((EFilterRule *)fr);
 }
 
 void
-em_filter_rule_replace_action(EMFilterRule *fr, FilterPart *fp, FilterPart *new)
+em_filter_rule_replace_action(EMFilterRule *fr, EFilterPart *fp, EFilterPart *new)
 {
 	GList *l;
 
@@ -160,30 +160,30 @@ em_filter_rule_replace_action(EMFilterRule *fr, FilterPart *fp, FilterPart *new)
 		fr->actions = g_list_append(fr->actions, new);
 	}
 
-	filter_rule_emit_changed((FilterRule *)fr);
+	e_filter_rule_emit_changed((EFilterRule *)fr);
 }
 
 void
 em_filter_rule_build_action(EMFilterRule *fr, GString *out)
 {
 	g_string_append(out, "(begin\n");
-	filter_part_build_code_list(fr->actions, out);
+	e_filter_part_build_code_list(fr->actions, out);
 	g_string_append(out, ")\n");
 }
 
 static gint
-validate(FilterRule *fr, GtkWindow *error_parent)
+validate(EFilterRule *fr, GtkWindow *error_parent)
 {
 	EMFilterRule *ff =(EMFilterRule *)fr;
 	GList *parts;
 	gint valid;
 
-        valid = FILTER_RULE_CLASS(parent_class)->validate (fr, error_parent);
+        valid = E_FILTER_RULE_CLASS(parent_class)->validate (fr, error_parent);
 
 	/* validate rule actions */
 	parts = ff->actions;
 	while (parts && valid) {
-		valid = filter_part_validate ((FilterPart *)parts->data, error_parent);
+		valid = e_filter_part_validate ((EFilterPart *)parts->data, error_parent);
 		parts = parts->next;
 	}
 
@@ -196,9 +196,9 @@ list_eq(GList *al, GList *bl)
 	gint truth = TRUE;
 
 	while (truth && al && bl) {
-		FilterPart *a = al->data, *b = bl->data;
+		EFilterPart *a = al->data, *b = bl->data;
 
-		truth = filter_part_eq(a, b);
+		truth = e_filter_part_eq(a, b);
 		al = al->next;
 		bl = bl->next;
 	}
@@ -207,26 +207,26 @@ list_eq(GList *al, GList *bl)
 }
 
 static gint
-filter_eq(FilterRule *fr, FilterRule *cm)
+filter_eq(EFilterRule *fr, EFilterRule *cm)
 {
-        return FILTER_RULE_CLASS(parent_class)->eq(fr, cm)
+        return E_FILTER_RULE_CLASS(parent_class)->eq(fr, cm)
 		&& list_eq(((EMFilterRule *)fr)->actions,((EMFilterRule *)cm)->actions);
 }
 
 static xmlNodePtr
-xml_encode(FilterRule *fr)
+xml_encode(EFilterRule *fr)
 {
 	EMFilterRule *ff =(EMFilterRule *)fr;
 	xmlNodePtr node, set, work;
 	GList *l;
 
-        node = FILTER_RULE_CLASS(parent_class)->xml_encode(fr);
+        node = E_FILTER_RULE_CLASS(parent_class)->xml_encode(fr);
 	g_return_val_if_fail (node != NULL, NULL);
 	set = xmlNewNode(NULL, (const guchar *)"actionset");
 	xmlAddChild(node, set);
 	l = ff->actions;
 	while (l) {
-		work = filter_part_xml_encode((FilterPart *)l->data);
+		work = e_filter_part_xml_encode((EFilterPart *)l->data);
 		xmlAddChild(set, work);
 		l = l->next;
 	}
@@ -236,11 +236,11 @@ xml_encode(FilterRule *fr)
 }
 
 static void
-load_set(xmlNodePtr node, EMFilterRule *ff, RuleContext *rc)
+load_set(xmlNodePtr node, EMFilterRule *ff, ERuleContext *rc)
 {
 	xmlNodePtr work;
 	gchar *rulename;
-	FilterPart *part;
+	EFilterPart *part;
 
 	work = node->children;
 	while (work) {
@@ -248,8 +248,8 @@ load_set(xmlNodePtr node, EMFilterRule *ff, RuleContext *rc)
 			rulename = (gchar *)xmlGetProp(work, (const guchar *)"name");
 			part = em_filter_context_find_action((EMFilterContext *)rc, rulename);
 			if (part) {
-				part = filter_part_clone(part);
-				filter_part_xml_decode(part, work);
+				part = e_filter_part_clone(part);
+				e_filter_part_xml_decode(part, work);
 				em_filter_rule_add_action(ff, part);
 			} else {
 				g_warning("cannot find rule part '%s'\n", rulename);
@@ -263,13 +263,13 @@ load_set(xmlNodePtr node, EMFilterRule *ff, RuleContext *rc)
 }
 
 static gint
-xml_decode(FilterRule *fr, xmlNodePtr node, RuleContext *rc)
+xml_decode(EFilterRule *fr, xmlNodePtr node, ERuleContext *rc)
 {
 	EMFilterRule *ff =(EMFilterRule *)fr;
 	xmlNodePtr work;
 	gint result;
 
-        result = FILTER_RULE_CLASS(parent_class)->xml_decode(fr, node, rc);
+        result = E_FILTER_RULE_CLASS(parent_class)->xml_decode(fr, node, rc);
 	if (result != 0)
 		return result;
 
@@ -285,7 +285,7 @@ xml_decode(FilterRule *fr, xmlNodePtr node, RuleContext *rc)
 }
 
 static void
-rule_copy(FilterRule *dest, FilterRule *src)
+rule_copy(EFilterRule *dest, EFilterRule *src)
 {
 	EMFilterRule *fdest, *fsrc;
 	GList *node;
@@ -301,33 +301,33 @@ rule_copy(FilterRule *dest, FilterRule *src)
 
 	node = fsrc->actions;
 	while (node) {
-		FilterPart *part = node->data;
+		EFilterPart *part = node->data;
 
 		g_object_ref(part);
 		fdest->actions = g_list_append(fdest->actions, part);
 		node = node->next;
 	}
 
-	FILTER_RULE_CLASS(parent_class)->copy(dest, src);
+	E_FILTER_RULE_CLASS(parent_class)->copy(dest, src);
 }
 
-/*static void build_code(FilterRule *fr, GString *out)
+/*static void build_code(EFilterRule *fr, GString *out)
 {
         return FILTER_RULE_CLASS(parent_class)->build_code(fr, out);
 }*/
 
 struct _part_data {
-	FilterRule *fr;
+	EFilterRule *fr;
 	EMFilterContext *f;
-	FilterPart *part;
+	EFilterPart *part;
 	GtkWidget *partwidget, *container;
 };
 
 static void
 part_combobox_changed (GtkComboBox *combobox, struct _part_data *data)
 {
-	FilterPart *part = NULL;
-	FilterPart *newpart;
+	EFilterPart *part = NULL;
+	EFilterPart *newpart;
 	gint index, i;
 
 	index = gtk_combo_box_get_active (combobox);
@@ -347,20 +347,20 @@ part_combobox_changed (GtkComboBox *combobox, struct _part_data *data)
 	if (data->partwidget)
 		gtk_container_remove (GTK_CONTAINER (data->container), data->partwidget);
 
-	newpart = filter_part_clone (part);
-	filter_part_copy_values (newpart, data->part);
+	newpart = e_filter_part_clone (part);
+	e_filter_part_copy_values (newpart, data->part);
 	em_filter_rule_replace_action ((EMFilterRule *)data->fr, data->part, newpart);
 	g_object_unref (data->part);
 	data->part = newpart;
-	data->partwidget = filter_part_get_widget (newpart);
+	data->partwidget = e_filter_part_get_widget (newpart);
 	if (data->partwidget)
 		gtk_box_pack_start (GTK_BOX (data->container), data->partwidget, TRUE, TRUE, 0);
 }
 
 static GtkWidget *
-get_rule_part_widget(EMFilterContext *f, FilterPart *newpart, FilterRule *fr)
+get_rule_part_widget(EMFilterContext *f, EFilterPart *newpart, EFilterRule *fr)
 {
-	FilterPart *part = NULL;
+	EFilterPart *part = NULL;
 	GtkWidget *combobox;
 	GtkWidget *hbox;
 	GtkWidget *p;
@@ -373,7 +373,7 @@ get_rule_part_widget(EMFilterContext *f, FilterPart *newpart, FilterRule *fr)
 	data->part = newpart;
 
 	hbox = gtk_hbox_new(FALSE, 0);
-	p = filter_part_get_widget(newpart);
+	p = e_filter_part_get_widget(newpart);
 
 	data->partwidget = p;
 	data->container = hbox;
@@ -402,7 +402,7 @@ get_rule_part_widget(EMFilterContext *f, FilterPart *newpart, FilterRule *fr)
 }
 
 struct _rule_data {
-	FilterRule *fr;
+	EFilterRule *fr;
 	EMFilterContext *f;
 	GtkWidget *parts;
 };
@@ -410,7 +410,7 @@ struct _rule_data {
 static void
 less_parts(GtkWidget *button, struct _rule_data *data)
 {
-	FilterPart *part;
+	EFilterPart *part;
 	GtkWidget *rule;
 	GList *l;
 
@@ -431,7 +431,7 @@ less_parts(GtkWidget *button, struct _rule_data *data)
 }
 
 static void
-attach_rule(GtkWidget *rule, struct _rule_data *data, FilterPart *part, gint row)
+attach_rule(GtkWidget *rule, struct _rule_data *data, EFilterPart *part, gint row)
 {
 	GtkWidget *remove;
 
@@ -465,7 +465,7 @@ do_grab_focus_cb (GtkWidget *widget, gpointer data)
 static void
 more_parts(GtkWidget *button, struct _rule_data *data)
 {
-	FilterPart *new;
+	EFilterPart *new;
 
 	/* create a new rule entry, use the first type of rule */
 	new = em_filter_context_next_action((EMFilterContext *)data->f, NULL);
@@ -473,7 +473,7 @@ more_parts(GtkWidget *button, struct _rule_data *data)
 		GtkWidget *w;
 		guint16 rows;
 
-		new = filter_part_clone(new);
+		new = e_filter_part_clone(new);
 		em_filter_rule_add_action((EMFilterRule *)data->fr, new);
 		w = get_rule_part_widget(data->f, new, data->fr);
 
@@ -502,20 +502,20 @@ more_parts(GtkWidget *button, struct _rule_data *data)
 }
 
 static GtkWidget *
-get_widget(FilterRule *fr, RuleContext *rc)
+get_widget(EFilterRule *fr, ERuleContext *rc)
 {
 	GtkWidget *widget, *hbox, *add, *label;
 	GtkWidget *parts, *inframe, *w;
 	GtkWidget *scrolledwindow;
 	GtkObject *hadj, *vadj;
 	GList *l;
-	FilterPart *part;
+	EFilterPart *part;
 	struct _rule_data *data;
 	EMFilterRule *ff =(EMFilterRule *)fr;
 	gint rows, i = 0;
 	gchar *msg;
 
-        widget = FILTER_RULE_CLASS(parent_class)->get_widget(fr, rc);
+        widget = E_FILTER_RULE_CLASS(parent_class)->get_widget(fr, rc);
 
 	/* and now for the action area */
 	msg = g_strdup_printf("<b>%s</b>", _("Then"));
diff --git a/mail/em-filter-rule.h b/mail/em-filter-rule.h
index 6ddaddc..4ea4978 100644
--- a/mail/em-filter-rule.h
+++ b/mail/em-filter-rule.h
@@ -25,7 +25,7 @@
 #ifndef _EM_FILTER_RULE_H
 #define _EM_FILTER_RULE_H
 
-#include "filter/filter-rule.h"
+#include "filter/e-filter-rule.h"
 
 #define EM_FILTER_RULE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), em_filter_rule_get_type(), EMFilterRule))
 #define EM_FILTER_RULE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), em_filter_rule_get_type(), EMFilterRuleClass))
@@ -37,22 +37,22 @@ typedef struct _EMFilterRule EMFilterRule;
 typedef struct _EMFilterRuleClass EMFilterRuleClass;
 
 struct _EMFilterRule {
-	FilterRule parent_object;
+	EFilterRule parent_object;
 
 	GList *actions;
 };
 
 struct _EMFilterRuleClass {
-	FilterRuleClass parent_class;
+	EFilterRuleClass parent_class;
 };
 
 GType           em_filter_rule_get_type (void);
 EMFilterRule   *em_filter_rule_new      (void);
 
 /* methods */
-void            em_filter_rule_add_action     (EMFilterRule *fr, FilterPart *fp);
-void            em_filter_rule_remove_action  (EMFilterRule *fr, FilterPart *fp);
-void            em_filter_rule_replace_action (EMFilterRule *fr, FilterPart *fp, FilterPart *new);
+void            em_filter_rule_add_action     (EMFilterRule *fr, EFilterPart *fp);
+void            em_filter_rule_remove_action  (EMFilterRule *fr, EFilterPart *fp);
+void            em_filter_rule_replace_action (EMFilterRule *fr, EFilterPart *fp, EFilterPart *new);
 
 void            em_filter_rule_build_action   (EMFilterRule *fr, GString *out);
 
diff --git a/mail/em-filter-source-element.c b/mail/em-filter-source-element.c
index 40af002..d080076 100644
--- a/mail/em-filter-source-element.c
+++ b/mail/em-filter-source-element.c
@@ -34,18 +34,20 @@
 #include <libedataserver/e-account-list.h>
 #include <camel/camel-url.h>
 
+#include "filter/e-filter-part.h"
+
 static void em_filter_source_element_class_init(EMFilterSourceElementClass *klass);
 static void em_filter_source_element_init(EMFilterSourceElement *fs);
 static void em_filter_source_element_finalize(GObject *obj);
 
-static gint source_eq(FilterElement *fe, FilterElement *cm);
-static void xml_create(FilterElement *fe, xmlNodePtr node);
-static xmlNodePtr xml_encode(FilterElement *fe);
-static gint xml_decode(FilterElement *fe, xmlNodePtr node);
-static FilterElement *clone(FilterElement *fe);
-static GtkWidget *get_widget(FilterElement *fe);
-static void build_code(FilterElement *fe, GString *out, struct _FilterPart *ff);
-static void format_sexp(FilterElement *, GString *);
+static gint source_eq(EFilterElement *fe, EFilterElement *cm);
+static void xml_create(EFilterElement *fe, xmlNodePtr node);
+static xmlNodePtr xml_encode(EFilterElement *fe);
+static gint xml_decode(EFilterElement *fe, xmlNodePtr node);
+static EFilterElement *clone(EFilterElement *fe);
+static GtkWidget *get_widget(EFilterElement *fe);
+static void build_code(EFilterElement *fe, GString *out, EFilterPart *ff);
+static void format_sexp(EFilterElement *, GString *);
 
 static void em_filter_source_element_add_source (EMFilterSourceElement *fs, const gchar *account_name, const gchar *name,
 				       const gchar *addr, const gchar *url);
@@ -63,7 +65,7 @@ struct _EMFilterSourceElementPrivate {
 	gchar *current_url;
 };
 
-static FilterElementClass *parent_class = NULL;
+static EFilterElementClass *parent_class = NULL;
 
 GType
 em_filter_source_element_get_type(void)
@@ -83,7 +85,7 @@ em_filter_source_element_get_type(void)
 			(GInstanceInitFunc)em_filter_source_element_init,
 		};
 
-		type = g_type_register_static(FILTER_TYPE_ELEMENT, "EMFilterSourceElement", &info, 0);
+		type = g_type_register_static(E_TYPE_FILTER_ELEMENT, "EMFilterSourceElement", &info, 0);
 	}
 
 	return type;
@@ -93,9 +95,9 @@ static void
 em_filter_source_element_class_init(EMFilterSourceElementClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS(klass);
-	FilterElementClass *fe_class = FILTER_ELEMENT_CLASS(klass);
+	EFilterElementClass *fe_class = E_FILTER_ELEMENT_CLASS(klass);
 
-	parent_class = g_type_class_ref(FILTER_TYPE_ELEMENT);
+	parent_class = g_type_class_ref(E_TYPE_FILTER_ELEMENT);
 
 	object_class->finalize = em_filter_source_element_finalize;
 
@@ -149,25 +151,25 @@ em_filter_source_element_new(void)
 }
 
 static gint
-source_eq(FilterElement *fe, FilterElement *cm)
+source_eq(EFilterElement *fe, EFilterElement *cm)
 {
 	EMFilterSourceElement *fs = (EMFilterSourceElement *)fe, *cs = (EMFilterSourceElement *)cm;
 
-	return FILTER_ELEMENT_CLASS(parent_class)->eq(fe, cm)
+	return E_FILTER_ELEMENT_CLASS(parent_class)->eq(fe, cm)
 		&&((fs->priv->current_url && cs->priv->current_url
 		     && strcmp(fs->priv->current_url, cs->priv->current_url)== 0)
 		    ||(fs->priv->current_url == NULL && cs->priv->current_url == NULL));
 }
 
 static void
-xml_create(FilterElement *fe, xmlNodePtr node)
+xml_create(EFilterElement *fe, xmlNodePtr node)
 {
 	/* Call parent implementation */
-	FILTER_ELEMENT_CLASS(parent_class)->xml_create(fe, node);
+	E_FILTER_ELEMENT_CLASS(parent_class)->xml_create(fe, node);
 }
 
 static xmlNodePtr
-xml_encode(FilterElement *fe)
+xml_encode(EFilterElement *fe)
 {
 	xmlNodePtr value;
 
@@ -184,7 +186,7 @@ xml_encode(FilterElement *fe)
 }
 
 static gint
-xml_decode(FilterElement *fe, xmlNodePtr node)
+xml_decode(EFilterElement *fe, xmlNodePtr node)
 {
 	EMFilterSourceElement *fs = (EMFilterSourceElement *)fe;
 	CamelURL *url;
@@ -209,14 +211,14 @@ xml_decode(FilterElement *fe, xmlNodePtr node)
 	return 0;
 }
 
-static FilterElement *
-clone(FilterElement *fe)
+static EFilterElement *
+clone(EFilterElement *fe)
 {
 	EMFilterSourceElement *fs = (EMFilterSourceElement *)fe;
 	EMFilterSourceElement *cpy = em_filter_source_element_new();
 	GList *i;
 
-	((FilterElement *)cpy)->name = (gchar *)xmlStrdup((guchar *)fe->name);
+	((EFilterElement *)cpy)->name = (gchar *)xmlStrdup((guchar *)fe->name);
 
 	cpy->priv->current_url = g_strdup(fs->priv->current_url);
 
@@ -225,7 +227,7 @@ clone(FilterElement *fe)
 		em_filter_source_element_add_source(cpy, info->account_name, info->name, info->address, info->url);
 	}
 
-	return (FilterElement *)cpy;
+	return (EFilterElement *)cpy;
 }
 
 static void
@@ -245,7 +247,7 @@ source_changed(GtkComboBox *combobox, EMFilterSourceElement *fs)
 }
 
 static GtkWidget *
-get_widget(FilterElement *fe)
+get_widget(EFilterElement *fe)
 {
 	EMFilterSourceElement *fs = (EMFilterSourceElement *)fe;
 	GtkWidget *combobox;
@@ -303,13 +305,13 @@ get_widget(FilterElement *fe)
 }
 
 static void
-build_code(FilterElement *fe, GString *out, struct _FilterPart *ff)
+build_code(EFilterElement *fe, GString *out, EFilterPart *ff)
 {
 	/* We are doing nothing on purpose. */
 }
 
 static void
-format_sexp(FilterElement *fe, GString *out)
+format_sexp(EFilterElement *fe, GString *out)
 {
 	EMFilterSourceElement *fs = (EMFilterSourceElement *)fe;
 
diff --git a/mail/em-filter-source-element.h b/mail/em-filter-source-element.h
index d4d6a75..cb68552 100644
--- a/mail/em-filter-source-element.h
+++ b/mail/em-filter-source-element.h
@@ -24,7 +24,7 @@
 #ifndef _EM_FILTER_SOURCE_ELEMENT_H
 #define _EM_FILTER_SOURCE_ELEMENT_H
 
-#include "filter/filter-element.h"
+#include "filter/e-filter-element.h"
 
 #define EM_FILTER_SOURCE_ELEMENT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), em_filter_source_element_get_type(), EMFilterSourceElement))
 #define EM_FILTER_SOURCE_ELEMENT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), em_filter_source_element_get_type(), EMFilterSourceElementClass))
@@ -36,12 +36,12 @@ typedef struct _EMFilterSourceElement EMFilterSourceElement;
 typedef struct _EMFilterSourceElementClass EMFilterSourceElementClass;
 
 struct _EMFilterSourceElement {
-	FilterElement parent_object;
+	EFilterElement parent_object;
 	struct _EMFilterSourceElementPrivate *priv;
 };
 
 struct _EMFilterSourceElementClass {
-	FilterElementClass parent_class;
+	EFilterElementClass parent_class;
 };
 
 GType em_filter_source_element_get_type (void);
diff --git a/mail/em-folder-utils.c b/mail/em-folder-utils.c
index c2850da..8b1dab9 100644
--- a/mail/em-folder-utils.c
+++ b/mail/em-folder-utils.c
@@ -625,7 +625,7 @@ emfu_popup_new_folder_response (EMFolderSelector *emfs, gint response, gpointer
 		vfolder_load_storage ();
 
 		rule = em_vfolder_rule_new();
-		filter_rule_set_name((FilterRule *)rule, path);
+		e_filter_rule_set_name((EFilterRule *)rule, path);
 		vfolder_gui_add_rule(rule);
 		gtk_widget_destroy((GtkWidget *)emfs);
 	} else {
diff --git a/mail/em-search-context.c b/mail/em-search-context.c
index 7bc43a1..f4b817b 100644
--- a/mail/em-search-context.c
+++ b/mail/em-search-context.c
@@ -29,44 +29,44 @@
 #include <string.h>
 
 #include "em-search-context.h"
-#include "filter/filter-rule.h"
-#include "filter/filter-option.h"
-#include "filter/filter-int.h"
+#include "filter/e-filter-rule.h"
+#include "filter/e-filter-option.h"
+#include "filter/e-filter-int.h"
 
 static gpointer parent_class;
 
-static FilterElement *
-search_context_new_element (RuleContext *context,
+static EFilterElement *
+search_context_new_element (ERuleContext *context,
                             const gchar *type)
 {
 	if (strcmp (type, "system-flag") == 0)
-		return (FilterElement *) filter_option_new ();
+		return (EFilterElement *) e_filter_option_new ();
 
 	if (strcmp (type, "score") == 0)
-		return (FilterElement *) filter_int_new_type ("score", -3, 3);
+		return (EFilterElement *) e_filter_int_new_type ("score", -3, 3);
 
 	/* Chain up to parent's new_element() method. */
-	return RULE_CONTEXT_CLASS (parent_class)->new_element (context, type);
+	return E_RULE_CONTEXT_CLASS (parent_class)->new_element (context, type);
 }
 
 static void
 search_context_class_init (EMSearchContextClass *class)
 {
-	RuleContextClass *rule_context_class;
+	ERuleContextClass *rule_context_class;
 
 	parent_class = g_type_class_peek_parent (class);
 
-	rule_context_class = RULE_CONTEXT_CLASS (class);
+	rule_context_class = E_RULE_CONTEXT_CLASS (class);
 	rule_context_class->new_element = search_context_new_element;
 }
 
 static void
 search_context_init (EMSearchContext *vc)
 {
-	RuleContext *rule_context;
+	ERuleContext *rule_context;
 
-	rule_context = RULE_CONTEXT (vc);
-	rule_context->flags = RULE_CONTEXT_THREADING | RULE_CONTEXT_GROUPING;
+	rule_context = E_RULE_CONTEXT (vc);
+	rule_context->flags = E_RULE_CONTEXT_THREADING | E_RULE_CONTEXT_GROUPING;
 }
 
 GType
@@ -89,13 +89,13 @@ em_search_context_get_type (void)
 		};
 
 		type = g_type_register_static (
-			RULE_TYPE_CONTEXT, "EMSearchContext", &type_info, 0);
+			E_TYPE_RULE_CONTEXT, "EMSearchContext", &type_info, 0);
 	}
 
 	return type;
 }
 
-RuleContext *
+ERuleContext *
 em_search_context_new (void)
 {
 	return g_object_new (EM_SEARCH_TYPE_CONTEXT, NULL);
diff --git a/mail/em-search-context.h b/mail/em-search-context.h
index d8b8902..316a53a 100644
--- a/mail/em-search-context.h
+++ b/mail/em-search-context.h
@@ -25,7 +25,7 @@
 #ifndef EM_SEARCH_CONTEXT_H
 #define EM_SEARCH_CONTEXT_H
 
-#include <filter/rule-context.h>
+#include <filter/e-rule-context.h>
 
 /* Standard GObject macros */
 #define EM_SEARCH_TYPE_CONTEXT \
@@ -52,15 +52,15 @@ typedef struct _EMSearchContext EMSearchContext;
 typedef struct _EMSearchContextClass EMSearchContextClass;
 
 struct _EMSearchContext {
-	RuleContext parent;
+	ERuleContext parent;
 };
 
 struct _EMSearchContextClass {
-	RuleContextClass parent_class;
+	ERuleContextClass parent_class;
 };
 
 GType		em_search_context_get_type	(void);
-RuleContext *	em_search_context_new		(void);
+ERuleContext *	em_search_context_new		(void);
 
 G_END_DECLS
 
diff --git a/mail/em-utils.c b/mail/em-utils.c
index 3c6c4ff..2154c62 100644
--- a/mail/em-utils.c
+++ b/mail/em-utils.c
@@ -243,7 +243,7 @@ em_filter_editor_response (GtkWidget *dialog, gint button, gpointer user_data)
 		data_dir = em_utils_get_data_dir ();
 		fc = g_object_get_data ((GObject *) dialog, "context");
 		user = g_strdup_printf ("%s/filters.xml", data_dir);
-		rule_context_save ((RuleContext *) fc, user);
+		e_rule_context_save ((ERuleContext *) fc, user);
 		g_free (user);
 	}
 
@@ -283,12 +283,12 @@ em_utils_edit_filters (GtkWidget *parent)
 	fc = em_filter_context_new ();
 	user = g_build_filename (data_dir, "filters.xml", NULL);
 	system = g_build_filename (EVOLUTION_PRIVDATADIR, "filtertypes.xml", NULL);
-	rule_context_load ((RuleContext *) fc, system, user);
+	e_rule_context_load ((ERuleContext *) fc, system, user);
 	g_free (user);
 	g_free (system);
 
-	if (((RuleContext *) fc)->error) {
-		GtkWidget *w = e_error_new((GtkWindow *)parent, "mail:filter-load-error", ((RuleContext *)fc)->error, NULL);
+	if (((ERuleContext *) fc)->error) {
+		GtkWidget *w = e_error_new((GtkWindow *)parent, "mail:filter-load-error", ((ERuleContext *)fc)->error, NULL);
 		em_utils_show_error_silent (w);
 		return;
 	}
diff --git a/mail/em-vfolder-context.c b/mail/em-vfolder-context.c
index b111376..7897356 100644
--- a/mail/em-vfolder-context.c
+++ b/mail/em-vfolder-context.c
@@ -30,14 +30,14 @@
 
 #include "em-vfolder-context.h"
 #include "em-vfolder-rule.h"
-#include "filter/filter-option.h"
-#include "filter/filter-int.h"
+#include "filter/e-filter-option.h"
+#include "filter/e-filter-int.h"
 
 #include "em-filter-folder-element.h"
 
-static FilterElement *vfolder_new_element(RuleContext *rc, const gchar *type);
+static EFilterElement *vfolder_new_element(ERuleContext *rc, const gchar *type);
 
-static RuleContextClass *parent_class = NULL;
+static ERuleContextClass *parent_class = NULL;
 
 static void
 em_vfolder_context_finalise(GObject *obj)
@@ -48,22 +48,22 @@ em_vfolder_context_finalise(GObject *obj)
 static void
 em_vfolder_context_class_init(EMVFolderContextClass *klass)
 {
-	parent_class = g_type_class_ref(RULE_TYPE_CONTEXT);
+	parent_class = g_type_class_ref(E_TYPE_RULE_CONTEXT);
 
 	((GObjectClass *)klass)->finalize = em_vfolder_context_finalise;
-	((RuleContextClass *)klass)->new_element = vfolder_new_element;
+	((ERuleContextClass *)klass)->new_element = vfolder_new_element;
 }
 
 static void
 em_vfolder_context_init(EMVFolderContext *vc)
 {
-	rule_context_add_part_set((RuleContext *) vc, "partset", filter_part_get_type(),
-				   rule_context_add_part, rule_context_next_part);
+	e_rule_context_add_part_set((ERuleContext *) vc, "partset", E_TYPE_FILTER_PART,
+				   e_rule_context_add_part, e_rule_context_next_part);
 
-	rule_context_add_rule_set((RuleContext *) vc, "ruleset", em_vfolder_rule_get_type(),
-				   rule_context_add_rule, rule_context_next_rule);
+	e_rule_context_add_rule_set((ERuleContext *) vc, "ruleset", em_vfolder_rule_get_type(),
+				   e_rule_context_add_rule, e_rule_context_next_rule);
 
-	((RuleContext *)vc)->flags = RULE_CONTEXT_THREADING | RULE_CONTEXT_GROUPING;
+	((ERuleContext *)vc)->flags = E_RULE_CONTEXT_THREADING | E_RULE_CONTEXT_GROUPING;
 }
 
 GType
@@ -84,7 +84,7 @@ em_vfolder_context_get_type(void)
 			(GInstanceInitFunc) em_vfolder_context_init,
 		};
 
-		type = g_type_register_static(RULE_TYPE_CONTEXT, "EMVFolderContext", &info, 0);
+		type = g_type_register_static(E_TYPE_RULE_CONTEXT, "EMVFolderContext", &info, 0);
 	}
 
 	return type;
@@ -103,20 +103,20 @@ em_vfolder_context_new(void)
 	return (EMVFolderContext *)g_object_new(em_vfolder_context_get_type(), NULL, NULL);
 }
 
-static FilterElement *
-vfolder_new_element(RuleContext *rc, const gchar *type)
+static EFilterElement *
+vfolder_new_element(ERuleContext *rc, const gchar *type)
 {
 	if (!strcmp(type, "system-flag")) {
-		return (FilterElement *) filter_option_new();
+		return (EFilterElement *) e_filter_option_new();
 	} else if (!strcmp(type, "score")) {
-		return (FilterElement *) filter_int_new_type("score", -3, 3);
+		return (EFilterElement *) e_filter_int_new_type("score", -3, 3);
 	} else if (!strcmp(type, "folder-curi")) {
 		EMFilterFolderElement *ff = em_filter_folder_element_new ();
 		if (ff)
 			ff->store_camel_uri = TRUE;
-		return (FilterElement *) ff;
+		return (EFilterElement *) ff;
 	} else if (!strcmp(type, "folder")) {
-		return (FilterElement *) em_filter_folder_element_new();
+		return (EFilterElement *) em_filter_folder_element_new();
 	} else {
 		return parent_class->new_element(rc, type);
 	}
diff --git a/mail/em-vfolder-context.h b/mail/em-vfolder-context.h
index 7f17f4e..baf3f5f 100644
--- a/mail/em-vfolder-context.h
+++ b/mail/em-vfolder-context.h
@@ -25,7 +25,7 @@
 #ifndef _EM_VFOLDER_CONTEXT_H
 #define _EM_VFOLDER_CONTEXT_H
 
-#include "filter/rule-context.h"
+#include "filter/e-rule-context.h"
 
 #define EM_VFOLDER_CONTEXT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), em_vfolder_context_get_type(), EMVFolderContext))
 #define EM_VFOLDER_CONTEXT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), em_vfolder_context_get_type(), EMVFolderContextClass))
@@ -37,12 +37,12 @@ typedef struct _EMVFolderContext EMVFolderContext;
 typedef struct _EMVFolderContextClass EMVFolderContextClass;
 
 struct _EMVFolderContext {
-	RuleContext parent_object;
+	ERuleContext parent_object;
 
 };
 
 struct _EMVFolderContextClass {
-	RuleContextClass parent_class;
+	ERuleContextClass parent_class;
 };
 
 GType em_vfolder_context_get_type (void);
diff --git a/mail/em-vfolder-editor.c b/mail/em-vfolder-editor.c
index 058ad0a..073a4c5 100644
--- a/mail/em-vfolder-editor.c
+++ b/mail/em-vfolder-editor.c
@@ -38,16 +38,16 @@
 
 static gpointer parent_class;
 
-static FilterRule *
-vfolder_editor_create_rule (RuleEditor *rule_editor)
+static EFilterRule *
+vfolder_editor_create_rule (ERuleEditor *rule_editor)
 {
-	FilterRule *rule = filter_rule_new ();
-	FilterPart *part;
+	EFilterRule *rule = e_filter_rule_new ();
+	EFilterPart *part;
 
 	/* create a rule with 1 part in it */
-	rule = (FilterRule *) em_vfolder_rule_new ();
-	part = rule_context_next_part (rule_editor->context, NULL);
-	filter_rule_add_part (rule, filter_part_clone (part));
+	rule = (EFilterRule *) em_vfolder_rule_new ();
+	part = e_rule_context_next_part (rule_editor->context, NULL);
+	e_filter_rule_add_part (rule, e_filter_part_clone (part));
 
 	return rule;
 }
@@ -55,11 +55,11 @@ vfolder_editor_create_rule (RuleEditor *rule_editor)
 static void
 vfolder_editor_class_init (EMVFolderEditorClass *class)
 {
-	RuleEditorClass *rule_editor_class;
+	ERuleEditorClass *rule_editor_class;
 
 	parent_class = g_type_class_peek_parent (class);
 
-	rule_editor_class = RULE_EDITOR_CLASS (class);
+	rule_editor_class = E_RULE_EDITOR_CLASS (class);
 	rule_editor_class->create_rule = vfolder_editor_create_rule;
 }
 
@@ -96,7 +96,7 @@ em_vfolder_editor_get_type (void)
 		};
 
 		type = g_type_register_static (
-			RULE_TYPE_EDITOR, "EMVFolderEditor", &type_info, 0);
+			E_TYPE_RULE_EDITOR, "EMVFolderEditor", &type_info, 0);
 	}
 
 	return type;
@@ -123,7 +123,7 @@ em_vfolder_editor_new (EMVFolderContext *vc)
 	gui = glade_xml_new (gladefile, "rule_editor", NULL);
 	g_free (gladefile);
 
-	rule_editor_construct ((RuleEditor *) ve, (RuleContext *) vc, gui, "incoming", _("Search _Folders"));
+	e_rule_editor_construct ((ERuleEditor *) ve, (ERuleContext *) vc, gui, "incoming", _("Search _Folders"));
 	gtk_widget_hide (glade_xml_get_widget (gui, "label17"));
 	gtk_widget_hide (glade_xml_get_widget (gui, "filter_source_combobox"));
 	g_object_unref (gui);
diff --git a/mail/em-vfolder-editor.h b/mail/em-vfolder-editor.h
index 2a48c46..2548582 100644
--- a/mail/em-vfolder-editor.h
+++ b/mail/em-vfolder-editor.h
@@ -24,7 +24,7 @@
 #ifndef EM_VFOLDER_EDITOR_H
 #define EM_VFOLDER_EDITOR_H
 
-#include "filter/rule-editor.h"
+#include "filter/e-rule-editor.h"
 #include "em-vfolder-context.h"
 
 /* Standard GObject macros */
@@ -52,11 +52,11 @@ typedef struct _EMVFolderEditor EMVFolderEditor;
 typedef struct _EMVFolderEditorClass EMVFolderEditorClass;
 
 struct _EMVFolderEditor {
-	RuleEditor parent;
+	ERuleEditor parent;
 };
 
 struct _EMVFolderEditorClass {
-	RuleEditorClass parent_class;
+	ERuleEditorClass parent_class;
 };
 
 GType		em_vfolder_editor_get_type	(void);
diff --git a/mail/em-vfolder-rule.c b/mail/em-vfolder-rule.c
index 3a87c09..50016d0 100644
--- a/mail/em-vfolder-rule.c
+++ b/mail/em-vfolder-rule.c
@@ -43,13 +43,13 @@
 
 #define d(x)
 
-static gint validate(FilterRule *, GtkWindow *error_parent);
-static gint vfolder_eq(FilterRule *fr, FilterRule *cm);
-static xmlNodePtr xml_encode(FilterRule *);
-static gint xml_decode(FilterRule *, xmlNodePtr, RuleContext *f);
-static void rule_copy(FilterRule *dest, FilterRule *src);
-/*static void build_code(FilterRule *, GString *out);*/
-static GtkWidget *get_widget(FilterRule *fr, RuleContext *f);
+static gint validate(EFilterRule *, GtkWindow *error_parent);
+static gint vfolder_eq(EFilterRule *fr, EFilterRule *cm);
+static xmlNodePtr xml_encode(EFilterRule *);
+static gint xml_decode(EFilterRule *, xmlNodePtr, ERuleContext *f);
+static void rule_copy(EFilterRule *dest, EFilterRule *src);
+/*static void build_code(EFilterRule *, GString *out);*/
+static GtkWidget *get_widget(EFilterRule *fr, ERuleContext *f);
 
 static void em_vfolder_rule_class_init(EMVFolderRuleClass *klass);
 static void em_vfolder_rule_init(EMVFolderRule *vr);
@@ -63,7 +63,7 @@ static const gchar *with_names[] = {
 	"local"
 };
 
-static FilterRuleClass *parent_class = NULL;
+static EFilterRuleClass *parent_class = NULL;
 
 GType
 em_vfolder_rule_get_type(void)
@@ -83,7 +83,7 @@ em_vfolder_rule_get_type(void)
 			(GInstanceInitFunc)em_vfolder_rule_init,
 		};
 
-		type = g_type_register_static(FILTER_TYPE_RULE, "EMVFolderRule", &info, 0);
+		type = g_type_register_static(E_TYPE_FILTER_RULE, "EMVFolderRule", &info, 0);
 	}
 
 	return type;
@@ -93,9 +93,9 @@ static void
 em_vfolder_rule_class_init(EMVFolderRuleClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS(klass);
-	FilterRuleClass *fr_class =(FilterRuleClass *)klass;
+	EFilterRuleClass *fr_class =(EFilterRuleClass *)klass;
 
-	parent_class = g_type_class_ref(FILTER_TYPE_RULE);
+	parent_class = g_type_class_ref(E_TYPE_FILTER_RULE);
 
 	object_class->finalize = em_vfolder_rule_finalise;
 
@@ -148,7 +148,7 @@ em_vfolder_rule_add_source(EMVFolderRule *vr, const gchar *uri)
 
 	vr->sources = g_list_append(vr->sources, g_strdup(uri));
 
-	filter_rule_emit_changed((FilterRule *)vr);
+	e_filter_rule_emit_changed((EFilterRule *)vr);
 }
 
 const gchar *
@@ -181,7 +181,7 @@ em_vfolder_rule_remove_source(EMVFolderRule *vr, const gchar *uri)
 	if (found) {
 		vr->sources = g_list_remove(vr->sources, found);
 		g_free(found);
-		filter_rule_emit_changed((FilterRule *)vr);
+		e_filter_rule_emit_changed((EFilterRule *)vr);
 	}
 }
 
@@ -207,7 +207,7 @@ em_vfolder_rule_next_source(EMVFolderRule *vr, const gchar *last)
 }
 
 static gint
-validate(FilterRule *fr, GtkWindow *error_parent)
+validate(EFilterRule *fr, GtkWindow *error_parent)
 {
 	g_return_val_if_fail(fr != NULL, 0);
 
@@ -223,7 +223,7 @@ validate(FilterRule *fr, GtkWindow *error_parent)
 		return 0;
 	}
 
-	return FILTER_RULE_CLASS(parent_class)->validate (fr, error_parent);
+	return E_FILTER_RULE_CLASS(parent_class)->validate (fr, error_parent);
 }
 
 static gint
@@ -243,20 +243,20 @@ list_eq(GList *al, GList *bl)
 }
 
 static gint
-vfolder_eq(FilterRule *fr, FilterRule *cm)
+vfolder_eq(EFilterRule *fr, EFilterRule *cm)
 {
-        return FILTER_RULE_CLASS(parent_class)->eq(fr, cm)
+        return E_FILTER_RULE_CLASS(parent_class)->eq(fr, cm)
 		&& list_eq(((EMVFolderRule *)fr)->sources, ((EMVFolderRule *)cm)->sources);
 }
 
 static xmlNodePtr
-xml_encode(FilterRule *fr)
+xml_encode(EFilterRule *fr)
 {
 	EMVFolderRule *vr =(EMVFolderRule *)fr;
 	xmlNodePtr node, set, work;
 	GList *l;
 
-        node = FILTER_RULE_CLASS(parent_class)->xml_encode(fr);
+        node = E_FILTER_RULE_CLASS(parent_class)->xml_encode(fr);
 	g_return_val_if_fail (node != NULL, NULL);
 	g_return_val_if_fail (vr->with < G_N_ELEMENTS (with_names), NULL);
 
@@ -290,14 +290,14 @@ set_with(EMVFolderRule *vr, const gchar *name)
 }
 
 static gint
-xml_decode(FilterRule *fr, xmlNodePtr node, struct _RuleContext *f)
+xml_decode(EFilterRule *fr, xmlNodePtr node, struct _ERuleContext *f)
 {
 	xmlNodePtr set, work;
 	gint result;
 	EMVFolderRule *vr =(EMVFolderRule *)fr;
 	gchar *tmp;
 
-        result = FILTER_RULE_CLASS(parent_class)->xml_decode(fr, node, f);
+        result = E_FILTER_RULE_CLASS(parent_class)->xml_decode(fr, node, f);
 	if (result != 0)
 		return result;
 
@@ -334,7 +334,7 @@ xml_decode(FilterRule *fr, xmlNodePtr node, struct _RuleContext *f)
 }
 
 static void
-rule_copy(FilterRule *dest, FilterRule *src)
+rule_copy(EFilterRule *dest, EFilterRule *src)
 {
 	EMVFolderRule *vdest, *vsrc;
 	GList *node;
@@ -358,7 +358,7 @@ rule_copy(FilterRule *dest, FilterRule *src)
 
 	vdest->with = vsrc->with;
 
-	FILTER_RULE_CLASS(parent_class)->copy(dest, src);
+	E_FILTER_RULE_CLASS(parent_class)->copy(dest, src);
 }
 
 enum {
@@ -368,7 +368,7 @@ enum {
 };
 
 struct _source_data {
-	RuleContext *rc;
+	ERuleContext *rc;
 	EMVFolderRule *vr;
 	const gchar *current;
 	GtkListStore *model;
@@ -611,7 +611,7 @@ em_vfolder_editor_sourcelist_new(gchar *widget_name, gchar *string1, gchar *stri
 }
 
 static GtkWidget *
-get_widget(FilterRule *fr, RuleContext *rc)
+get_widget(EFilterRule *fr, ERuleContext *rc)
 {
 	EMVFolderRule *vr =(EMVFolderRule *)fr;
 	GtkWidget *widget, *frame, *list;
@@ -623,7 +623,7 @@ get_widget(FilterRule *fr, RuleContext *rc)
 	gint i;
 	gchar *gladefile;
 
-        widget = FILTER_RULE_CLASS(parent_class)->get_widget(fr, rc);
+        widget = E_FILTER_RULE_CLASS(parent_class)->get_widget(fr, rc);
 
 	data = g_malloc0(sizeof(*data));
 	data->rc = rc;
diff --git a/mail/em-vfolder-rule.h b/mail/em-vfolder-rule.h
index 1c0b2a3..a5c8035 100644
--- a/mail/em-vfolder-rule.h
+++ b/mail/em-vfolder-rule.h
@@ -24,7 +24,7 @@
 #ifndef _EM_VFOLDER_RULE_H
 #define _EM_VFOLDER_RULE_H
 
-#include "filter/filter-rule.h"
+#include "filter/e-filter-rule.h"
 
 #define EM_VFOLDER_RULE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), em_vfolder_rule_get_type(), EMVFolderRule))
 #define EM_VFOLDER_RULE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), em_vfolder_rule_get_type(), EMVFolderRuleClass))
@@ -46,14 +46,14 @@ typedef struct _EMVFolderRuleClass EMVFolderRuleClass;
 typedef enum _em_vfolder_rule_with_t em_vfolder_rule_with_t;
 
 struct _EMVFolderRule {
-	FilterRule rule;
+	EFilterRule rule;
 
 	em_vfolder_rule_with_t with;
 	GList *sources;		/* uri's of the source folders */
 };
 
 struct _EMVFolderRuleClass {
-	FilterRuleClass parent_class;
+	EFilterRuleClass parent_class;
 };
 
 GType        em_vfolder_rule_get_type (void);
diff --git a/mail/mail-autofilter.c b/mail/mail-autofilter.c
index cf6575d..d64a4ae 100644
--- a/mail/mail-autofilter.c
+++ b/mail/mail-autofilter.c
@@ -43,7 +43,7 @@
 #include "em-filter-context.h"
 #include "em-filter-rule.h"
 #include "em-filter-editor.h"
-#include "filter/filter-option.h"
+#include "filter/e-filter-option.h"
 
 #include <camel/camel-internet-address.h>
 #include <camel/camel-mime-message.h>
@@ -51,25 +51,25 @@
 #define d(x)
 
 static void
-rule_match_recipients (RuleContext *context, FilterRule *rule, CamelInternetAddress *iaddr)
+rule_match_recipients (ERuleContext *context, EFilterRule *rule, CamelInternetAddress *iaddr)
 {
-	FilterPart *part;
-	FilterElement *element;
+	EFilterPart *part;
+	EFilterElement *element;
 	gint i;
 	const gchar *real, *addr;
 	gchar *namestr;
 
 	/* address types etc should handle multiple values */
 	for (i = 0; camel_internet_address_get (iaddr, i, &real, &addr); i++) {
-		part = rule_context_create_part (context, "to");
-		filter_rule_add_part ((FilterRule *)rule, part);
-		element = filter_part_find_element (part, "recipient-type");
-		filter_option_set_current ((FilterOption *)element, "contains");
-		element = filter_part_find_element (part, "recipient");
-		filter_input_set_value ((FilterInput *)element, addr);
+		part = e_rule_context_create_part (context, "to");
+		e_filter_rule_add_part ((EFilterRule *)rule, part);
+		element = e_filter_part_find_element (part, "recipient-type");
+		e_filter_option_set_current ((EFilterOption *)element, "contains");
+		element = e_filter_part_find_element (part, "recipient");
+		e_filter_input_set_value ((EFilterInput *)element, addr);
 
 		namestr = g_strdup_printf (_("Mail to %s"), real && real[0] ? real : addr);
-		filter_rule_set_name (rule, namestr);
+		e_filter_rule_set_name (rule, namestr);
 		g_free (namestr);
 	}
 }
@@ -122,43 +122,43 @@ reg_match (gchar *str, gchar *regstr)
 #endif
 
 static void
-rule_add_subject (RuleContext *context, FilterRule *rule, const gchar *text)
+rule_add_subject (ERuleContext *context, EFilterRule *rule, const gchar *text)
 {
-	FilterPart *part;
-	FilterElement *element;
+	EFilterPart *part;
+	EFilterElement *element;
 
 	/* dont match on empty strings ever */
 	if (*text == 0)
 		return;
-	part = rule_context_create_part (context, "subject");
-	filter_rule_add_part ((FilterRule *)rule, part);
-	element = filter_part_find_element (part, "subject-type");
-	filter_option_set_current ((FilterOption *)element, "contains");
-	element = filter_part_find_element (part, "subject");
-	filter_input_set_value ((FilterInput *)element, text);
+	part = e_rule_context_create_part (context, "subject");
+	e_filter_rule_add_part ((EFilterRule *)rule, part);
+	element = e_filter_part_find_element (part, "subject-type");
+	e_filter_option_set_current ((EFilterOption *)element, "contains");
+	element = e_filter_part_find_element (part, "subject");
+	e_filter_input_set_value ((EFilterInput *)element, text);
 }
 
 static void
-rule_add_sender (RuleContext *context, FilterRule *rule, const gchar *text)
+rule_add_sender (ERuleContext *context, EFilterRule *rule, const gchar *text)
 {
-	FilterPart *part;
-	FilterElement *element;
+	EFilterPart *part;
+	EFilterElement *element;
 
 	/* dont match on empty strings ever */
 	if (*text == 0)
 		return;
-	part = rule_context_create_part (context, "sender");
-	filter_rule_add_part ((FilterRule *)rule, part);
-	element = filter_part_find_element (part, "sender-type");
-	filter_option_set_current ((FilterOption *)element, "contains");
-	element = filter_part_find_element (part, "sender");
-	filter_input_set_value ((FilterInput *)element, text);
+	part = e_rule_context_create_part (context, "sender");
+	e_filter_rule_add_part ((EFilterRule *)rule, part);
+	element = e_filter_part_find_element (part, "sender-type");
+	e_filter_option_set_current ((EFilterOption *)element, "contains");
+	element = e_filter_part_find_element (part, "sender");
+	e_filter_input_set_value ((EFilterInput *)element, text);
 }
 
 /* do a bunch of things on the subject to try and detect mailing lists, remove
    unneeded stuff, etc */
 static void
-rule_match_subject (RuleContext *context, FilterRule *rule, const gchar *subject)
+rule_match_subject (ERuleContext *context, EFilterRule *rule, const gchar *subject)
 {
 	const gchar *s;
 	const gchar *s1, *s2;
@@ -200,28 +200,28 @@ rule_match_subject (RuleContext *context, FilterRule *rule, const gchar *subject
 }
 
 static void
-rule_match_mlist(RuleContext *context, FilterRule *rule, const gchar *mlist)
+rule_match_mlist(ERuleContext *context, EFilterRule *rule, const gchar *mlist)
 {
-	FilterPart *part;
-	FilterElement *element;
+	EFilterPart *part;
+	EFilterElement *element;
 
 	if (mlist[0] == 0)
 		return;
 
-	part = rule_context_create_part(context, "mlist");
-	filter_rule_add_part(rule, part);
+	part = e_rule_context_create_part(context, "mlist");
+	e_filter_rule_add_part(rule, part);
 
-	element = filter_part_find_element(part, "mlist-type");
-	filter_option_set_current((FilterOption *)element, "is");
+	element = e_filter_part_find_element(part, "mlist-type");
+	e_filter_option_set_current((EFilterOption *)element, "is");
 
-	element = filter_part_find_element (part, "mlist");
-	filter_input_set_value((FilterInput *)element, mlist);
+	element = e_filter_part_find_element (part, "mlist");
+	e_filter_input_set_value((EFilterInput *)element, mlist);
 }
 
 static void
-rule_from_address (FilterRule *rule, RuleContext *context, CamelInternetAddress* addr, gint flags)
+rule_from_address (EFilterRule *rule, ERuleContext *context, CamelInternetAddress* addr, gint flags)
 {
-	rule->grouping = FILTER_GROUP_ANY;
+	rule->grouping = E_FILTER_GROUP_ANY;
 
 	if (flags & AUTO_FROM) {
 		const gchar *name, *address;
@@ -232,7 +232,7 @@ rule_from_address (FilterRule *rule, RuleContext *context, CamelInternetAddress*
 		if (name == NULL || name[0] == '\0')
 			name = address;
 		namestr = g_strdup_printf(_("Mail from %s"), name);
-		filter_rule_set_name (rule, namestr);
+		e_filter_rule_set_name (rule, namestr);
 		g_free (namestr);
 	}
 	if (flags & AUTO_TO) {
@@ -242,11 +242,11 @@ rule_from_address (FilterRule *rule, RuleContext *context, CamelInternetAddress*
 }
 
 static void
-rule_from_message (FilterRule *rule, RuleContext *context, CamelMimeMessage *msg, gint flags)
+rule_from_message (EFilterRule *rule, ERuleContext *context, CamelMimeMessage *msg, gint flags)
 {
 	CamelInternetAddress *addr;
 
-	rule->grouping = FILTER_GROUP_ANY;
+	rule->grouping = E_FILTER_GROUP_ANY;
 
 	if (flags & AUTO_SUBJECT) {
 		const gchar *subject = msg->subject ? msg->subject : "";
@@ -255,7 +255,7 @@ rule_from_message (FilterRule *rule, RuleContext *context, CamelMimeMessage *msg
 		rule_match_subject (context, rule, subject);
 
 		namestr = g_strdup_printf (_("Subject is %s"), strip_re (subject));
-		filter_rule_set_name (rule, namestr);
+		e_filter_rule_set_name (rule, namestr);
 		g_free (namestr);
 	}
 	/* should parse the from address into an internet address? */
@@ -271,7 +271,7 @@ rule_from_message (FilterRule *rule, RuleContext *context, CamelMimeMessage *msg
 			if (name == NULL || name[0] == '\0')
 				name = address;
 			namestr = g_strdup_printf(_("Mail from %s"), name);
-			filter_rule_set_name (rule, namestr);
+			e_filter_rule_set_name (rule, namestr);
 			g_free (namestr);
 		}
 	}
@@ -290,14 +290,14 @@ rule_from_message (FilterRule *rule, RuleContext *context, CamelMimeMessage *msg
 		if (mlist) {
 			rule_match_mlist(context, rule, mlist);
 			name = g_strdup_printf (_("%s mailing list"), mlist);
-			filter_rule_set_name(rule, name);
+			e_filter_rule_set_name(rule, name);
 			g_free(name);
 		}
 		g_free(mlist);
 	}
 }
 
-FilterRule *
+EFilterRule *
 em_vfolder_rule_from_message (EMVFolderContext *context, CamelMimeMessage *msg, gint flags, const gchar *source)
 {
 	EMVFolderRule *rule;
@@ -305,13 +305,13 @@ em_vfolder_rule_from_message (EMVFolderContext *context, CamelMimeMessage *msg,
 
 	rule = em_vfolder_rule_new ();
 	em_vfolder_rule_add_source (rule, euri);
-	rule_from_message ((FilterRule *)rule, (RuleContext *)context, msg, flags);
+	rule_from_message ((EFilterRule *)rule, (ERuleContext *)context, msg, flags);
 	g_free(euri);
 
-	return (FilterRule *)rule;
+	return (EFilterRule *)rule;
 }
 
-FilterRule *
+EFilterRule *
 em_vfolder_rule_from_address (EMVFolderContext *context, CamelInternetAddress *addr, gint flags, const gchar *source)
 {
 	EMVFolderRule *rule;
@@ -319,25 +319,25 @@ em_vfolder_rule_from_address (EMVFolderContext *context, CamelInternetAddress *a
 
 	rule = em_vfolder_rule_new ();
 	em_vfolder_rule_add_source (rule, euri);
-	rule_from_address ((FilterRule *)rule, (RuleContext *)context, addr, flags);
+	rule_from_address ((EFilterRule *)rule, (ERuleContext *)context, addr, flags);
 	g_free(euri);
 
-	return (FilterRule *)rule;
+	return (EFilterRule *)rule;
 }
 
-FilterRule *
+EFilterRule *
 filter_rule_from_message (EMFilterContext *context, CamelMimeMessage *msg, gint flags)
 {
 	EMFilterRule *rule;
-	FilterPart *part;
+	EFilterPart *part;
 
 	rule = em_filter_rule_new ();
-	rule_from_message ((FilterRule *)rule, (RuleContext *)context, msg, flags);
+	rule_from_message ((EFilterRule *)rule, (ERuleContext *)context, msg, flags);
 
 	part = em_filter_context_next_action (context, NULL);
-	em_filter_rule_add_action (rule, filter_part_clone (part));
+	em_filter_rule_add_action (rule, e_filter_part_clone (part));
 
-	return (FilterRule *)rule;
+	return (EFilterRule *)rule;
 }
 
 void
@@ -346,7 +346,7 @@ filter_gui_add_from_message (CamelMimeMessage *msg, const gchar *source, gint fl
 	EMFilterContext *fc;
 	const gchar *data_dir;
 	gchar *user, *system;
-	FilterRule *rule;
+	EFilterRule *rule;
 
 	g_return_if_fail (msg != NULL);
 
@@ -354,14 +354,14 @@ filter_gui_add_from_message (CamelMimeMessage *msg, const gchar *source, gint fl
 	data_dir = em_utils_get_data_dir ();
 	user = g_build_filename (data_dir, "filters.xml", NULL);
 	system = g_build_filename (EVOLUTION_PRIVDATADIR, "filtertypes.xml", NULL);
-	rule_context_load ((RuleContext *)fc, system, user);
+	e_rule_context_load ((ERuleContext *)fc, system, user);
 	g_free (system);
 
 	rule = filter_rule_from_message (fc, msg, flags);
 
-	filter_rule_set_source (rule, source);
+	e_filter_rule_set_source (rule, source);
 
-	rule_context_add_rule_gui ((RuleContext *)fc, rule, _("Add Filter Rule"), user);
+	e_rule_context_add_rule_gui ((ERuleContext *)fc, rule, _("Add Filter Rule"), user);
 	g_free (user);
 	g_object_unref (fc);
 }
@@ -382,15 +382,15 @@ mail_filter_rename_uri(CamelStore *store, const gchar *olduri, const gchar *newu
 	data_dir = em_utils_get_data_dir ();
 	user = g_build_filename (data_dir, "filters.xml", NULL);
 	system = g_build_filename (EVOLUTION_PRIVDATADIR, "filtertypes.xml", NULL);
-	rule_context_load ((RuleContext *)fc, system, user);
+	e_rule_context_load ((ERuleContext *)fc, system, user);
 	g_free (system);
 
-	changed = rule_context_rename_uri((RuleContext *)fc, eolduri, enewuri, g_str_equal);
+	changed = e_rule_context_rename_uri((ERuleContext *)fc, eolduri, enewuri, g_str_equal);
 	if (changed) {
 		d(printf("Folder rename '%s' -> '%s' changed filters, resaving\n", olduri, newuri));
-		if (rule_context_save((RuleContext *)fc, user) == -1)
+		if (e_rule_context_save((ERuleContext *)fc, user) == -1)
 			g_warning("Could not write out changed filter rules\n");
-		rule_context_free_uri_list((RuleContext *)fc, changed);
+		e_rule_context_free_uri_list((ERuleContext *)fc, changed);
 	}
 
 	g_free(user);
@@ -415,10 +415,10 @@ mail_filter_delete_uri(CamelStore *store, const gchar *uri)
 	data_dir = em_utils_get_data_dir ();
 	user = g_build_filename (data_dir, "filters.xml", NULL);
 	system = g_build_filename (EVOLUTION_PRIVDATADIR, "filtertypes.xml", NULL);
-	rule_context_load ((RuleContext *)fc, system, user);
+	e_rule_context_load ((ERuleContext *)fc, system, user);
 	g_free (system);
 
-	deleted = rule_context_delete_uri ((RuleContext *) fc, euri, g_str_equal);
+	deleted = e_rule_context_delete_uri ((ERuleContext *) fc, euri, g_str_equal);
 	if (deleted) {
 		GtkWidget *dialog;
 		GString *s;
@@ -436,9 +436,9 @@ mail_filter_delete_uri(CamelStore *store, const gchar *uri)
 		em_utils_show_info_silent (dialog);
 
 		d(printf("Folder delete/rename '%s' changed filters, resaving\n", euri));
-		if (rule_context_save ((RuleContext *) fc, user) == -1)
+		if (e_rule_context_save ((ERuleContext *) fc, user) == -1)
 			g_warning ("Could not write out changed filter rules\n");
-		rule_context_free_uri_list ((RuleContext *) fc, deleted);
+		e_rule_context_free_uri_list ((ERuleContext *) fc, deleted);
 	}
 
 	g_free(user);
diff --git a/mail/mail-autofilter.h b/mail/mail-autofilter.h
index 8ad9858..fb474ab 100644
--- a/mail/mail-autofilter.h
+++ b/mail/mail-autofilter.h
@@ -26,7 +26,7 @@
 
 #include <camel/camel-mime-message.h>
 
-#include <filter/filter-rule.h>
+#include <filter/e-filter-rule.h>
 #include <mail/em-filter-context.h>
 #include <mail/em-vfolder-context.h>
 
@@ -37,9 +37,9 @@ enum {
 	AUTO_MLIST = 8
 };
 
-FilterRule *em_vfolder_rule_from_message(EMVFolderContext *context, CamelMimeMessage *msg, gint flags, const gchar *source);
-FilterRule *filter_rule_from_message(EMFilterContext *context, CamelMimeMessage *msg, gint flags);
-FilterRule *em_vfolder_rule_from_address(EMVFolderContext *context, CamelInternetAddress *addr, gint flags, const gchar *source);
+EFilterRule *em_vfolder_rule_from_message(EMVFolderContext *context, CamelMimeMessage *msg, gint flags, const gchar *source);
+EFilterRule *filter_rule_from_message(EMFilterContext *context, CamelMimeMessage *msg, gint flags);
+EFilterRule *em_vfolder_rule_from_address(EMVFolderContext *context, CamelInternetAddress *addr, gint flags, const gchar *source);
 
 /* easiest place to put this */
 void  filter_gui_add_from_message(CamelMimeMessage *msg, const gchar *source, gint flags);
diff --git a/mail/mail-ops.c b/mail/mail-ops.c
index a251c87..27b5ef8 100644
--- a/mail/mail-ops.c
+++ b/mail/mail-ops.c
@@ -231,13 +231,13 @@ mail_filter_folder (CamelFolder *source_folder, GPtrArray *uids,
 void
 mail_filter_on_demand (CamelFolder *folder, GPtrArray *uids)
 {
-	mail_filter_folder (folder, uids, FILTER_SOURCE_DEMAND, FALSE, NULL);
+	mail_filter_folder (folder, uids, E_FILTER_SOURCE_DEMAND, FALSE, NULL);
 }
 
 void
 mail_filter_junk (CamelFolder *folder, GPtrArray *uids)
 {
-	mail_filter_folder (folder, uids, FILTER_SOURCE_JUNKTEST, FALSE, NULL);
+	mail_filter_folder (folder, uids, E_FILTER_SOURCE_JUNKTEST, FALSE, NULL);
 }
 
 /* ********************************************************************** */
diff --git a/mail/mail-send-recv.c b/mail/mail-send-recv.c
index b0cff31..6244685 100644
--- a/mail/mail-send-recv.c
+++ b/mail/mail-send-recv.c
@@ -741,7 +741,7 @@ receive_done (const gchar *uri, gpointer data)
 		info->again = 0;
 		mail_send_queue (local_outbox,
 				 info->uri,
-				 FILTER_SOURCE_OUTGOING,
+				 E_FILTER_SOURCE_OUTGOING,
 				 info->cancel,
 				 receive_get_folder, info,
 				 receive_status, info,
@@ -1002,7 +1002,7 @@ mail_send_receive (GtkWindow *parent)
 		switch (info->type) {
 		case SEND_RECEIVE:
 			mail_fetch_mail(info->uri, info->keep_on_server,
-					FILTER_SOURCE_INCOMING,
+					E_FILTER_SOURCE_INCOMING,
 					info->cancel,
 					receive_get_folder, info,
 					receive_status, info,
@@ -1011,7 +1011,7 @@ mail_send_receive (GtkWindow *parent)
 		case SEND_SEND:
 			/* todo, store the folder in info? */
 			mail_send_queue(local_outbox, info->uri,
-					FILTER_SOURCE_OUTGOING,
+					E_FILTER_SOURCE_OUTGOING,
 					info->cancel,
 					receive_get_folder, info,
 					receive_status, info,
@@ -1217,7 +1217,7 @@ mail_receive_uri (const gchar *uri, gboolean keep_on_server)
 	switch (info->type) {
 	case SEND_RECEIVE:
 		mail_fetch_mail (info->uri, info->keep_on_server,
-				 FILTER_SOURCE_INCOMING,
+				 E_FILTER_SOURCE_INCOMING,
 				 info->cancel,
 				 receive_get_folder, info,
 				 receive_status, info,
@@ -1227,7 +1227,7 @@ mail_receive_uri (const gchar *uri, gboolean keep_on_server)
 		/* todo, store the folder in info? */
 		local_outbox = e_mail_local_get_folder (E_MAIL_FOLDER_OUTBOX);
 		mail_send_queue (local_outbox, info->uri,
-				 FILTER_SOURCE_OUTGOING,
+				 E_FILTER_SOURCE_OUTGOING,
 				 info->cancel,
 				 receive_get_folder, info,
 				 receive_status, info,
@@ -1289,7 +1289,7 @@ mail_send (void)
 	/* todo, store the folder in info? */
 	local_outbox = e_mail_local_get_folder (E_MAIL_FOLDER_OUTBOX);
 	mail_send_queue (local_outbox, info->uri,
-			 FILTER_SOURCE_OUTGOING,
+			 E_FILTER_SOURCE_OUTGOING,
 			 info->cancel,
 			 receive_get_folder, info,
 			 receive_status, info,
diff --git a/mail/mail-session.c b/mail/mail-session.c
index 2b6f902..967909d 100644
--- a/mail/mail-session.c
+++ b/mail/mail-session.c
@@ -506,19 +506,19 @@ static CamelFilterDriver *
 main_get_filter_driver (CamelSession *session, const gchar *type, CamelException *ex)
 {
 	CamelFilterDriver *driver;
-	FilterRule *rule = NULL;
+	EFilterRule *rule = NULL;
 	const gchar *data_dir;
 	gchar *user, *system;
 	GConfClient *gconf;
-	RuleContext *fc;
+	ERuleContext *fc;
 
 	gconf = mail_config_get_gconf_client ();
 
 	data_dir = e_shell_backend_get_data_dir (session_shell_backend);
 	user = g_build_filename (data_dir, "filters.xml", NULL);
 	system = g_build_filename (EVOLUTION_PRIVDATADIR, "filtertypes.xml", NULL);
-	fc = (RuleContext *) em_filter_context_new ();
-	rule_context_load (fc, system, user);
+	fc = (ERuleContext *) em_filter_context_new ();
+	e_rule_context_load (fc, system, user);
 	g_free (system);
 	g_free (user);
 
@@ -546,23 +546,23 @@ main_get_filter_driver (CamelSession *session, const gchar *type, CamelException
 	camel_filter_driver_set_play_sound_func (driver, session_play_sound, NULL);
 	camel_filter_driver_set_system_beep_func (driver, session_system_beep, NULL);
 
-	if ((!strcmp (type, FILTER_SOURCE_INCOMING) || !strcmp (type, FILTER_SOURCE_JUNKTEST))
+	if ((!strcmp (type, E_FILTER_SOURCE_INCOMING) || !strcmp (type, E_FILTER_SOURCE_JUNKTEST))
 	    && camel_session_check_junk (session)) {
 		/* implicit junk check as 1st rule */
 		camel_filter_driver_add_rule (driver, "Junk check", "(junk-test)", "(begin (set-system-flag \"junk\"))");
 	}
 
-	if (strcmp (type, FILTER_SOURCE_JUNKTEST) != 0) {
+	if (strcmp (type, E_FILTER_SOURCE_JUNKTEST) != 0) {
 		GString *fsearch, *faction;
 
 		fsearch = g_string_new ("");
 		faction = g_string_new ("");
 
-		if (!strcmp (type, FILTER_SOURCE_DEMAND))
-			type = FILTER_SOURCE_INCOMING;
+		if (!strcmp (type, E_FILTER_SOURCE_DEMAND))
+			type = E_FILTER_SOURCE_INCOMING;
 
 		/* add the user-defined rules next */
-		while ((rule = rule_context_next_rule (fc, rule, type))) {
+		while ((rule = e_rule_context_next_rule (fc, rule, type))) {
 			g_string_truncate (fsearch, 0);
 			g_string_truncate (faction, 0);
 
@@ -570,7 +570,7 @@ main_get_filter_driver (CamelSession *session, const gchar *type, CamelException
 			if (!rule->enabled)
 				continue;
 
-			filter_rule_build_code (rule, fsearch);
+			e_filter_rule_build_code (rule, fsearch);
 			em_filter_rule_build_action ((EMFilterRule *) rule, faction);
 			camel_filter_driver_add_rule (driver, rule->name, fsearch->str, faction->str);
 		}
diff --git a/mail/mail-tools.c b/mail/mail-tools.c
index 4c21a6d..1403605 100644
--- a/mail/mail-tools.c
+++ b/mail/mail-tools.c
@@ -44,8 +44,8 @@
 #include <camel/camel-movemail.h>
 #include <camel/camel-vee-folder.h>
 
-#include "filter/filter-option.h"
-#include "filter/filter-input.h"
+#include "filter/e-filter-option.h"
+#include "filter/e-filter-input.h"
 
 #include <libedataserver/e-data-server-util.h>
 #include "em-utils.h"
diff --git a/mail/mail-vfolder.c b/mail/mail-vfolder.c
index 1612b28..9fed827 100644
--- a/mail/mail-vfolder.c
+++ b/mail/mail-vfolder.c
@@ -69,7 +69,7 @@ static volatile gint shutdown;		/* are we shutting down? */
 /* more globals ... */
 extern CamelSession *session;
 
-static void rule_changed(FilterRule *rule, CamelFolder *folder);
+static void rule_changed(EFilterRule *rule, CamelFolder *folder);
 
 /* ********************************************************************** */
 
@@ -427,7 +427,7 @@ uri_is_spethal(CamelStore *store, const gchar *uri)
 void
 mail_vfolder_add_uri(CamelStore *store, const gchar *curi, gint remove)
 {
-	FilterRule *rule;
+	EFilterRule *rule;
 	const gchar *source;
 	CamelVeeFolder *vf;
 	GList *folders = NULL, *link;
@@ -479,7 +479,7 @@ mail_vfolder_add_uri(CamelStore *store, const gchar *curi, gint remove)
 		goto done;
 
 	rule = NULL;
-	while ((rule = rule_context_next_rule((RuleContext *)context, rule, NULL))) {
+	while ((rule = e_rule_context_next_rule((ERuleContext *)context, rule, NULL))) {
 		gint found = FALSE;
 
 		if (!rule->name) {
@@ -527,7 +527,7 @@ done:
 void
 mail_vfolder_delete_uri(CamelStore *store, const gchar *curi)
 {
-	FilterRule *rule;
+	EFilterRule *rule;
 	const gchar *source;
 	CamelVeeFolder *vf;
 	GString *changed;
@@ -552,7 +552,7 @@ mail_vfolder_delete_uri(CamelStore *store, const gchar *curi)
 
 	/* see if any rules directly reference this removed uri */
 	rule = NULL;
-	while ((rule = rule_context_next_rule ((RuleContext *) context, rule, NULL))) {
+	while ((rule = e_rule_context_next_rule ((ERuleContext *) context, rule, NULL))) {
 
 		if (!rule->name) {
 			d(printf("invalid rule (%p): rule->name is set to NULL\n", rule));
@@ -605,7 +605,7 @@ done:
 
 		data_dir = em_utils_get_data_dir ();
 		user = g_build_filename (data_dir, "vfolders.xml", NULL);
-		rule_context_save ((RuleContext *) context, user);
+		e_rule_context_save ((ERuleContext *) context, user);
 		g_free (user);
 	}
 
@@ -618,7 +618,7 @@ done:
 void
 mail_vfolder_rename_uri(CamelStore *store, const gchar *cfrom, const gchar *cto)
 {
-	FilterRule *rule;
+	EFilterRule *rule;
 	const gchar *source;
 	CamelVeeFolder *vf;
 	gint changed = 0;
@@ -638,7 +638,7 @@ mail_vfolder_rename_uri(CamelStore *store, const gchar *cfrom, const gchar *cto)
 
 	/* see if any rules directly reference this removed uri */
 	rule = NULL;
-	while ( (rule = rule_context_next_rule((RuleContext *)context, rule, NULL)) ) {
+	while ( (rule = e_rule_context_next_rule((ERuleContext *)context, rule, NULL)) ) {
 		source = NULL;
 		while ( (source = em_vfolder_rule_next_source((EMVFolderRule *)rule, source)) ) {
 			gchar *csource = em_uri_to_camel(source);
@@ -673,7 +673,7 @@ mail_vfolder_rename_uri(CamelStore *store, const gchar *cfrom, const gchar *cto)
 		d(printf("Vfolders updated from renamed folder\n"));
 		data_dir = em_utils_get_data_dir ();
 		user = g_build_filename (data_dir, "vfolders.xml", NULL);
-		rule_context_save((RuleContext *)context, user);
+		e_rule_context_save((ERuleContext *)context, user);
 		g_free(user);
 	}
 
@@ -695,7 +695,7 @@ mail_vfolder_get_sources_remote (void)
 
 /* ********************************************************************** */
 
-static void context_rule_added(RuleContext *ctx, FilterRule *rule);
+static void context_rule_added(ERuleContext *ctx, EFilterRule *rule);
 
 static void
 rule_add_sources(GList *l, GList **sources_folderp, GList **sources_urip)
@@ -722,7 +722,7 @@ rule_add_sources(GList *l, GList **sources_folderp, GList **sources_urip)
 }
 
 static void
-rule_changed(FilterRule *rule, CamelFolder *folder)
+rule_changed(EFilterRule *rule, CamelFolder *folder)
 {
 	GList *sources_uri = NULL, *sources_folder = NULL;
 	GString *query;
@@ -765,14 +765,14 @@ rule_changed(FilterRule *rule, CamelFolder *folder)
 	G_UNLOCK (vfolder);
 
 	query = g_string_new("");
-	filter_rule_build_code(rule, query);
+	e_filter_rule_build_code(rule, query);
 
 	vfolder_setup(folder, query->str, sources_uri, sources_folder);
 
 	g_string_free(query, TRUE);
 }
 
-static void context_rule_added(RuleContext *ctx, FilterRule *rule)
+static void context_rule_added(ERuleContext *ctx, EFilterRule *rule)
 {
 	CamelFolder *folder;
 
@@ -791,7 +791,7 @@ static void context_rule_added(RuleContext *ctx, FilterRule *rule)
 	}
 }
 
-static void context_rule_removed(RuleContext *ctx, FilterRule *rule)
+static void context_rule_removed(ERuleContext *ctx, EFilterRule *rule)
 {
 	gpointer key, folder = NULL;
 
@@ -827,7 +827,7 @@ store_folder_deleted(CamelObject *o, gpointer event_data, gpointer data)
 {
 	CamelStore *store = (CamelStore *)o;
 	CamelFolderInfo *info = event_data;
-	FilterRule *rule;
+	EFilterRule *rule;
 	gchar *user;
 
 	d(printf("Folder deleted: %s\n", info->name));
@@ -838,20 +838,20 @@ store_folder_deleted(CamelObject *o, gpointer event_data, gpointer data)
 	G_LOCK (vfolder);
 
 	/* delete it from our list */
-	rule = rule_context_find_rule((RuleContext *)context, info->full_name, NULL);
+	rule = e_rule_context_find_rule((ERuleContext *)context, info->full_name, NULL);
 	if (rule) {
 		const gchar *data_dir;
 
 		/* We need to stop listening to removed events, otherwise we'll try and remove it again */
 		g_signal_handlers_disconnect_matched(context, G_SIGNAL_MATCH_FUNC|G_SIGNAL_MATCH_DATA, 0,
 						     0, NULL, context_rule_removed, context);
-		rule_context_remove_rule((RuleContext *)context, rule);
+		e_rule_context_remove_rule((ERuleContext *)context, rule);
 		g_object_unref(rule);
 		g_signal_connect(context, "rule_removed", G_CALLBACK(context_rule_removed), context);
 
 		data_dir = em_utils_get_data_dir ();
 		user = g_build_filename (data_dir, "vfolders.xml", NULL);
-		rule_context_save((RuleContext *)context, user);
+		e_rule_context_save((ERuleContext *)context, user);
 		g_free(user);
 	} else {
 		g_warning("Cannot find rule for deleted vfolder '%s'", info->name);
@@ -864,7 +864,7 @@ static void
 store_folder_renamed(CamelObject *o, gpointer event_data, gpointer data)
 {
 	CamelRenameInfo *info = event_data;
-	FilterRule *rule;
+	EFilterRule *rule;
 	gchar *user;
 
 	gpointer key, folder;
@@ -883,7 +883,7 @@ store_folder_renamed(CamelObject *o, gpointer event_data, gpointer data)
 		g_free (key);
 		g_hash_table_insert (vfolder_hash, g_strdup(info->new->full_name), folder);
 
-		rule = rule_context_find_rule((RuleContext *)context, info->old_base, NULL);
+		rule = e_rule_context_find_rule((ERuleContext *)context, info->old_base, NULL);
 		if (!rule) {
 			G_UNLOCK (vfolder);
 			g_warning ("Rule shouldn't be NULL\n");
@@ -892,12 +892,12 @@ store_folder_renamed(CamelObject *o, gpointer event_data, gpointer data)
 
 		g_signal_handlers_disconnect_matched(rule, G_SIGNAL_MATCH_FUNC|G_SIGNAL_MATCH_DATA, 0,
 						     0, NULL, rule_changed, folder);
-		filter_rule_set_name(rule, info->new->full_name);
+		e_filter_rule_set_name(rule, info->new->full_name);
 		g_signal_connect(rule, "changed", G_CALLBACK(rule_changed), folder);
 
 		data_dir = em_utils_get_data_dir ();
 		user = g_build_filename (data_dir, "vfolders.xml", NULL);
-		rule_context_save((RuleContext *)context, user);
+		e_rule_context_save((ERuleContext *)context, user);
 		g_free(user);
 
 		G_UNLOCK (vfolder);
@@ -915,7 +915,7 @@ vfolder_load_storage(void)
 
 	const gchar *data_dir;
 	gchar *user, *storeuri;
-	FilterRule *rule;
+	EFilterRule *rule;
 	gchar *xmlfile;
 	GConfClient *gconf;
 
@@ -954,9 +954,9 @@ vfolder_load_storage(void)
 	context = em_vfolder_context_new ();
 
 	xmlfile = g_build_filename (EVOLUTION_PRIVDATADIR, "vfoldertypes.xml", NULL);
-	if (rule_context_load ((RuleContext *)context,
+	if (e_rule_context_load ((ERuleContext *)context,
 			       xmlfile, user) != 0) {
-		g_warning("cannot load vfolders: %s\n", ((RuleContext *)context)->error);
+		g_warning("cannot load vfolders: %s\n", ((ERuleContext *)context)->error);
 	}
 	g_free (xmlfile);
 	g_free (user);
@@ -969,10 +969,10 @@ vfolder_load_storage(void)
 
 	/* and setup the rules we have */
 	rule = NULL;
-	while ( (rule = rule_context_next_rule((RuleContext *)context, rule, NULL)) ) {
+	while ( (rule = e_rule_context_next_rule((ERuleContext *)context, rule, NULL)) ) {
 		if (rule->name) {
 			d(printf("rule added: %s\n", rule->name));
-			context_rule_added((RuleContext *)context, rule);
+			context_rule_added((ERuleContext *)context, rule);
 		} else {
 			d(printf("invalid rule (%p) encountered: rule->name is NULL\n", rule));
 		}
@@ -995,7 +995,7 @@ vfolder_revert(void)
 	d(printf("vfolder_revert\n"));
 	data_dir = em_utils_get_data_dir ();
 	user = g_build_filename (data_dir, "vfolders.xml", NULL);
-	rule_context_revert((RuleContext *)context, user);
+	e_rule_context_revert((ERuleContext *)context, user);
 	g_free(user);
 }
 
@@ -1027,10 +1027,10 @@ vfolder_edit (EShellView *shell_view)
 
 	switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
 		case GTK_RESPONSE_OK:
-			rule_context_save ((RuleContext *) context, filename);
+			e_rule_context_save ((ERuleContext *) context, filename);
 			break;
 		default:
-			rule_context_revert ((RuleContext *) context, filename);
+			e_rule_context_revert ((ERuleContext *) context, filename);
 			break;
 	}
 
@@ -1043,13 +1043,13 @@ edit_rule_response(GtkWidget *w, gint button, gpointer data)
 	if (button == GTK_RESPONSE_OK) {
 		const gchar *data_dir;
 		gchar *user;
-		FilterRule *rule = g_object_get_data (G_OBJECT (w), "rule");
-		FilterRule *orig = g_object_get_data (G_OBJECT (w), "orig");
+		EFilterRule *rule = g_object_get_data (G_OBJECT (w), "rule");
+		EFilterRule *orig = g_object_get_data (G_OBJECT (w), "orig");
 
-		filter_rule_copy(orig, rule);
+		e_filter_rule_copy(orig, rule);
 		data_dir = em_utils_get_data_dir ();
 		user = g_build_filename (data_dir, "vfolders.xml", NULL);
-		rule_context_save((RuleContext *)context, user);
+		e_rule_context_save((ERuleContext *)context, user);
 		g_free(user);
 	}
 
@@ -1061,16 +1061,16 @@ vfolder_edit_rule(const gchar *uri)
 {
 	GtkWidget *w;
 	GtkDialog *gd;
-	FilterRule *rule, *newrule;
+	EFilterRule *rule, *newrule;
 	CamelURL *url;
 
 	url = camel_url_new(uri, NULL);
 	if (url && url->fragment
-	    && (rule = rule_context_find_rule((RuleContext *)context, url->fragment, NULL))) {
+	    && (rule = e_rule_context_find_rule((ERuleContext *)context, url->fragment, NULL))) {
 		g_object_ref((GtkObject *)rule);
-		newrule = filter_rule_clone(rule);
+		newrule = e_filter_rule_clone(rule);
 
-		w = filter_rule_get_widget((FilterRule *)newrule, (RuleContext *)context);
+		w = e_filter_rule_get_widget((EFilterRule *)newrule, (ERuleContext *)context);
 
 		gd = (GtkDialog *)gtk_dialog_new_with_buttons(_("Edit Search Folder"), NULL,
 							      GTK_DIALOG_DESTROY_WITH_PARENT,
@@ -1108,44 +1108,44 @@ new_rule_clicked(GtkWidget *w, gint button, gpointer data)
 	if (button == GTK_RESPONSE_OK) {
 		const gchar *data_dir;
 		gchar *user;
-		FilterRule *rule = g_object_get_data((GObject *)w, "rule");
+		EFilterRule *rule = g_object_get_data((GObject *)w, "rule");
 
-		if (!filter_rule_validate (rule, GTK_WINDOW (w))) {
+		if (!e_filter_rule_validate (rule, GTK_WINDOW (w))) {
 			/* no need to popup a dialog because the validate code does that. */
 			return;
 		}
 
-		if (rule_context_find_rule ((RuleContext *)context, rule->name, rule->source)) {
+		if (e_rule_context_find_rule ((ERuleContext *)context, rule->name, rule->source)) {
 			e_error_run ((GtkWindow *)w, "mail:vfolder-notunique", rule->name, NULL);
 			return;
 		}
 
 		g_object_ref(rule);
-		rule_context_add_rule((RuleContext *)context, rule);
+		e_rule_context_add_rule((ERuleContext *)context, rule);
 		data_dir = em_utils_get_data_dir ();
 		user = g_build_filename (data_dir, "vfolders.xml", NULL);
-		rule_context_save((RuleContext *)context, user);
+		e_rule_context_save((ERuleContext *)context, user);
 		g_free(user);
 	}
 
 	gtk_widget_destroy(w);
 }
 
-FilterPart *
+EFilterPart *
 vfolder_create_part(const gchar *name)
 {
-	return rule_context_create_part((RuleContext *)context, name);
+	return e_rule_context_create_part((ERuleContext *)context, name);
 }
 
 /* clones a filter/search rule into a matching vfolder rule (assuming the same system definitions) */
-FilterRule *
-vfolder_clone_rule(FilterRule *in)
+EFilterRule *
+vfolder_clone_rule(EFilterRule *in)
 {
-	FilterRule *rule = (FilterRule *)em_vfolder_rule_new();
+	EFilterRule *rule = (EFilterRule *)em_vfolder_rule_new();
 	xmlNodePtr xml;
 
-	xml = filter_rule_xml_encode(in);
-	filter_rule_xml_decode(rule, xml, (RuleContext *)context);
+	xml = e_filter_rule_xml_encode(in);
+	e_filter_rule_xml_decode(rule, xml, (ERuleContext *)context);
 	xmlFreeNodeList(xml);
 
 	return rule;
@@ -1161,7 +1161,7 @@ vfolder_gui_add_rule(EMVFolderRule *rule)
 	/* this should be done before we call this function */
 	vfolder_load_storage ();
 
-	w = filter_rule_get_widget((FilterRule *)rule, (RuleContext *)context);
+	w = e_filter_rule_get_widget((EFilterRule *)rule, (ERuleContext *)context);
 
 	gd = (GtkDialog *)gtk_dialog_new_with_buttons(_("New Search Folder"),
 						      NULL,
diff --git a/mail/mail-vfolder.h b/mail/mail-vfolder.h
index b3299ab..725f7ec 100644
--- a/mail/mail-vfolder.h
+++ b/mail/mail-vfolder.h
@@ -25,8 +25,8 @@
 #include <camel/camel-internet-address.h>
 #include <camel/camel-mime-message.h>
 
-#include <filter/filter-part.h>
-#include <filter/filter-rule.h>
+#include <filter/e-filter-part.h>
+#include <filter/e-filter-rule.h>
 #include <mail/em-vfolder-rule.h>
 #include <shell/e-shell-view.h>
 
@@ -35,8 +35,8 @@ void vfolder_revert(void);
 
 void vfolder_edit (EShellView *shell_view);
 void vfolder_edit_rule(const gchar *name);
-FilterPart *vfolder_create_part (const gchar *name);
-FilterRule *vfolder_clone_rule (FilterRule *in);
+EFilterPart *vfolder_create_part (const gchar *name);
+EFilterRule *vfolder_clone_rule (EFilterRule *in);
 void vfolder_gui_add_rule (EMVFolderRule *rule);
 void vfolder_gui_add_from_message (CamelMimeMessage *msg, gint flags, const gchar *source);
 void vfolder_gui_add_from_address (CamelInternetAddress *addr, gint flags, const gchar *source);
diff --git a/modules/addressbook/e-book-shell-view-actions.c b/modules/addressbook/e-book-shell-view-actions.c
index 1d875ba..c680c64 100644
--- a/modules/addressbook/e-book-shell-view-actions.c
+++ b/modules/addressbook/e-book-shell-view-actions.c
@@ -23,7 +23,7 @@
 
 #include <e-util/e-error.h>
 #include <e-util/e-util.h>
-#include <filter/filter-rule.h>
+#include <filter/e-filter-rule.h>
 
 #include <addressbook-config.h>
 
diff --git a/modules/addressbook/e-book-shell-view.c b/modules/addressbook/e-book-shell-view.c
index f7019b0..4a09a14 100644
--- a/modules/addressbook/e-book-shell-view.c
+++ b/modules/addressbook/e-book-shell-view.c
@@ -131,7 +131,7 @@ book_shell_view_execute_search (EShellView *shell_view)
 	GString *string;
 	EAddressbookView *view;
 	EAddressbookModel *model;
-	FilterRule *rule;
+	EFilterRule *rule;
 	const gchar *format;
 	const gchar *text;
 	gchar *query;
@@ -208,10 +208,10 @@ book_shell_view_execute_search (EShellView *shell_view)
 		}
 	}
 
-	/* XXX This is wrong.  We need to programmatically construct a
-	 *     FilterRule, tell it to build code, and pass the resulting
+	/* XXX This is wrong.  We need to programmatically construct an
+	 *     EFilterRule, tell it to build code, and pass the resulting
 	 *     expression string to EAddressbookModel. */
-	rule = filter_rule_new ();
+	rule = e_filter_rule_new ();
 	e_shell_content_set_search_rule (shell_content, rule);
 	g_object_unref (rule);
 
diff --git a/modules/calendar/e-cal-shell-view.c b/modules/calendar/e-cal-shell-view.c
index 32f12b6..41782de 100644
--- a/modules/calendar/e-cal-shell-view.c
+++ b/modules/calendar/e-cal-shell-view.c
@@ -63,7 +63,7 @@ cal_shell_view_execute_search (EShellView *shell_view)
 	ECalendar *date_navigator;
 	GtkRadioAction *action;
 	GString *string;
-	FilterRule *rule;
+	EFilterRule *rule;
 	const gchar *format;
 	const gchar *text;
 	time_t start_range;
@@ -179,10 +179,10 @@ cal_shell_view_execute_search (EShellView *shell_view)
 		}
 	}
 
-	/* XXX This is wrong.  We need to programmatically construct a
-	 *     FilterRule, tell it to build code, and pass the resulting
+	/* XXX This is wrong.  We need to programmatically construct an
+	 *     EFilterRule, tell it to build code, and pass the resulting
 	 *     expressing string to ECalModel. */
-	rule = filter_rule_new ();
+	rule = e_filter_rule_new ();
 	e_shell_content_set_search_rule (shell_content, rule);
 	g_object_unref (rule);
 
diff --git a/modules/calendar/e-memo-shell-view.c b/modules/calendar/e-memo-shell-view.c
index ea869b5..f5698fe 100644
--- a/modules/calendar/e-memo-shell-view.c
+++ b/modules/calendar/e-memo-shell-view.c
@@ -62,7 +62,7 @@ memo_shell_view_execute_search (EShellView *shell_view)
 	ECalComponentPreview *memo_preview;
 	EMemoTable *memo_table;
 	ECalModel *model;
-	FilterRule *rule;
+	EFilterRule *rule;
 	const gchar *format;
 	const gchar *text;
 	gchar *query;
@@ -135,10 +135,10 @@ memo_shell_view_execute_search (EShellView *shell_view)
 		}
 	}
 
-	/* XXX This is wrong.  We need to programmatically construct a
-	 *     FilterRule, tell it to build code, and pass the resulting
+	/* XXX This is wrong.  We need to programmatically construct an
+	 *     EFilterRule, tell it to build code, and pass the resulting
 	 *     expression string to ECalModel. */
-	rule = filter_rule_new ();
+	rule = e_filter_rule_new ();
 	e_shell_content_set_search_rule (shell_content, rule);
 	g_object_unref (rule);
 
diff --git a/modules/calendar/e-task-shell-view.c b/modules/calendar/e-task-shell-view.c
index 650037b..ec7d697 100644
--- a/modules/calendar/e-task-shell-view.c
+++ b/modules/calendar/e-task-shell-view.c
@@ -101,7 +101,7 @@ task_shell_view_execute_search (EShellView *shell_view)
 	ECalComponentPreview *task_preview;
 	ECalendarTable *task_table;
 	ECalModel *model;
-	FilterRule *rule;
+	EFilterRule *rule;
 	const gchar *format;
 	const gchar *text;
 	time_t start_range;
@@ -247,10 +247,10 @@ task_shell_view_execute_search (EShellView *shell_view)
 		query = temp2;
 	}
 
-	/* XXX This is wrong.  We need to programmatically construct a
-	 *     FilterRule, tell it to build code, and pass the resulting
+	/* XXX This is wrong.  We need to programmatically construct an
+	 *     EFilterRule, tell it to build code, and pass the resulting
 	 *     expression string to ECalModel. */
-	rule = filter_rule_new ();
+	rule = e_filter_rule_new ();
 	e_shell_content_set_search_rule (shell_content, rule);
 	g_object_unref (rule);
 
diff --git a/modules/mail/e-mail-shell-backend.c b/modules/mail/e-mail-shell-backend.c
index 877087c..0572cfd 100644
--- a/modules/mail/e-mail-shell-backend.c
+++ b/modules/mail/e-mail-shell-backend.c
@@ -935,7 +935,7 @@ e_mail_shell_backend_register_type (GTypeModule *type_module)
 
 /******************* Code below here belongs elsewhere. *******************/
 
-#include "filter/filter-option.h"
+#include "filter/e-filter-option.h"
 #include "shell/e-shell-settings.h"
 #include "mail/e-mail-label-list-store.h"
 
diff --git a/modules/mail/e-mail-shell-view-actions.c b/modules/mail/e-mail-shell-view-actions.c
index 22aa88e..07fdf8f 100644
--- a/modules/mail/e-mail-shell-view-actions.c
+++ b/modules/mail/e-mail-shell-view-actions.c
@@ -84,7 +84,7 @@ action_mail_create_search_folder_cb (GtkAction *action,
 	EShellView *shell_view;
 	EShellContent *shell_content;
 	MessageList *message_list;
-	FilterRule *search_rule;
+	EFilterRule *search_rule;
 	EMVFolderRule *vfolder_rule;
 	const gchar *folder_uri;
 	const gchar *search_text;
@@ -108,8 +108,8 @@ action_mail_create_search_folder_cb (GtkAction *action,
 
 	search_rule = vfolder_clone_rule (search_rule);
 	rule_name = g_strdup_printf ("%s %s", search_rule->name, search_text);
-	filter_rule_set_source (search_rule, FILTER_SOURCE_INCOMING);
-	filter_rule_set_name (search_rule, rule_name);
+	e_filter_rule_set_source (search_rule, E_FILTER_SOURCE_INCOMING);
+	e_filter_rule_set_name (search_rule, rule_name);
 	g_free (rule_name);
 
 	vfolder_rule = EM_VFOLDER_RULE (search_rule);
@@ -969,7 +969,7 @@ action_search_quick_cb (GtkAction *action,
 	EShellView *shell_view;
 	EShellWindow *shell_window;
 	EShellContent *shell_content;
-	FilterRule *search_rule;
+	EFilterRule *search_rule;
 	gint value;
 
 	/* Set the search rule in EShellContent so that "Create
diff --git a/modules/mail/e-mail-shell-view-private.c b/modules/mail/e-mail-shell-view-private.c
index e6c5417..dd124f4 100644
--- a/modules/mail/e-mail-shell-view-private.c
+++ b/modules/mail/e-mail-shell-view-private.c
@@ -347,8 +347,8 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view)
 	EShellWindow *shell_window;
 	EMFormatHTMLDisplay *html_display;
 	EMFolderTree *folder_tree;
-	RuleContext *context;
-	FilterRule *rule = NULL;
+	ERuleContext *context;
+	EFilterRule *rule = NULL;
 	GtkTreeSelection *selection;
 	GtkTreeModel *tree_model;
 	GtkUIManager *ui_manager;
@@ -489,8 +489,8 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view)
 	 * Keep the assertions, please.  If the conditions aren't
 	 * met we're going to crash anyway, just more mysteriously. */
 	context = e_shell_content_get_search_context (shell_content);
-	source = FILTER_SOURCE_DEMAND;
-	while ((rule = rule_context_next_rule (context, rule, source))) {
+	source = E_FILTER_SOURCE_DEMAND;
+	while ((rule = e_rule_context_next_rule (context, rule, source))) {
 		g_assert (ii < MAIL_NUM_SEARCH_RULES);
 		priv->search_rules[ii++] = g_object_ref (rule);
 	}
@@ -592,11 +592,11 @@ e_mail_shell_view_create_filter_from_selected (EMailShellView *mail_shell_view,
 	folder = message_list->folder;
 
 	if (em_utils_folder_is_sent (folder, folder_uri))
-		filter_source = FILTER_SOURCE_OUTGOING;
+		filter_source = E_FILTER_SOURCE_OUTGOING;
 	else if (em_utils_folder_is_outbox (folder, folder_uri))
-		filter_source = FILTER_SOURCE_OUTGOING;
+		filter_source = E_FILTER_SOURCE_OUTGOING;
 	else
-		filter_source = FILTER_SOURCE_INCOMING;
+		filter_source = E_FILTER_SOURCE_INCOMING;
 
 	uids = message_list_get_selected (message_list);
 
diff --git a/modules/mail/e-mail-shell-view-private.h b/modules/mail/e-mail-shell-view-private.h
index a1c823c..bf86f33 100644
--- a/modules/mail/e-mail-shell-view-private.h
+++ b/modules/mail/e-mail-shell-view-private.h
@@ -35,7 +35,7 @@
 #include "e-util/e-binding.h"
 #include "e-util/gconf-bridge.h"
 #include "e-util/e-account-utils.h"
-#include "filter/filter-part.h"
+#include "filter/e-filter-part.h"
 #include "widgets/misc/e-web-view.h"
 #include "widgets/misc/e-popup-action.h"
 #include "widgets/menus/gal-view-instance.h"
@@ -137,7 +137,7 @@ struct _EMailShellViewPrivate {
 	guint label_merge_id;
 
 	/* Filter rules correspond to the search entry menu. */
-	FilterRule *search_rules[MAIL_NUM_SEARCH_RULES];
+	EFilterRule *search_rules[MAIL_NUM_SEARCH_RULES];
 
 	guint show_deleted : 1;
 };
diff --git a/modules/mail/e-mail-shell-view.c b/modules/mail/e-mail-shell-view.c
index b2ea509..3c82e51 100644
--- a/modules/mail/e-mail-shell-view.c
+++ b/modules/mail/e-mail-shell-view.c
@@ -92,7 +92,7 @@ mail_shell_view_execute_search (EShellView *shell_view)
 	EMFormatHTMLDisplay *html_display;
 	EMailShellContent *mail_shell_content;
 	MessageList *message_list;
-	FilterRule *rule;
+	EFilterRule *rule;
 	EMailReader *reader;
 	CamelFolder *folder;
 	GtkAction *action;
@@ -169,17 +169,17 @@ mail_shell_view_execute_search (EShellView *shell_view)
 	rule = priv->search_rules[value];
 
 	for (iter = rule->parts; iter != NULL; iter = iter->next) {
-		FilterPart *part = iter->data;
-		FilterElement *element = NULL;
+		EFilterPart *part = iter->data;
+		EFilterElement *element = NULL;
 
 		if (strcmp (part->name, "subject") == 0)
-			element = filter_part_find_element (part, "subject");
+			element = e_filter_part_find_element (part, "subject");
 		else if (strcmp (part->name, "body") == 0)
-			element = filter_part_find_element (part, "word");
+			element = e_filter_part_find_element (part, "word");
 		else if (strcmp (part->name, "sender") == 0)
-			element = filter_part_find_element (part, "sender");
+			element = e_filter_part_find_element (part, "sender");
 		else if (strcmp (part->name, "to") == 0)
-			element = filter_part_find_element (part, "recipient");
+			element = e_filter_part_find_element (part, "recipient");
 
 		if (strcmp (part->name, "body") == 0) {
 			struct _camel_search_words *words;
@@ -194,13 +194,13 @@ mail_shell_view_execute_search (EShellView *shell_view)
 		}
 
 		if (element != NULL) {
-			FilterInput *input = FILTER_INPUT (element);
-			filter_input_set_value (input, text);
+			EFilterInput *input = E_FILTER_INPUT (element);
+			e_filter_input_set_value (input, text);
 		}
 	}
 
 	string = g_string_sized_new (1024);
-	filter_rule_build_code (rule, string);
+	e_filter_rule_build_code (rule, string);
 	query = g_string_free (string, FALSE);
 
 filter:
diff --git a/plugins/groupwise-features/share-folder-common.c b/plugins/groupwise-features/share-folder-common.c
index 3856fcc..b00559a 100644
--- a/plugins/groupwise-features/share-folder-common.c
+++ b/plugins/groupwise-features/share-folder-common.c
@@ -37,7 +37,7 @@
 #include <mail/mail-config.h>
 #include <mail/mail-vfolder.h>
 #include <mail/em-vfolder-rule.h>
-#include <filter/filter-rule.h>
+#include <filter/e-filter-rule.h>
 #include <camel/camel-store.h>
 #include <camel/camel-session.h>
 #include <camel/camel-store.h>
@@ -276,7 +276,7 @@ users_dialog_response(GtkWidget *dialog, gint response, struct ShareInfo *ssi)
 		vfolder_load_storage ();
 
 		rule = em_vfolder_rule_new();
-		filter_rule_set_name((FilterRule *)rule, path);
+		e_filter_rule_set_name((EFilterRule *)rule, path);
 		vfolder_gui_add_rule(rule);
 		gtk_widget_destroy((GtkWidget *)emfs);
 	} else {
diff --git a/shell/e-shell-content.c b/shell/e-shell-content.c
index 6761af7..5d2f3df 100644
--- a/shell/e-shell-content.c
+++ b/shell/e-shell-content.c
@@ -25,7 +25,7 @@
 
 #include "e-util/e-binding.h"
 #include "e-util/e-util.h"
-#include "filter/rule-editor.h"
+#include "filter/e-rule-editor.h"
 #include "widgets/misc/e-action-combo-box.h"
 #include "widgets/misc/e-hinted-entry.h"
 
@@ -45,8 +45,8 @@ struct _EShellContentPrivate {
 
 	gpointer shell_view;  /* weak pointer */
 
-	RuleContext *search_context;
-	FilterRule *search_rule;
+	ERuleContext *search_context;
+	EFilterRule *search_rule;
 	gchar *system_filename;
 	gchar *user_filename;
 
@@ -81,7 +81,7 @@ static gpointer parent_class;
 
 static void
 shell_content_dialog_rule_changed (GtkWidget *dialog,
-                                   FilterRule *rule)
+                                   EFilterRule *rule)
 {
 	gboolean sensitive;
 
@@ -264,9 +264,9 @@ shell_content_init_search_context (EShellContent *shell_content)
 	EShellView *shell_view;
 	EShellViewClass *shell_view_class;
 	EShellBackend *shell_backend;
-	RuleContext *context;
-	FilterRule *rule;
-	FilterPart *part;
+	ERuleContext *context;
+	EFilterRule *rule;
+	EFilterPart *part;
 	gchar *system_filename;
 	gchar *user_filename;
 
@@ -291,13 +291,13 @@ shell_content_init_search_context (EShellContent *shell_content)
 		"searches.xml", NULL);
 
 	context = shell_content_class->new_search_context ();
-	rule_context_add_part_set (
-		context, "partset", FILTER_TYPE_PART,
-		rule_context_add_part, rule_context_next_part);
-	rule_context_add_rule_set (
-		context, "ruleset", FILTER_TYPE_RULE,
-		rule_context_add_rule, rule_context_next_rule);
-	rule_context_load (context, system_filename, user_filename);
+	e_rule_context_add_part_set (
+		context, "partset", E_TYPE_FILTER_PART,
+		e_rule_context_add_part, e_rule_context_next_part);
+	e_rule_context_add_rule_set (
+		context, "ruleset", E_TYPE_FILTER_RULE,
+		e_rule_context_add_rule, e_rule_context_next_rule);
+	e_rule_context_load (context, system_filename, user_filename);
 
 	/* XXX Not sure why this is necessary. */
 	g_object_set_data_full (
@@ -307,14 +307,14 @@ shell_content_init_search_context (EShellContent *shell_content)
 		G_OBJECT (context), "user",
 		g_strdup (user_filename), g_free);
 
-	rule = filter_rule_new ();
-	part = rule_context_next_part (context, NULL);
+	rule = e_filter_rule_new ();
+	part = e_rule_context_next_part (context, NULL);
 	if (part == NULL)
 		g_warning (
 			"Could not load %s search: no parts",
 			e_shell_view_get_name (shell_view));
 	else
-		filter_rule_add_part (rule, filter_part_clone (part));
+		e_filter_rule_add_part (rule, e_filter_part_clone (part));
 
 	shell_content->priv->search_context = context;
 	shell_content->priv->system_filename = system_filename;
@@ -701,7 +701,7 @@ shell_content_class_init (EShellContentClass *class)
 	container_class = GTK_CONTAINER_CLASS (class);
 	container_class->forall = shell_content_forall;
 
-	class->new_search_context = rule_context_new;
+	class->new_search_context = e_rule_context_new;
 
 	g_object_class_install_property (
 		object_class,
@@ -743,7 +743,7 @@ shell_content_class_init (EShellContentClass *class)
 			"search-context",
 			NULL,
 			NULL,
-			RULE_TYPE_CONTEXT,
+			E_TYPE_RULE_CONTEXT,
 			G_PARAM_READABLE));
 
 	g_object_class_install_property (
@@ -763,7 +763,7 @@ shell_content_class_init (EShellContentClass *class)
 			"search-rule",
 			NULL,
 			NULL,
-			FILTER_TYPE_RULE,
+			E_TYPE_FILTER_RULE,
 			G_PARAM_READWRITE));
 
 	g_object_class_install_property (
@@ -1138,7 +1138,7 @@ e_shell_content_add_filter_separator_after (EShellContent *shell_content,
 	e_action_combo_box_add_separator_after (combo_box, action_value);
 }
 
-RuleContext *
+ERuleContext *
 e_shell_content_get_search_context (EShellContent *shell_content)
 {
 	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
@@ -1173,7 +1173,7 @@ e_shell_content_set_search_hint (EShellContent *shell_content,
 	g_object_notify (G_OBJECT (shell_content), "search-hint");
 }
 
-FilterRule *
+EFilterRule *
 e_shell_content_get_search_rule (EShellContent *shell_content)
 {
 	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
@@ -1183,12 +1183,12 @@ e_shell_content_get_search_rule (EShellContent *shell_content)
 
 void
 e_shell_content_set_search_rule (EShellContent *shell_content,
-                                 FilterRule *search_rule)
+                                 EFilterRule *search_rule)
 {
 	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 
 	if (search_rule != NULL) {
-		g_return_if_fail (IS_FILTER_RULE (search_rule));
+		g_return_if_fail (E_IS_FILTER_RULE (search_rule));
 		g_object_ref (search_rule);
 	}
 
@@ -1336,8 +1336,8 @@ e_shell_content_run_advanced_search_dialog (EShellContent *shell_content)
 	EShellWindow *shell_window;
 	GtkWidget *dialog;
 	GtkWidget *widget;
-	FilterRule *rule;
-	RuleContext *context;
+	EFilterRule *rule;
+	ERuleContext *context;
 	const gchar *user_filename;
 	gint response;
 
@@ -1350,13 +1350,13 @@ e_shell_content_run_advanced_search_dialog (EShellContent *shell_content)
 	rule = e_shell_content_get_search_rule (shell_content);
 
 	if (rule == NULL)
-		rule = filter_rule_new ();
+		rule = e_filter_rule_new ();
 	else
-		rule = filter_rule_clone (rule);
+		rule = e_filter_rule_clone (rule);
 
 	context = e_shell_content_get_search_context (shell_content);
-	widget = filter_rule_get_widget (rule, context);
-	filter_rule_set_source (rule, FILTER_SOURCE_INCOMING);
+	widget = e_filter_rule_get_widget (rule, context);
+	e_filter_rule_set_source (rule, E_FILTER_SOURCE_INCOMING);
 
 	dialog = gtk_dialog_new_with_buttons (
 		_("Advanced Search"), GTK_WINDOW (shell_window),
@@ -1384,7 +1384,7 @@ run:
 	if (response != GTK_RESPONSE_OK && response != GTK_RESPONSE_APPLY)
 		goto exit;
 
-	if (!filter_rule_validate (rule, GTK_WINDOW (dialog)))
+	if (!e_filter_rule_validate (rule, GTK_WINDOW (dialog)))
 		goto run;
 
 	e_shell_content_set_search_rule (shell_content, rule);
@@ -1392,9 +1392,9 @@ run:
 	e_shell_view_execute_search (shell_view);
 
 	if (response == GTK_RESPONSE_APPLY) {
-		if (!rule_context_find_rule (context, rule->name, rule->source))
-			rule_context_add_rule (context, rule);
-		rule_context_save (context, user_filename);
+		if (!e_rule_context_find_rule (context, rule->name, rule->source))
+			e_rule_context_add_rule (context, rule);
+		e_rule_context_save (context, user_filename);
 		goto run;
 	}
 
@@ -1406,8 +1406,8 @@ exit:
 void
 e_shell_content_run_edit_searches_dialog (EShellContent *shell_content)
 {
-	RuleContext *context;
-	RuleEditor *editor;
+	ERuleContext *context;
+	ERuleEditor *editor;
 	const gchar *user_filename;
 
 	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
@@ -1415,12 +1415,12 @@ e_shell_content_run_edit_searches_dialog (EShellContent *shell_content)
 	context = e_shell_content_get_search_context (shell_content);
 	user_filename = shell_content->priv->user_filename;
 
-	editor = rule_editor_new (
-		context, FILTER_SOURCE_INCOMING, _("Searches"));
+	editor = e_rule_editor_new (
+		context, E_FILTER_SOURCE_INCOMING, _("Searches"));
 	gtk_window_set_title (GTK_WINDOW (editor), _("Searches"));
 
 	if (gtk_dialog_run (GTK_DIALOG (editor)) == GTK_RESPONSE_OK)
-		rule_context_save (context, user_filename);
+		e_rule_context_save (context, user_filename);
 
 	gtk_widget_destroy (GTK_WIDGET (editor));
 }
@@ -1432,8 +1432,8 @@ e_shell_content_run_save_search_dialog (EShellContent *shell_content)
 	EShellWindow *shell_window;
 	GtkWidget *dialog;
 	GtkWidget *widget;
-	FilterRule *rule;
-	RuleContext *context;
+	EFilterRule *rule;
+	ERuleContext *context;
 	const gchar *search_text;
 	const gchar *user_filename;
 	gchar *search_name;
@@ -1446,20 +1446,20 @@ e_shell_content_run_save_search_dialog (EShellContent *shell_content)
 	user_filename = shell_content->priv->user_filename;
 
 	rule = e_shell_content_get_search_rule (shell_content);
-	g_return_if_fail (IS_FILTER_RULE (rule));
-	rule = filter_rule_clone (rule);
+	g_return_if_fail (E_IS_FILTER_RULE (rule));
+	rule = e_filter_rule_clone (rule);
 
 	search_text = e_shell_content_get_search_text (shell_content);
 	if (search_text == NULL || *search_text == '\0')
 		search_text = "''";
 
 	search_name = g_strdup_printf ("%s %s", rule->name, search_text);
-	filter_rule_set_name (rule, search_name);
+	e_filter_rule_set_name (rule, search_name);
 	g_free (search_name);
 
 	context = e_shell_content_get_search_context (shell_content);
-	widget = filter_rule_get_widget (rule, context);
-	filter_rule_set_source (rule, FILTER_SOURCE_INCOMING);
+	widget = e_filter_rule_get_widget (rule, context);
+	e_filter_rule_set_source (rule, E_FILTER_SOURCE_INCOMING);
 
 	dialog = gtk_dialog_new_with_buttons (
 		_("Save Search"), GTK_WINDOW (shell_window),
@@ -1486,11 +1486,11 @@ run:
 	if (response != GTK_RESPONSE_OK)
 		goto exit;
 
-	if (!filter_rule_validate (rule, GTK_WINDOW (dialog)))
+	if (!e_filter_rule_validate (rule, GTK_WINDOW (dialog)))
 		goto run;
 
-	rule_context_add_rule (context, rule);
-	rule_context_save (context, user_filename);
+	e_rule_context_add_rule (context, rule);
+	e_rule_context_save (context, user_filename);
 
 exit:
 	g_object_unref (rule);
diff --git a/shell/e-shell-content.h b/shell/e-shell-content.h
index 8e754ff..9449040 100644
--- a/shell/e-shell-content.h
+++ b/shell/e-shell-content.h
@@ -29,8 +29,8 @@
 #define E_SHELL_CONTENT_H
 
 #include <shell/e-shell-common.h>
-#include <filter/filter-rule.h>
-#include <filter/rule-context.h>
+#include <filter/e-filter-rule.h>
+#include <filter/e-rule-context.h>
 
 /* Standard GObject macros */
 #define E_TYPE_SHELL_CONTENT \
@@ -75,7 +75,7 @@ struct _EShellContentClass {
 	GtkBinClass parent_class;
 
 	/* Factory Methods */
-	RuleContext *	(*new_search_context)	(void);
+	ERuleContext *	(*new_search_context)	(void);
 
 	guint32		(*check_state)		(EShellContent *shell_content);
 };
@@ -104,14 +104,14 @@ void		e_shell_content_add_filter_separator_before
 void		e_shell_content_add_filter_separator_after
 						(EShellContent *shell_content,
 						 gint action_value);
-RuleContext *	e_shell_content_get_search_context
+ERuleContext *	e_shell_content_get_search_context
 						(EShellContent *shell_content);
 const gchar *	e_shell_content_get_search_hint	(EShellContent *shell_content);
 void		e_shell_content_set_search_hint	(EShellContent *shell_content,
 						 const gchar *search_hint);
-FilterRule *	e_shell_content_get_search_rule	(EShellContent *shell_content);
+EFilterRule *	e_shell_content_get_search_rule	(EShellContent *shell_content);
 void		e_shell_content_set_search_rule (EShellContent *shell_content,
-						 FilterRule *search_rule);
+						 EFilterRule *search_rule);
 const gchar *	e_shell_content_get_search_text	(EShellContent *shell_content);
 void		e_shell_content_set_search_text	(EShellContent *shell_content,
 						 const gchar *search_text);
diff --git a/shell/e-shell-window-actions.c b/shell/e-shell-window-actions.c
index 3eb25e2..46cb321 100644
--- a/shell/e-shell-window-actions.c
+++ b/shell/e-shell-window-actions.c
@@ -702,7 +702,7 @@ static void
 action_custom_rule_cb (GtkAction *action,
                        EShellWindow *shell_window)
 {
-	FilterRule *rule;
+	EFilterRule *rule;
 	EShellView *shell_view;
 	EShellContent *shell_content;
 	const gchar *view_name;
@@ -715,7 +715,7 @@ action_custom_rule_cb (GtkAction *action,
 	shell_content = e_shell_view_get_shell_content (shell_view);
 
 	rule = g_object_get_data (G_OBJECT (action), "rule");
-	g_return_if_fail (IS_FILTER_RULE (rule));
+	g_return_if_fail (E_IS_FILTER_RULE (rule));
 
 	e_shell_content_set_search_rule (shell_content, rule);
 
@@ -2231,8 +2231,8 @@ e_shell_window_update_search_menu (EShellWindow *shell_window)
 	EShellContent *shell_content;
 	EShellView *shell_view;
 	EShellViewClass *shell_view_class;
-	RuleContext *context;
-	FilterRule *rule;
+	ERuleContext *context;
+	EFilterRule *rule;
 	GtkUIManager *ui_manager;
 	GtkActionGroup *action_group;
 	const gchar *source;
@@ -2247,7 +2247,7 @@ e_shell_window_update_search_menu (EShellWindow *shell_window)
 	shell_content = e_shell_view_get_shell_content (shell_view);
 	context = e_shell_content_get_search_context (shell_content);
 	shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
-	source = FILTER_SOURCE_INCOMING;
+	source = E_FILTER_SOURCE_INCOMING;
 
 	/* Update sensitivity of search actions. */
 
@@ -2267,7 +2267,7 @@ e_shell_window_update_search_menu (EShellWindow *shell_window)
 	gtk_ui_manager_remove_ui (ui_manager, merge_id);
 	e_action_group_remove_all_actions (action_group);
 
-	rule = rule_context_next_rule (context, NULL, source);
+	rule = e_rule_context_next_rule (context, NULL, source);
 	while (rule != NULL) {
 		GtkAction *action;
 		gchar *action_name;
@@ -2304,6 +2304,6 @@ e_shell_window_update_search_menu (EShellWindow *shell_window)
 		g_free (action_name);
 		g_free (action_label);
 
-		rule = rule_context_next_rule (context, rule, source);
+		rule = e_rule_context_next_rule (context, rule, source);
 	}
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]