? filter/diff
Index: mail/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/mail/ChangeLog,v
retrieving revision 1.2252
diff -u -3 -r1.2252 ChangeLog
--- mail/ChangeLog	9 Jul 2002 20:27:15 -0000	1.2252
+++ mail/ChangeLog	10 Jul 2002 09:27:17 -0000
@@ -1,3 +1,33 @@
+2002-07-10  Not Zed  <NotZed@Ximian.com>
+
+	** fixes for #10781
+
+	* mail-callbacks.c (filter_edit): Add back a cancel button.  We
+	dont need to do anything special to 'undo' here, as the rules are
+	loaded every time they're used.
+
+	* mail-vfolder.c (vfolder_editor_clicked): If ok wans't clicked,
+	revert the ruleset.
+	(vfolder_editor_destroy): Fake a button of -1 if we get destroyed
+	with no click.
+	(context_rule_removed): Unref the folder after we delete it.  If
+	we're the last ref to the folder, unrefing it means it no longer
+	exist,s which means no delte processing occurs ...
+
+2002-07-04  Not Zed  <NotZed@Ximian.com>
+
+	* mail-accounts.c (news_add_destroyed): Pass teh autoconnect flag,
+	whcih shoudlnt' exist anyeway.
+
+2002-07-03  Not Zed  <NotZed@Ximian.com>
+
+	* component-factory.c (populate_folder_context_menu): If this is a
+	file url, look up its component, if we have it, then use the
+	mail-callback reconfigure call.
+
+	* folder-browser-factory.c (folder_browser_factory_get_browser):
+	Util to get the folder browser from a uri.
+
 2002-07-09  Ettore Perazzoli  <ettore@ximian.com>
 
 	* subscribe-dialog.c (recursive_add_folder): Pass NULL for
@@ -96,6 +126,7 @@
 	(add_storage): Only call mail_note_store() if we plan on
 	auto-connecting.
 
+>>>>>>> 1.2246
 2002-07-02  Jeffrey Stedfast  <fejj@ximian.com>
 
 	* folder-browser.c (on_right_click): Increase the size of the
@@ -145,6 +176,7 @@
 	* mail-format.c (handle_multipart_related): Make sure that cid is
 	non-NULL.
 
+>>>>>>> 1.2245
 2002-07-01  Not Zed  <NotZed@Ximian.com>
 
 	* mail-folder-cache.c (folder_deleted): Removed.  The
Index: mail/mail-vfolder.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-vfolder.c,v
retrieving revision 1.71
diff -u -3 -r1.71 mail-vfolder.c
--- mail/mail-vfolder.c	3 Jul 2002 20:40:12 -0000	1.71
+++ mail/mail-vfolder.c	10 Jul 2002 09:27:18 -0000
@@ -42,7 +42,7 @@
 #include "filter/vfolder-context.h"
 #include "filter/vfolder-editor.h"
 
-#define d(x) 
+#define d(x) /*(printf("%s(%d):%s: ",  __FILE__, __LINE__, __PRETTY_FUNCTION__), (x))*/
 
 static VfolderContext *context;	/* context remains open all time */
 static CamelStore *vfolder_store; /* the 1 static vfolder store */
@@ -340,7 +340,7 @@
 		int found = FALSE;
 		
 		if (!rule->name) {
-			d(printf ("invalid rule (%p): rule->name is set to NULL\n"));
+			d(printf("invalid rule (%p): rule->name is set to NULL\n", rule));
 			continue;
 		}
 		
@@ -592,7 +592,7 @@
 static void context_rule_removed(RuleContext *ctx, FilterRule *rule)
 {
 	char *key, *path;
-	CamelFolder *folder;
+	CamelFolder *folder = NULL;
 
 	d(printf("rule removed; %s\n", rule->name));
 
@@ -606,12 +606,13 @@
 	if (g_hash_table_lookup_extended(vfolder_hash, rule->name, (void **)&key, (void **)&folder)) {
 		g_hash_table_remove(vfolder_hash, key);
 		g_free(key);
-		UNLOCK();
-		camel_object_unref((CamelObject *)folder);
-	} else
-		UNLOCK();
+	}
+	UNLOCK();
 
 	camel_store_delete_folder(vfolder_store, rule->name, NULL);
+	/* this must be unref'd after its deleted */
+	if (folder)
+		camel_object_unref(folder);
 }
 
 static void
@@ -743,7 +744,7 @@
 		if (rule->name)
 			context_rule_added((RuleContext *)context, rule);
 		else
-			d(printf ("invalid rule (%p) encountered: rule->name is NULL\n"));
+			d(printf("invalid rule (%p) encountered: rule->name is NULL\n", rule));
 	}
 
 	g_free(storeuri);
@@ -752,24 +753,29 @@
 static GtkWidget *vfolder_editor = NULL;
 
 static void
-vfolder_editor_destroy (GtkWidget *widget, gpointer user_data)
+vfolder_editor_clicked (GtkWidget *dialog, int button, void *data)
 {
+	char *user;
+
+	user = alloca(strlen(evolution_dir)+16);
+	sprintf(user, "%s/vfolders.xml", evolution_dir);
+
+	if (button == 0)
+		rule_context_save ((RuleContext *)context, user);
+	else
+		rule_context_revert ((RuleContext *)context, user);
+
+	if (button != -1)
+		gnome_dialog_close (GNOME_DIALOG (dialog));
+
 	vfolder_editor = NULL;
 }
 
 static void
-vfolder_editor_clicked (GtkWidget *dialog, int button, void *data)
+vfolder_editor_destroy (GtkWidget *widget, gpointer user_data)
 {
-	if (button == 0) {
-		char *user;
-
-		user = g_strdup_printf ("%s/vfolders.xml", evolution_dir);
-		rule_context_save ((RuleContext *)context, user);
-		g_free (user);
-	}
-	if (button != -1) {
-		gnome_dialog_close (GNOME_DIALOG (dialog));
-	}
+	if (vfolder_editor)
+		vfolder_editor_clicked(vfolder_editor, -1, user_data);
 }
 
 void
@@ -784,6 +790,8 @@
 	gtk_window_set_title (GTK_WINDOW (vfolder_editor), _("vFolders"));
 	gtk_signal_connect (GTK_OBJECT (vfolder_editor), "clicked", vfolder_editor_clicked, NULL);
 	gtk_signal_connect (GTK_OBJECT (vfolder_editor), "destroy", vfolder_editor_destroy, NULL);
+	gnome_dialog_append_buttons (GNOME_DIALOG (vfolder_editor), GNOME_STOCK_BUTTON_CANCEL, NULL);
+
 	gtk_widget_show (vfolder_editor);
 }
 
Index: mail/mail-callbacks.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-callbacks.c,v
retrieving revision 1.362
diff -u -3 -r1.362 mail-callbacks.c
--- mail/mail-callbacks.c	9 Jul 2002 20:25:30 -0000	1.362
+++ mail/mail-callbacks.c	10 Jul 2002 09:27:24 -0000
@@ -2739,6 +2739,7 @@
 	gtk_object_set_data_full (GTK_OBJECT (filter_editor), "context", fc, (GtkDestroyNotify)gtk_object_unref);
 	gtk_signal_connect (GTK_OBJECT (filter_editor), "clicked", filter_editor_clicked, fb);
 	gtk_signal_connect (GTK_OBJECT (filter_editor), "destroy", filter_editor_destroy, NULL);
+	gnome_dialog_append_buttons(GNOME_DIALOG(filter_editor), GNOME_STOCK_BUTTON_CANCEL, NULL);
 	gtk_widget_show (GTK_WIDGET (filter_editor));
 }
 
Index: filter/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/filter/ChangeLog,v
retrieving revision 1.292
diff -u -3 -r1.292 ChangeLog
--- filter/ChangeLog	8 Jul 2002 20:30:39 -0000	1.292
+++ filter/ChangeLog	10 Jul 2002 09:27:31 -0000
@@ -1,3 +1,28 @@
+2002-07-10  Not Zed  <NotZed@Ximian.com>
+
+	** fixes for #10781
+	
+	* filter-int.c (xml_encode): 
+	(xml_decode): Handle encoding/decoding with a type name, in a
+	manner compatible with the score/label elemtns.
+	(filter_int_new_type): New constructor to create a generic 'int'
+	type.
+
+	* filter-score.c: Removed.  Now relies on using a filter-int with
+	appropriate settings.
+
+	* filter-label.[ch]: Now inherits from filter-int.
+
+	* rule-context.c (rule_context_revert): New method to revert a
+	filter context back to a user-file's definition.
+	(revert): implementation.
+
+	* filter-rule.h: Added new virtual method _eq and wrapper, and
+	fixed all subclasses to implement it.
+
+	* filter-element.h: Added new virtual method _eq and wrapper.
+	Fixed all subclasses to implement it.
+
 2002-07-08  Jeffrey Stedfast  <fejj@ximian.com>
 
 	* filtertypes.xml: Make the sound type for (play-sound ) a "file"
Index: filter/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution/filter/Makefile.am,v
retrieving revision 1.39
diff -u -3 -r1.39 Makefile.am
--- filter/Makefile.am	16 May 2002 20:01:32 -0000	1.39
+++ filter/Makefile.am	10 Jul 2002 09:27:31 -0000
@@ -48,8 +48,6 @@
 	filter-part.h				\
 	filter-rule.c				\
 	filter-rule.h				\
-	filter-score.c				\
-	filter-score.h				\
 	filter-source.h				\
 	filter-source.c				\
 	rule-context.c				\
Index: filter/filter-colour.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-colour.c,v
retrieving revision 1.6
diff -u -3 -r1.6 filter-colour.c
--- filter/filter-colour.c	27 Oct 2001 17:59:02 -0000	1.6
+++ filter/filter-colour.c	10 Jul 2002 09:27:31 -0000
@@ -30,6 +30,7 @@
 
 #define d(x)
 
+static int colour_eq(FilterElement *fe, FilterElement *cm);
 static void xml_create(FilterElement *fe, xmlNodePtr node);
 static xmlNodePtr xml_encode(FilterElement *fe);
 static int xml_decode(FilterElement *fe, xmlNodePtr node);
@@ -88,6 +89,7 @@
 	object_class->finalize = filter_colour_finalise;
 
 	/* override methods */
+	filter_element->eq = colour_eq;
 	filter_element->xml_create = xml_create;
 	filter_element->xml_encode = xml_encode;
 	filter_element->xml_decode = xml_decode;
@@ -128,6 +130,18 @@
 {
 	FilterColour *o = (FilterColour *)gtk_type_new(filter_colour_get_type ());
 	return o;
+}
+
+static int
+colour_eq(FilterElement *fe, FilterElement *cm)
+{
+	FilterColour *fc = (FilterColour *)fe, *cc = (FilterColour *)cm;
+
+        return ((FilterElementClass *)(parent_class))->eq(fe, cm)
+		&& fc->r == cc->r
+		&& fc->g == cc->g
+		&& fc->b == cc->b
+		&& fc->a == cc->a;
 }
 
 static void xml_create(FilterElement *fe, xmlNodePtr node)
Index: filter/filter-datespec.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-datespec.c,v
retrieving revision 1.17
diff -u -3 -r1.17 filter-datespec.c
--- filter/filter-datespec.c	26 Feb 2002 02:27:22 -0000	1.17
+++ filter/filter-datespec.c	10 Jul 2002 09:27:32 -0000
@@ -46,6 +46,7 @@
 #define d(x)
 
 static gboolean validate (FilterElement *fe);
+static int date_eq(FilterElement *fe, FilterElement *cm);
 static void xml_create (FilterElement *fe, xmlNodePtr node);
 static xmlNodePtr xml_encode (FilterElement *fe);
 static int xml_decode (FilterElement *fe, xmlNodePtr node);
@@ -138,6 +139,7 @@
 	
 	/* override methods */
 	filter_element->validate = validate;
+	filter_element->eq = date_eq;
 	filter_element->xml_create = xml_create;
 	filter_element->xml_encode = xml_encode;
 	filter_element->xml_decode = xml_decode;
@@ -199,6 +201,16 @@
 	}
 	
 	return valid;
+}
+
+static int
+date_eq(FilterElement *fe, FilterElement *cm)
+{
+	FilterDatespec *fd = (FilterDatespec *)fe, *cd = (FilterDatespec *)cm;
+
+        return ((FilterElementClass *)(parent_class))->eq(fe, cm)
+		&& (fd->type == cd->type)
+		&& (fd->value == cd->value);
 }
 
 static void
Index: filter/filter-element.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-element.c,v
retrieving revision 1.25
diff -u -3 -r1.25 filter-element.c
--- filter/filter-element.c	8 Jul 2002 20:30:39 -0000	1.25
+++ filter/filter-element.c	10 Jul 2002 09:27:33 -0000
@@ -41,6 +41,7 @@
 
 
 static gboolean validate (FilterElement *fe);
+static int element_eq(FilterElement *fe, FilterElement *cm);
 static void xml_create(FilterElement *fe, xmlNodePtr node);
 static FilterElement *clone(FilterElement *fe);
 
@@ -94,6 +95,7 @@
 
 	/* override methods */
 	class->validate = validate;
+	class->eq = element_eq;
 	class->xml_create = xml_create;
 	class->clone = clone;
 
@@ -138,6 +140,13 @@
 	return ((FilterElementClass *)((GtkObject *)fe)->klass)->validate (fe);
 }
 
+int
+filter_element_eq(FilterElement *fe, FilterElement *cm)
+{
+	return ((GtkObject *)fe)->klass == ((GtkObject *)cm)->klass
+		&& ((FilterElementClass *)((GtkObject *)fe)->klass)->eq(fe, cm);
+}
+
 /**
  * filter_element_xml_create:
  * @fe: filter element
@@ -268,7 +277,7 @@
 	} else if (!strcmp (type, "datespec")) {
 		return (FilterElement *)filter_datespec_new ();
 	} else if (!strcmp (type, "score")) {
-		return (FilterElement *)filter_score_new ();
+		return (FilterElement *)filter_int_new_type("score", -3, 3);
 	} else if (!strcmp (type, "integer")) {
 		return (FilterElement *)filter_int_new ();
 	} else if (!strcmp (type, "regex")) {
@@ -298,6 +307,13 @@
 validate (FilterElement *fe)
 {
 	return TRUE;
+}
+
+static int
+element_eq(FilterElement *fe, FilterElement *cm)
+{
+	return ((fe->name && cm->name && strcmp(fe->name, cm->name) == 0)
+		|| (fe->name == NULL && cm->name == NULL));
 }
 
 static void
Index: filter/filter-element.h
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-element.h,v
retrieving revision 1.9
diff -u -3 -r1.9 filter-element.h
--- filter/filter-element.h	26 Feb 2002 02:27:22 -0000	1.9
+++ filter/filter-element.h	10 Jul 2002 09:27:33 -0000
@@ -48,7 +48,8 @@
 
 	/* virtual methods */
 	gboolean (*validate)(FilterElement *fe);
-	
+	int (*eq)(FilterElement *fe, FilterElement *cm);
+
 	void (*xml_create)(FilterElement *, xmlNodePtr);
 	xmlNodePtr (*xml_encode)(FilterElement *);
 	int (*xml_decode)(FilterElement *, xmlNodePtr);
@@ -71,6 +72,7 @@
 
 /* methods */
 gboolean        filter_element_validate         (FilterElement *fe);
+int		filter_element_eq		(FilterElement *fe, FilterElement *cm);
 
 void		filter_element_xml_create	(FilterElement *fe, xmlNodePtr node);
 
Index: filter/filter-file.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-file.c,v
retrieving revision 1.5
diff -u -3 -r1.5 filter-file.c
--- filter/filter-file.c	8 Jul 2002 20:30:39 -0000	1.5
+++ filter/filter-file.c	10 Jul 2002 09:27:34 -0000
@@ -44,6 +44,7 @@
 #define d(x) 
 
 static gboolean validate (FilterElement *fe);
+static int file_eq(FilterElement *fe, FilterElement *cm);
 static void xml_create(FilterElement *fe, xmlNodePtr node);
 static xmlNodePtr xml_encode(FilterElement *fe);
 static int xml_decode(FilterElement *fe, xmlNodePtr node);
@@ -102,6 +103,7 @@
 	
 	/* override methods */
 	filter_element->validate = validate;
+	filter_element->eq = file_eq;
 	filter_element->xml_create = xml_create;
 	filter_element->xml_encode = xml_encode;
 	filter_element->xml_decode = xml_decode;
@@ -195,6 +197,18 @@
 	}
 	
 	return TRUE;
+}
+
+static int
+file_eq(FilterElement *fe, FilterElement *cm)
+{
+	FilterFile *ff = (FilterFile *)fe, *cf = (FilterFile *)cm;
+
+        return ((FilterElementClass *)(parent_class))->eq(fe, cm)
+		&& ((ff->path && cf->path && strcmp(ff->path, cf->path) == 0)
+		    || (ff->path == NULL && cf->path == NULL))
+		&& ((ff->type && cf->type && strcmp(ff->type, cf->type) == 0)
+		    || (ff->type == NULL && cf->type == NULL));
 }
 
 static void
Index: filter/filter-filter.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-filter.c,v
retrieving revision 1.20
diff -u -3 -r1.20 filter-filter.c
--- filter/filter-filter.c	26 Feb 2002 02:27:22 -0000	1.20
+++ filter/filter-filter.c	10 Jul 2002 09:27:34 -0000
@@ -40,6 +40,7 @@
 #define d(x)
 
 static int validate(FilterRule *);
+static int filter_eq(FilterRule *fr, FilterRule *cm);
 static xmlNodePtr xml_encode (FilterRule *);
 static int xml_decode (FilterRule *, xmlNodePtr, struct _RuleContext *f);
 static void rule_copy (FilterRule *dest, FilterRule *src);
@@ -98,6 +99,7 @@
 	
 	/* override methods */
 	filter_rule->validate = validate;
+	filter_rule->eq = filter_eq;
 	filter_rule->xml_encode = xml_encode;
 	filter_rule->xml_decode = xml_decode;
 	/*filter_rule->build_code = build_code;*/
@@ -204,6 +206,29 @@
 	}
 
 	return valid;
+}
+
+static int
+list_eq(GList *al, GList *bl)
+{
+	int truth = TRUE;
+
+	while (truth && al && bl) {
+		FilterPart *a = al->data, *b = bl->data;
+
+		truth = filter_part_eq(a, b);
+		al = al->next;
+		bl = bl->next;
+	}
+
+	return truth && al == NULL && bl == NULL;
+}
+
+static int
+filter_eq(FilterRule *fr, FilterRule *cm)
+{
+        return ((FilterRuleClass *)(parent_class))->eq(fr, cm)
+		&& list_eq(((FilterFilter *)fr)->actions, ((FilterFilter *)cm)->actions);
 }
 
 static xmlNodePtr
Index: filter/filter-folder.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-folder.c,v
retrieving revision 1.24
diff -u -3 -r1.24 filter-folder.c
--- filter/filter-folder.c	4 Apr 2002 20:03:02 -0000	1.24
+++ filter/filter-folder.c	10 Jul 2002 09:27:34 -0000
@@ -34,6 +34,7 @@
 #define d(x)
 
 static gboolean validate (FilterElement *fe);
+static int folder_eq(FilterElement *fe, FilterElement *cm);
 static void xml_create(FilterElement *fe, xmlNodePtr node);
 static xmlNodePtr xml_encode(FilterElement *fe);
 static int xml_decode(FilterElement *fe, xmlNodePtr node);
@@ -89,6 +90,7 @@
 
 	/* override methods */
 	filter_element->validate = validate;
+	filter_element->eq = folder_eq;
 	filter_element->xml_create = xml_create;
 	filter_element->xml_encode = xml_encode;
 	filter_element->xml_decode = xml_decode;
@@ -151,6 +153,13 @@
 		
 		return FALSE;
 	}
+}
+
+static int
+folder_eq(FilterElement *fe, FilterElement *cm)
+{
+        return ((FilterElementClass *)(parent_class))->eq(fe, cm)
+		&& strcmp(((FilterFolder *)fe)->uri, ((FilterFolder *)cm)->uri) == 0;
 }
 
 static void
Index: filter/filter-input.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-input.c,v
retrieving revision 1.19
diff -u -3 -r1.19 filter-input.c
--- filter/filter-input.c	10 Apr 2002 10:27:39 -0000	1.19
+++ filter/filter-input.c	10 Jul 2002 09:27:35 -0000
@@ -40,6 +40,7 @@
 #define d(x) 
 
 static gboolean validate (FilterElement *fe);
+static int input_eq(FilterElement *fe, FilterElement *cm);
 static void xml_create(FilterElement *fe, xmlNodePtr node);
 static xmlNodePtr xml_encode(FilterElement *fe);
 static int xml_decode(FilterElement *fe, xmlNodePtr node);
@@ -99,6 +100,7 @@
 
 	/* override methods */
 	filter_element->validate = validate;
+	filter_element->eq = input_eq;
 	filter_element->xml_create = xml_create;
 	filter_element->xml_encode = xml_encode;
 	filter_element->xml_decode = xml_decode;
@@ -211,6 +213,30 @@
 	}
 	
 	return valid;
+}
+
+static int
+list_eq(GList *al, GList *bl)
+{
+	int truth = TRUE;
+
+	while (truth && al && bl) {
+		truth = strcmp((char *)al->data, (char *)bl->data) == 0;
+		al = al->next;
+		bl = bl->next;
+	}
+
+	return truth && al == NULL && bl == NULL;
+}
+
+static int
+input_eq(FilterElement *fe, FilterElement *cm)
+{
+	FilterInput *fi = (FilterInput *)fe, *ci = (FilterInput *)cm;
+
+	return ((FilterElementClass *)(parent_class))->eq(fe, cm)
+		&& strcmp(fi->type, ci->type) == 0
+		&& list_eq(fi->values, ci->values);
 }
 
 static void
Index: filter/filter-int.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-int.c,v
retrieving revision 1.3
diff -u -3 -r1.3 filter-int.c
--- filter/filter-int.c	16 May 2002 20:01:32 -0000	1.3
+++ filter/filter-int.c	10 Jul 2002 09:27:35 -0000
@@ -32,6 +32,7 @@
 
 #define d(x)
 
+static int int_eq(FilterElement *fe, FilterElement *cm);
 static void xml_create (FilterElement *fe, xmlNodePtr node);
 static xmlNodePtr xml_encode (FilterElement *fe);
 static int xml_decode (FilterElement *fe, xmlNodePtr node);
@@ -90,6 +91,7 @@
 	object_class->finalize = filter_int_finalise;
 	
 	/* override methods */
+	filter_element->eq = int_eq;
 	filter_element->xml_create = xml_create;
 	filter_element->xml_encode = xml_encode;
 	filter_element->xml_decode = xml_decode;
@@ -105,6 +107,8 @@
 static void
 filter_int_init (FilterInt *o)
 {
+	o->min = 0;
+	o->max = G_MAXINT;
 	o->priv = g_malloc0 (sizeof (*o->priv));
 }
 
@@ -112,8 +116,8 @@
 filter_int_finalise(GtkObject *obj)
 {
 	FilterInt *o = (FilterInt *)obj;
-	
-	o = o;
+
+	g_free(o->type);
 	
         ((GtkObjectClass *)(parent_class))->finalize(obj);
 }
@@ -132,6 +136,29 @@
 	return o;
 }
 
+FilterInt *
+filter_int_new_type(const char *type, int min, int max)
+{
+	FilterInt *o = (FilterInt *)gtk_type_new(filter_int_get_type ());
+	o->type = g_strdup(type);
+	o->min = min;
+	o->max = max;
+	return o;
+}
+
+void
+filter_int_set_value(FilterInt *fi, int val)
+{
+	fi->val = val;
+}
+
+static int
+int_eq(FilterElement *fe, FilterElement *cm)
+{
+        return ((FilterElementClass *)(parent_class))->eq(fe, cm)
+		&& ((FilterInt *)fe)->val == ((FilterInt *)cm)->val;
+}
+
 static void
 xml_create (FilterElement *fe, xmlNodePtr node)
 {
@@ -144,17 +171,19 @@
 {
 	xmlNodePtr value;
 	FilterInt *fs = (FilterInt *)fe;
-	char *intval;
+	char intval[32];
+	const char *type;
 	
-	d(printf("Encoding integer as xml\n"));
+	type = fs->type?fs->type:"integer";
+
+	d(printf("Encoding %s as xml\n", type));
 	
 	value = xmlNewNode (NULL, "value");
 	xmlSetProp (value, "name", fe->name);
-	xmlSetProp (value, "type", "integer");
+	xmlSetProp (value, "type", type);
 	
-	intval = g_strdup_printf ("%d", fs->val);
-	xmlSetProp (value, "integer", intval);
-	g_free (intval);
+	sprintf(intval, "%d", fs->val);
+	xmlSetProp (value, type, intval);
 	
 	return value;
 }
@@ -163,7 +192,7 @@
 xml_decode (FilterElement *fe, xmlNodePtr node)
 {
 	FilterInt *fs = (FilterInt *)fe;
-	char *name;
+	char *name, *type;
 	char *intval;
 	
 	d(printf("Decoding integer from xml %p\n", fe));
@@ -172,7 +201,13 @@
 	d(printf ("Name = %s\n", name));
 	xmlFree (fe->name);
 	fe->name = name;
-	intval = xmlGetProp (node, "integer");
+
+	type = xmlGetProp(node, "type");
+	g_free(fs->type);
+	fs->type = g_strdup(type);
+	xmlFree(type);
+
+	intval = xmlGetProp (node, type?type:"integer");
 	if (intval) {
 		fs->val = atoi (intval);
 		xmlFree (intval);
@@ -197,14 +232,12 @@
 	GtkObject *adjustment;
 	FilterInt *fs = (FilterInt *)fe;
 	
-	adjustment = gtk_adjustment_new (0.0, 0.0, (gfloat)G_MAXINT, 
-					 1.0, 1.0, 1.0);
-	spin = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), 5.0, 0);
+	adjustment = gtk_adjustment_new (0.0, (gfloat)fs->min, (gfloat)fs->max, 1.0, 1.0, 1.0);
+	spin = gtk_spin_button_new (GTK_ADJUSTMENT (adjustment), fs->max>fs->min+1000?5.0:1.0, 0);
 	gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spin), TRUE);
 	
-	if (fs->val) {
+	if (fs->val)
 		gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin), (gfloat) fs->val);
-	}
 	
 	gtk_signal_connect (GTK_OBJECT (spin), "changed", spin_changed, fe);
 	
@@ -221,9 +254,6 @@
 format_sexp (FilterElement *fe, GString *out)
 {
 	FilterInt *fs = (FilterInt *)fe;
-	char *str;
-	
-	str = g_strdup_printf ("%d", fs->val);
-	g_string_append (out, str);
-	g_free (str);
+
+	g_string_sprintfa(out, "%d", fs->val);
 }
Index: filter/filter-int.h
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-int.h,v
retrieving revision 1.2
diff -u -3 -r1.2 filter-int.h
--- filter/filter-int.h	27 Oct 2001 17:59:02 -0000	1.2
+++ filter/filter-int.h	10 Jul 2002 09:27:35 -0000
@@ -37,8 +37,11 @@
 struct _FilterInt {
 	FilterElement parent;
 	struct _FilterIntPrivate *priv;
-	
-	gint32 val;
+
+	char *type;
+	int val;
+	int min;
+	int max;
 };
 
 struct _FilterIntClass {
@@ -51,6 +54,8 @@
 
 guint		filter_int_get_type	(void);
 FilterInt	*filter_int_new	(void);
+FilterInt	*filter_int_new_type(const char *type, int min, int max);
+void            filter_int_set_value(FilterInt *fi, int val);
 
 /* methods */
 
Index: filter/filter-label.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-label.c,v
retrieving revision 1.1
diff -u -3 -r1.1 filter-label.c
--- filter/filter-label.c	16 May 2002 20:01:51 -0000	1.1
+++ filter/filter-label.c	10 Jul 2002 09:27:35 -0000
@@ -50,11 +50,7 @@
 
 static gboolean validate (FilterElement *fe);
 static void xml_create (FilterElement *fe, xmlNodePtr node);
-static xmlNodePtr xml_encode (FilterElement *fe);
-static int 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 *fe, GString *out);
 
 static void filter_label_class_init (FilterLabelClass *klass);
 static void filter_label_init (FilterLabel *label);
@@ -86,7 +82,7 @@
 			(GtkArgGetFunc) NULL
 		};
 		
-		type = gtk_type_unique (filter_element_get_type (), &type_info);
+		type = gtk_type_unique (filter_int_get_type (), &type_info);
 	}
 	
 	return type;
@@ -98,18 +94,14 @@
 	GtkObjectClass *object_class = (GtkObjectClass *) klass;
 	FilterElementClass *filter_element = (FilterElementClass *) klass;
 	
-	parent_class = gtk_type_class (filter_element_get_type ());
+	parent_class = gtk_type_class (filter_int_get_type ());
 	
 	object_class->finalize = filter_label_finalise;
 	
 	/* override methods */
 	filter_element->validate = validate;
 	filter_element->xml_create = xml_create;
-	filter_element->xml_encode = xml_encode;
-	filter_element->xml_decode = xml_decode;
 	filter_element->get_widget = get_widget;
-	filter_element->build_code = build_code;
-	filter_element->format_sexp = format_sexp;
 	
 	/* signals */
 	
@@ -141,20 +133,13 @@
 	return (FilterLabel *) gtk_type_new (filter_label_get_type ());
 }
 
-
-void
-filter_label_set_label (FilterLabel *filter, int label)
-{
-	filter->label = label;
-}
-
 static gboolean
 validate (FilterElement *fe)
 {
-	FilterLabel *label = (FilterLabel *) fe;
+	FilterInt *label = (FilterInt *)fe;
 	GtkWidget *dialog;
 	
-	if (label->label < 0 || label->label > 4) {
+	if (label->val < 0 || label->val > 4) {
 		dialog = gnome_ok_dialog (_("You must specify a label name"));
 		
 		gnome_dialog_run_and_close (GNOME_DIALOG (dialog));
@@ -172,65 +157,18 @@
 	
 }
 
-static xmlNodePtr
-xml_encode (FilterElement *fe)
-{
-	FilterLabel *label = (FilterLabel *) fe;
-	xmlNodePtr value;
-	char *encstr;
-	
-	d(printf ("Encoding label as xml\n"));
-	
-	encstr = g_strdup_printf ("%d", label->label);
-	
-	value = xmlNewNode (NULL, "value");
-	xmlSetProp (value, "name", fe->name);
-	xmlSetProp (value, "type", "label");
-	xmlSetProp (value, "label", encstr);
-	g_free (encstr);
-	
-	return value;
-}
-
-static int
-xml_decode (FilterElement *fe, xmlNodePtr node)
-{
-	FilterLabel *label = (FilterLabel *) fe;
-	char *name, *str, *type;
-	
-	type = xmlGetProp (node, "type");
-	if (strcmp (type, "label") != 0) {
-		xmlFree (type);
-		return -1;
-	}
-	
-	xmlFree (type);
-	
-	d(printf("Decoding label from xml %p\n", fe));
-	
-	name = xmlGetProp (node, "name");
-	xmlFree (fe->name);
-	fe->name = name;
-	
-	str = xmlGetProp (node, "label");
-	label->label = atoi (str);
-	xmlFree (str);
-	
-	return 0;
-}
-
 static void
 label_selected (GtkWidget *item, gpointer user_data)
 {
-	FilterLabel *label = user_data;
+	FilterInt *label = user_data;
 	
-	label->label = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (item), "label"));
+	label->val = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (item), "label"));
 }
 
 static GtkWidget *
 get_widget (FilterElement *fe)
 {
-	FilterLabel *label = (FilterLabel *) fe;
+	FilterInt *label = (FilterInt *) fe;
 	GtkWidget *omenu, *menu, *item;
 	Bonobo_ConfigDatabase db;
 	CORBA_Environment ev;
@@ -282,24 +220,7 @@
 	g_free (path);
 	
 	gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu);
-	gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), label->label);
+	gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), label->val);
 	
 	return omenu;
-}
-
-static void
-build_code (FilterElement *fe, GString *out, struct _FilterPart *ff)
-{
-	return;
-}
-
-static void
-format_sexp (FilterElement *fe, GString *out)
-{
-	FilterLabel *label = (FilterLabel *) fe;
-	char *str;
-	
-	str = g_strdup_printf ("%d", label->label);
-	g_string_append (out, str);
-	g_free (str);
 }
Index: filter/filter-label.h
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-label.h,v
retrieving revision 1.1
diff -u -3 -r1.1 filter-label.h
--- filter/filter-label.h	16 May 2002 20:01:51 -0000	1.1
+++ filter/filter-label.h	10 Jul 2002 09:27:35 -0000
@@ -29,7 +29,7 @@
 #pragma }
 #endif /* __cplusplus */
 
-#include "filter-element.h"
+#include "filter-int.h"
 
 #define FILTER_LABEL(obj)         GTK_CHECK_CAST (obj, filter_label_get_type (), FilterLabel)
 #define FILTER_LABEL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_label_get_type (), FilterLabelClass)
@@ -39,13 +39,11 @@
 typedef struct _FilterLabelClass FilterLabelClass;
 
 struct _FilterLabel {
-	FilterElement parent;
-	
-	int label;
+	FilterInt parent;
 };
 
 struct _FilterLabelClass {
-	FilterElementClass parent_class;
+	FilterIntClass parent_class;
 	
 	/* virtual methods */
 	
@@ -55,8 +53,6 @@
 GtkType filter_label_get_type (void);
 
 FilterLabel *filter_label_new (void);
-
-void filter_label_set_label (FilterLabel *filter, int label);
 
 #ifdef __cplusplus
 }
Index: filter/filter-option.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-option.c,v
retrieving revision 1.19
diff -u -3 -r1.19 filter-option.c
--- filter/filter-option.c	27 Oct 2001 17:59:02 -0000	1.19
+++ filter/filter-option.c	10 Jul 2002 09:27:36 -0000
@@ -34,6 +34,7 @@
 
 #define d(x)
 
+static int option_eq(FilterElement *fe, FilterElement *cm);
 static void xml_create(FilterElement *fe, xmlNodePtr node);
 static xmlNodePtr xml_encode(FilterElement *fe);
 static int xml_decode(FilterElement *fe, xmlNodePtr node);
@@ -93,6 +94,7 @@
 	object_class->finalize = filter_option_finalise;
 	
 	/* override methods */
+	filter_element->eq = option_eq;
 	filter_element->xml_create = xml_create;
 	filter_element->xml_encode = xml_encode;
 	filter_element->xml_decode = xml_decode;
@@ -169,6 +171,16 @@
 	g_assert(IS_FILTER_OPTION(option));
 	
 	option->current = find_option (option, name);
+}
+
+static int
+option_eq(FilterElement *fe, FilterElement *cm)
+{
+	FilterOption *fo = (FilterOption *)fe, *co = (FilterOption *)cm;
+
+	return ((FilterElementClass *)(parent_class))->eq(fe, cm)
+		&& ((fo->current && co->current && strcmp(fo->current->value, co->current->value) == 0)
+		    || (fo->current == NULL && co->current == NULL));
 }
 
 static void
Index: filter/filter-part.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-part.c,v
retrieving revision 1.17
diff -u -3 -r1.17 filter-part.c
--- filter/filter-part.c	26 Feb 2002 02:27:22 -0000	1.17
+++ filter/filter-part.c	10 Jul 2002 09:27:37 -0000
@@ -153,10 +153,37 @@
 }
 
 int
+filter_part_eq(FilterPart *fp, FilterPart *fc)
+{
+	int truth;
+	GList *al, *bl;
+
+	truth = ((fp->name && fc->name && strcmp(fp->name, fc->name) == 0)
+		 || (fp->name == NULL && fc->name == NULL))
+		&& ((fp->title && fc->title && strcmp(fp->title, fc->title) == 0)
+		    || (fp->title == NULL && fc->title == NULL))
+		&& ((fp->code && fc->code && strcmp(fp->code, fc->code) == 0)
+		    || (fp->code == NULL && fc->code == NULL));
+
+	al = fp->elements;
+	bl = fc->elements;
+	while (truth && al && bl) {
+		FilterElement *a = al->data, *b = bl->data;
+
+		truth = filter_element_eq(a, b);
+
+		al = al->next;
+		bl = bl->next;
+	}
+
+	return truth && al == NULL && bl == NULL;
+}
+
+int
 filter_part_xml_create (FilterPart *ff, xmlNodePtr node)
 {
 	xmlNodePtr n;
-	char *type, *str, *decstr;
+	char *type, *str;
 	FilterElement *el;
 	
 	str = xmlGetProp(node, "name");
Index: filter/filter-part.h
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-part.h,v
retrieving revision 1.6
diff -u -3 -r1.6 filter-part.h
--- filter/filter-part.h	26 Feb 2002 02:27:22 -0000	1.6
+++ filter/filter-part.h	10 Jul 2002 09:27:37 -0000
@@ -54,6 +54,7 @@
 
 /* methods */
 gboolean        filter_part_validate    (FilterPart *fp);
+int		filter_part_eq		(FilterPart *fp, FilterPart *fc);
 
 int		filter_part_xml_create	(FilterPart *ff, xmlNodePtr node);
 
Index: filter/filter-rule.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-rule.c,v
retrieving revision 1.45
diff -u -3 -r1.45 filter-rule.c
--- filter/filter-rule.c	24 May 2002 18:40:49 -0000	1.45
+++ filter/filter-rule.c	10 Jul 2002 09:27:38 -0000
@@ -41,6 +41,7 @@
 #define d(x)
 
 static int validate(FilterRule *);
+static int rule_eq(FilterRule *fr, FilterRule *cm);
 static xmlNodePtr xml_encode (FilterRule *);
 static int xml_decode (FilterRule *, xmlNodePtr, RuleContext *);
 static void build_code (FilterRule *, GString * out);
@@ -100,6 +101,7 @@
 	
 	/* override methods */
 	class->validate = validate;
+	class->eq = rule_eq;
 	class->xml_encode = xml_encode;
 	class->xml_decode = xml_decode;
 	class->build_code = build_code;
@@ -229,6 +231,43 @@
 	}
 	
 	return valid;
+}
+
+int
+filter_rule_eq(FilterRule *fr, FilterRule *cm)
+{
+	g_assert(IS_FILTER_RULE(fr));
+	g_assert(IS_FILTER_RULE(cm));
+
+	return ((GtkObject *)fr)->klass == ((GtkObject *)cm)->klass
+		&& ((FilterRuleClass *) ((GtkObject *) fr)->klass)->eq(fr, cm);
+}
+
+static int
+list_eq(GList *al, GList *bl)
+{
+	int truth = TRUE;
+
+	while (truth && al && bl) {
+		FilterPart *a = al->data, *b = bl->data;
+
+		truth = filter_part_eq(a, b);
+		al = al->next;
+		bl = bl->next;
+	}
+
+	return truth && al == NULL && bl == NULL;
+}
+
+static int
+rule_eq(FilterRule *fr, FilterRule *cm)
+{
+	return fr->grouping == cm->grouping
+		&& ( (fr->name && cm->name && strcmp(fr->name, cm->name) == 0)
+		     || (fr->name == NULL && cm->name == NULL))
+		&& ( (fr->source && cm->source && strcmp(fr->source, cm->source) == 0)
+		     || (fr->source == NULL && cm->source == NULL) )
+		&& list_eq(fr->parts, cm->parts);
 }
 
 xmlNodePtr
Index: filter/filter-rule.h
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-rule.h,v
retrieving revision 1.12
diff -u -3 -r1.12 filter-rule.h
--- filter/filter-rule.h	27 Oct 2001 17:59:02 -0000	1.12
+++ filter/filter-rule.h	10 Jul 2002 09:27:38 -0000
@@ -60,6 +60,7 @@
 	
 	/* virtual methods */
 	int (*validate)(FilterRule *);
+	int (*eq)(FilterRule *fr, FilterRule *cm);
 
 	xmlNodePtr (*xml_encode)(FilterRule *);
 	int (*xml_decode)(FilterRule *, xmlNodePtr, struct _RuleContext *);
@@ -84,6 +85,7 @@
 void		filter_rule_set_source	(FilterRule *fr, const char *source);
 
 int		filter_rule_validate	(FilterRule *fr);
+int		filter_rule_eq		(FilterRule *fr, FilterRule *cm);
 
 xmlNodePtr	filter_rule_xml_encode	(FilterRule *fr);
 int		filter_rule_xml_decode	(FilterRule *fr, xmlNodePtr node, struct _RuleContext *f);
Index: filter/filter-source.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/filter-source.c,v
retrieving revision 1.11
diff -u -3 -r1.11 filter-source.c
--- filter/filter-source.c	16 May 2002 20:01:32 -0000	1.11
+++ filter/filter-source.c	10 Jul 2002 09:27:39 -0000
@@ -65,6 +65,7 @@
 static void filter_source_init (FilterSource *);
 static void filter_source_finalize (GtkObject *);
 
+static int source_eq(FilterElement *fe, FilterElement *cm);
 static void xml_create(FilterElement *fe, xmlNodePtr node);
 static xmlNodePtr xml_encode(FilterElement *fe);
 static int xml_decode(FilterElement *fe, xmlNodePtr node);
@@ -112,6 +113,7 @@
 	object_class->finalize = filter_source_finalize;
 
 	/* override methods */
+	filter_element->eq = source_eq;
 	filter_element->xml_create = xml_create;
 	filter_element->xml_encode = xml_encode;
 	filter_element->xml_decode = xml_decode;
@@ -162,6 +164,16 @@
 {
 	FilterSource *s = (FilterSource *) gtk_type_new (filter_source_get_type ());
 	return s;
+}
+
+static int
+source_eq(FilterElement *fe, FilterElement *cm)
+{
+	FilterSource *fs = (FilterSource *)fe, *cs = (FilterSource *)cm;
+
+	return ((FilterElementClass *)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
Index: filter/libfilter-i18n.h
===================================================================
RCS file: /cvs/gnome/evolution/filter/libfilter-i18n.h,v
retrieving revision 1.39
diff -u -3 -r1.39 libfilter-i18n.h
--- filter/libfilter-i18n.h	16 May 2002 20:01:32 -0000	1.39
+++ filter/libfilter-i18n.h	10 Jul 2002 09:27:39 -0000
@@ -5,34 +5,18 @@
 char *s = N_("Attachments");
 char *s = N_("Beep");
 char *s = N_("Command");
-char *s = N_("contains");
 char *s = N_("Copy to Folder");
 char *s = N_("Date received");
 char *s = N_("Date sent");
 char *s = N_("Delete");
 char *s = N_("Deleted");
-char *s = N_("does not contain");
-char *s = N_("does not end with");
-char *s = N_("does not exist");
-char *s = N_("does not sound like");
-char *s = N_("does not start with");
 char *s = N_("Do Not Exist");
 char *s = N_("Draft");
-char *s = N_("ends with");
 char *s = N_("Execute Shell Command");
 char *s = N_("Exist");
-char *s = N_("exists");
 char *s = N_("Expression");
 char *s = N_("Follow Up");
 char *s = N_("Important");
-char *s = N_("is");
-char *s = N_("is after");
-char *s = N_("is before");
-char *s = N_("is Flagged");
-char *s = N_("is greater than");
-char *s = N_("is less than");
-char *s = N_("is not");
-char *s = N_("is not Flagged");
 char *s = N_("Label");
 char *s = N_("Mailing list");
 char *s = N_("Message Body");
@@ -47,10 +31,26 @@
 char *s = N_("Sender");
 char *s = N_("Set Status");
 char *s = N_("Size (kB)");
-char *s = N_("sounds like");
 char *s = N_("Source Account");
 char *s = N_("Specific header");
-char *s = N_("starts with");
 char *s = N_("Status");
 char *s = N_("Stop Processing");
 char *s = N_("Subject");
+char *s = N_("contains");
+char *s = N_("does not contain");
+char *s = N_("does not end with");
+char *s = N_("does not exist");
+char *s = N_("does not sound like");
+char *s = N_("does not start with");
+char *s = N_("ends with");
+char *s = N_("exists");
+char *s = N_("is Flagged");
+char *s = N_("is after");
+char *s = N_("is before");
+char *s = N_("is greater than");
+char *s = N_("is less than");
+char *s = N_("is not Flagged");
+char *s = N_("is not");
+char *s = N_("is");
+char *s = N_("sounds like");
+char *s = N_("starts with");
Index: filter/rule-context.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/rule-context.c,v
retrieving revision 1.29
diff -u -3 -r1.29 rule-context.c
--- filter/rule-context.c	8 May 2002 06:36:28 -0000	1.29
+++ filter/rule-context.c	10 Jul 2002 09:27:40 -0000
@@ -38,6 +38,7 @@
 
 static int load(RuleContext * f, const char *system, const char *user);
 static int save(RuleContext * f, const char *user);
+static int revert(RuleContext *f, const char *user);
 static GList *rename_uri(RuleContext *f, const char *olduri, const char *newuri, GCompareFunc cmp);
 static GList *delete_uri(RuleContext *f, const char *uri, GCompareFunc cmp);
 
@@ -97,6 +98,7 @@
 	/* override methods */
 	class->load = load;
 	class->save = save;
+	class->revert = revert;
 	class->rename_uri = rename_uri;
 	class->delete_uri = delete_uri;
 
@@ -416,6 +418,148 @@
 	}
 	xmlFreeDoc (doc);
 	return ret;
+}
+
+/**
+ * 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: 
+ **/
+int
+rule_context_revert(RuleContext *f, const char *user)
+{
+	g_assert(f);
+
+	d(printf("rule_context: restoring %s %s\n", user));
+
+	return ((RuleContextClass *) ((GtkObject *) f)->klass)->revert(f, user);
+}
+
+struct _revert_data {
+	GHashTable *rules;
+	int rank;
+};
+
+static void
+revert_rule_remove(void *key, FilterRule *frule, RuleContext *f)
+{
+	rule_context_remove_rule(f, frule);
+	gtk_object_unref((GtkObject *)frule);
+}
+
+static void
+revert_source_remove(void *key, struct _revert_data *rest_data, RuleContext *f)
+{
+	g_hash_table_foreach(rest_data->rules, (GHFunc)revert_rule_remove, f);
+	g_hash_table_destroy(rest_data->rules);
+	g_free(rest_data);
+}
+
+static guint source_hashf(const char *a)
+{
+	if (a)
+		return g_str_hash(a);
+	return 0;
+}
+
+static int source_eqf(const char *a, const char *b)
+{
+	return (a && b && strcmp(a, b) == 0)
+		|| (a == NULL && b == NULL);
+}
+
+static int
+revert(RuleContext *f, const char *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;
+	FilterRule *frule;
+
+	rule_context_set_error (f, NULL);
+	
+	d(printf("restoring rules %s %s\n", user));
+
+	userdoc = xmlParseFile (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 = rule_context_next_rule(f, 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 = userdoc->root->childs;
+	while (set) {
+		d(printf("set name = %s\n", set->name));
+		rule_map = g_hash_table_lookup (f->rule_set_map, set->name);
+		if (rule_map) {
+			d(printf("loading rules ...\n"));
+			rule = set->childs;
+			while (rule) {
+				d(printf("checking node: %s\n", rule->name));
+				if (!strcmp (rule->name, "rule")) {
+					FilterRule *part = FILTER_RULE(gtk_type_new (rule_map->type));
+					
+					if (filter_rule_xml_decode (part, rule, f) == 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 (f->priv->frozen == 0 && !filter_rule_eq(frule, part))
+								filter_rule_copy(frule, part);
+							gtk_object_unref (GTK_OBJECT (part));
+							rule_context_rank_rule(f, frule, rest_data->rank);
+							g_hash_table_remove(rest_data->rules, frule->name);
+						} else {
+							rule_context_add_rule(f, part);
+							rule_context_rank_rule(f, part, rest_data->rank);
+						}
+						rest_data->rank++;
+					} else {
+						gtk_object_unref (GTK_OBJECT (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, f);
+	g_hash_table_destroy(source_hash);
+
+	return 0;
 }
 
 FilterPart *
Index: filter/rule-context.h
===================================================================
RCS file: /cvs/gnome/evolution/filter/rule-context.h,v
retrieving revision 1.15
diff -u -3 -r1.15 rule-context.h
--- filter/rule-context.h	8 May 2002 06:36:28 -0000	1.15
+++ filter/rule-context.h	10 Jul 2002 09:27:41 -0000
@@ -60,6 +60,7 @@
 	/* virtual methods */
 	int (*load)(RuleContext *f, const char *system, const char *user);
 	int (*save)(RuleContext *f, const char *user);
+	int (*revert)(RuleContext *f, const char *user);
 
 	GList *(*delete_uri)(RuleContext *f, const char *uri, GCompareFunc cmp);
 	GList *(*rename_uri)(RuleContext *f, const char *olduri, const char *newuri, GCompareFunc cmp);
@@ -95,6 +96,7 @@
 /* methods */
 int		rule_context_load(RuleContext *f, const char *system, const char *user);
 int		rule_context_save(RuleContext *f, const char *user);
+int		rule_context_revert(RuleContext *f, const char *user);
 
 void		rule_context_add_part(RuleContext *f, FilterPart *new);
 FilterPart 	*rule_context_find_part(RuleContext *f, const char *name);
Index: filter/vfolder-rule.c
===================================================================
RCS file: /cvs/gnome/evolution/filter/vfolder-rule.c,v
retrieving revision 1.20
diff -u -3 -r1.20 vfolder-rule.c
--- filter/vfolder-rule.c	4 Apr 2002 20:03:02 -0000	1.20
+++ filter/vfolder-rule.c	10 Jul 2002 09:27:41 -0000
@@ -39,6 +39,7 @@
 #define d(x) x
 
 static gint validate(FilterRule *);
+static int vfolder_eq(FilterRule *fr, FilterRule *cm);
 static xmlNodePtr xml_encode(FilterRule *);
 static int xml_decode(FilterRule *, xmlNodePtr, struct _RuleContext *f);
 static void rule_copy (FilterRule *dest, FilterRule *src);
@@ -93,6 +94,7 @@
 
 	/* override methods */
 	filter_rule->validate   = validate;
+	filter_rule->eq = vfolder_eq;
 	filter_rule->xml_encode = xml_encode;
 	filter_rule->xml_decode = xml_decode;
 	filter_rule->copy = rule_copy;
@@ -220,6 +222,29 @@
 		return FILTER_RULE_CLASS (parent_class)->validate (fr);
 	
 	return 1;
+}
+
+static int
+list_eq(GList *al, GList *bl)
+{
+	int truth = TRUE;
+
+	while (truth && al && bl) {
+		char *a = al->data, *b = bl->data;
+
+		truth = strcmp(a, b) == 0;
+		al = al->next;
+		bl = bl->next;
+	}
+
+	return truth && al == NULL && bl == NULL;
+}
+
+static int
+vfolder_eq(FilterRule *fr, FilterRule *cm)
+{
+        return ((FilterRuleClass *)(parent_class))->eq(fr, cm)
+		&& list_eq(((VfolderRule *)fr)->sources, ((VfolderRule *)cm)->sources);
 }
 
 static xmlNodePtr
