aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornobody <nobody@localhost>2000-02-16 17:16:10 +0800
committernobody <nobody@localhost>2000-02-16 17:16:10 +0800
commitd512fcda21677345188840ea5a77cefd6bb4a60b (patch)
tree8f1d578d4faf867fe7b4be0b281695c1a8b640af
parente293db6dfb3b21244742ecb5433a03466edb5bc6 (diff)
downloadgsoc2013-evolution-start.tar.gz
gsoc2013-evolution-start.tar.zst
gsoc2013-evolution-start.zip
This commit was manufactured by cvs2svn to create branch 'HELIX'.start
svn path=/branches/HELIX/; revision=1787
-rw-r--r--filter/ChangeLog4
-rw-r--r--filter/Makefile11
-rw-r--r--filter/filter-arg-types.c393
-rw-r--r--filter/filter-arg-types.h75
-rw-r--r--filter/filter-arg.c217
-rw-r--r--filter/filter-arg.h72
-rw-r--r--filter/filter-driver.c176
-rw-r--r--filter/filter-sexp.c1073
-rw-r--r--filter/filter-sexp.h117
-rw-r--r--filter/filter-xml.c658
-rw-r--r--filter/filter-xml.h51
11 files changed, 2847 insertions, 0 deletions
diff --git a/filter/ChangeLog b/filter/ChangeLog
new file mode 100644
index 0000000000..aa6d977034
--- /dev/null
+++ b/filter/ChangeLog
@@ -0,0 +1,4 @@
+2000-02-14 NotZed <notzed@helixcode.com>
+
+ * Initial import.
+
diff --git a/filter/Makefile b/filter/Makefile
new file mode 100644
index 0000000000..2527224874
--- /dev/null
+++ b/filter/Makefile
@@ -0,0 +1,11 @@
+
+OBJS = filter-arg-types.o filter-arg.o filter-xml.o filter-sexp.o filter-driver.o
+SRCS = filter-arg-types.c filter-arg.c filter-xml.c filter-sexp.c filter-driver.c
+
+CFLAGS = `gnome-config --cflags xml gnome gtk gtkhtml gnomeui` -g -I../camel -I .. -I../libibex
+LDFLAGS = `gnome-config --libs xml gnome gtk gtkhtml gnomeui` -L ../camel/.libs -lcamel
+
+all: filter-driver
+
+filter-driver: $(OBJS)
+
diff --git a/filter/filter-arg-types.c b/filter/filter-arg-types.c
new file mode 100644
index 0000000000..5b046d9ea6
--- /dev/null
+++ b/filter/filter-arg-types.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Michael Zucchi <notzed@helixcode.com>
+ *
+ * Implementations of the filter-arg types.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "filter-arg-types.h"
+
+/* ********************************************************************** */
+/* Address */
+/* ********************************************************************** */
+
+static void filter_arg_address_class_init (FilterArgAddressClass *class);
+static void filter_arg_address_init (FilterArgAddress *gspaper);
+
+static FilterArg *parent_class;
+
+guint
+filter_arg_address_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterArgAddress",
+ sizeof (FilterArgAddress),
+ sizeof (FilterArgAddressClass),
+ (GtkClassInitFunc) filter_arg_address_class_init,
+ (GtkObjectInitFunc) filter_arg_address_init,
+ (GtkArgSetFunc) NULL,
+ (GtkArgGetFunc) NULL
+ };
+
+ type = gtk_type_unique (filter_arg_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+arg_address_write_html(FilterArg *argin, GtkHTML *html, GtkHTMLStreamHandle *stream)
+{
+ FilterArgAddress *arg = (FilterArgAddress *)argin;
+ /* empty */
+}
+
+static void
+arg_address_write_text(FilterArg *argin, GString *string)
+{
+ FilterArgAddress *arg = (FilterArgAddress *)argin;
+ GList *l;
+ struct filter_arg_address *a;
+
+ l = argin->values;
+ if (l == NULL) {
+ g_string_append(string, "email address");
+ }
+ while (l) {
+ a = l->data;
+ g_string_append(string, a->name);
+ if (l->next) {
+ g_string_append(string, ", ");
+ }
+ l = g_list_next(l);
+ }
+}
+
+static void
+arg_address_edit_values(FilterArg *arg)
+{
+ printf("edit it!\n");
+}
+
+static xmlNodePtr
+arg_address_values_get_xml(FilterArg *argin)
+{
+ xmlNodePtr value;
+ FilterArgAddress *arg = (FilterArgAddress *)argin;
+ GList *l;
+ struct filter_arg_address *a;
+
+ /* hmm, perhaps this overhead should be in FilterArg, and this function just returns the base node?? */
+ value = xmlNewNode(NULL, "optionvalue");
+ xmlSetProp(value, "name", argin->name);
+
+ l = argin->values;
+ while (l) {
+ xmlNodePtr cur;
+
+ a = l->data;
+
+ cur = xmlNewChild(value, NULL, "address", NULL);
+ if (a->name)
+ xmlSetProp(cur, "name", a->name);
+ if (a->email)
+ xmlSetProp(cur, "email", a->email);
+ l = g_list_next(l);
+ }
+
+ return value;
+}
+
+static void
+arg_address_values_add_xml(FilterArg *arg, xmlNodePtr node)
+{
+ xmlNodePtr n;
+
+ n = node->childs;
+ while (n) {
+ if (!strcmp(n->name, "address")) {
+ filter_arg_address_add(arg, xmlGetProp(n, "name"), xmlGetProp(n, "email"));
+ } else {
+ g_warning("Loading address from xml, wrong node encountered: %s\n", n->name);
+ }
+ n = n->next;
+ }
+}
+
+/* the search string is just the raw email address */
+static char *
+arg_address_get_value_as_string(FilterArg *argin, void *data)
+{
+ FilterArgAddress *arg = (FilterArgAddress *)argin;
+ struct filter_arg_address *a = (struct filter_arg_address *)data;
+
+ if (a->email == NULL
+ || a->email[0] == '\0') {
+ if (a->name == NULL
+ || a->name[0] == '\0')
+ return "";
+ return a->name;
+ } else
+ return a->email;
+}
+
+static void
+arg_address_free_value(FilterArg *arg, struct filter_arg_address *a)
+{
+ g_free(a->name);
+ g_free(a->email);
+ g_free(a);
+}
+
+static void
+filter_arg_address_class_init (FilterArgAddressClass *class)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *) class;
+ if (parent_class == NULL)
+ parent_class = gtk_type_class (gtk_object_get_type ());
+
+ class->parent_class.write_html = arg_address_write_html;
+ class->parent_class.write_text = arg_address_write_text;
+ class->parent_class.edit_values = arg_address_edit_values;
+ class->parent_class.free_value = arg_address_free_value;
+
+ class->parent_class.values_get_xml = arg_address_values_get_xml;
+ class->parent_class.values_add_xml = arg_address_values_add_xml;
+
+ class->parent_class.get_value_as_string = arg_address_get_value_as_string;
+}
+
+static void
+filter_arg_address_init (FilterArgAddress *arg)
+{
+ arg->arg.values = NULL;
+}
+
+/**
+ * filter_arg_address_new:
+ *
+ * Create a new FilterArgAddress widget.
+ *
+ * Return value: A new FilterArgAddress widget.
+ **/
+FilterArg *
+filter_arg_address_new (char *name)
+{
+ FilterArg *a = FILTER_ARG ( gtk_type_new (filter_arg_address_get_type ()));
+ a->name = g_strdup(name);
+ return a;
+}
+
+void
+filter_arg_address_add(FilterArg *arg, char *name, char *email)
+{
+ struct filter_arg_address *a;
+
+ a = g_malloc0(sizeof(*a));
+
+ a->name = g_strdup(name);
+ a->email = g_strdup(email);
+
+ filter_arg_add(arg, a);
+}
+
+void
+filter_arg_address_remove(FilterArg *arg, char *name, char *email)
+{
+
+}
+
+/* ********************************************************************** */
+/* Folder */
+/* ********************************************************************** */
+
+
+static void filter_arg_folder_class_init (FilterArgFolderClass *class);
+static void filter_arg_folder_init (FilterArgFolder *gspaper);
+
+static FilterArg *parent_class;
+
+guint
+filter_arg_folder_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterArgFolder",
+ sizeof (FilterArgFolder),
+ sizeof (FilterArgFolderClass),
+ (GtkClassInitFunc) filter_arg_folder_class_init,
+ (GtkObjectInitFunc) filter_arg_folder_init,
+ (GtkArgSetFunc) NULL,
+ (GtkArgGetFunc) NULL
+ };
+
+ type = gtk_type_unique (filter_arg_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+arg_folder_write_html(FilterArg *argin, GtkHTML *html, GtkHTMLStreamHandle *stream)
+{
+ FilterArgFolder *arg = (FilterArgFolder *)argin;
+ /* empty */
+}
+
+static void
+arg_folder_write_text(FilterArg *argin, GString *string)
+{
+ FilterArgFolder *arg = (FilterArgFolder *)argin;
+ GList *l;
+ char *a;
+
+ l = argin->values;
+ if (l == NULL) {
+ g_string_append(string, "folder");
+ }
+ while (l) {
+ a = l->data;
+ g_string_append(string, a);
+ if (l->next) {
+ g_string_append(string, ", ");
+ }
+ l = g_list_next(l);
+ }
+}
+
+static void
+arg_folder_edit_values(FilterArg *arg)
+{
+ printf("edit it!\n");
+}
+
+static xmlNodePtr
+arg_folder_values_get_xml(FilterArg *argin)
+{
+ xmlNodePtr value;
+ FilterArgFolder *arg = (FilterArgFolder *)argin;
+ GList *l;
+ char *a;
+
+ value = xmlNewNode(NULL, "optionvalue");
+ xmlSetProp(value, "name", argin->name);
+
+ l = argin->values;
+ while (l) {
+ xmlNodePtr cur;
+
+ a = l->data;
+
+ cur = xmlNewChild(value, NULL, "folder", NULL);
+ if (a)
+ xmlSetProp(cur, "folder", a);
+ l = g_list_next(l);
+ }
+
+ return value;
+}
+
+static void
+arg_folder_values_add_xml(FilterArg *arg, xmlNodePtr node)
+{
+ xmlNodePtr n;
+
+ n = node->childs;
+ while (n) {
+ if (!strcmp(n->name, "folder")) {
+ filter_arg_folder_add(arg, xmlGetProp(n, "folder"));
+ } else {
+ g_warning("Loading folders from xml, wrong node encountered: %s\n", n->name);
+ }
+ n = n->next;
+ }
+}
+
+static char *
+arg_folder_get_value_as_string(FilterArg *argin, void *data)
+{
+ FilterArgFolder *arg = (FilterArgFolder *)argin;
+ char *a = (char *)data;
+
+ return a;
+}
+
+static void
+arg_folder_free_value(FilterArg *arg, void *a)
+{
+ g_free(a);
+}
+
+static void
+filter_arg_folder_class_init (FilterArgFolderClass *class)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *) class;
+ if (parent_class == NULL)
+ parent_class = gtk_type_class (gtk_object_get_type ());
+
+ class->parent_class.write_html = arg_folder_write_html;
+ class->parent_class.write_text = arg_folder_write_text;
+ class->parent_class.edit_values = arg_folder_edit_values;
+ class->parent_class.free_value = arg_folder_free_value;
+
+ class->parent_class.values_get_xml = arg_folder_values_get_xml;
+ class->parent_class.values_add_xml = arg_folder_values_add_xml;
+}
+
+static void
+filter_arg_folder_init (FilterArgFolder *arg)
+{
+ arg->arg.values = NULL;
+}
+
+/**
+ * filter_arg_folder_new:
+ *
+ * Create a new FilterArgFolder widget.
+ *
+ * Return value: A new FilterArgFolder widget.
+ **/
+FilterArg *
+filter_arg_folder_new (char *name)
+{
+ FilterArg *a = FILTER_ARG ( gtk_type_new (filter_arg_folder_get_type ()));
+ a->name = g_strdup(name);
+ return a;
+}
+
+
+void
+filter_arg_folder_add(FilterArg *arg, char *name)
+{
+ filter_arg_add(arg, g_strdup(name));
+}
+
+void
+filter_arg_folder_remove(FilterArg *arg, char *name)
+{
+ /* do it */
+}
diff --git a/filter/filter-arg-types.h b/filter/filter-arg-types.h
new file mode 100644
index 0000000000..26ee280a55
--- /dev/null
+++ b/filter/filter-arg-types.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Michael Zucchi <notzed@helixcode.com>
+ *
+ * Implementations of the filter-args.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FILTER_ARG_TYPES_H
+#define _FILTER_ARG_TYPES_H
+
+#include "filter-arg.h"
+
+/* An Address */
+#define FILTER_ARG_ADDRESS(obj) GTK_CHECK_CAST (obj, filter_arg_address_get_type (), FilterArgAddress)
+#define FILTER_ARG_ADDRESS_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_arg_address_get_type (), FilterArgAddressClass)
+#define IS_FILTER_ARG_ADDRESS(obj) GTK_CHECK_TYPE (obj, filter_arg_address_get_type ())
+
+typedef struct _FilterArgAddress FilterArgAddress;
+typedef struct _FilterArgAddressClass FilterArgAddressClass;
+
+struct _FilterArgAddress {
+ FilterArg arg;
+};
+
+struct _FilterArgAddressClass {
+ FilterArgClass parent_class;
+};
+
+struct filter_arg_address {
+ char *name;
+ char *email;
+};
+
+guint filter_arg_address_get_type (void);
+FilterArg *filter_arg_address_new (char *name);
+void filter_arg_address_add(FilterArg *, char *name, char *email);
+void filter_arg_address_remove(FilterArg *, char *name, char *email);
+
+/* A Folder */
+#define FILTER_ARG_FOLDER(obj) GTK_CHECK_CAST (obj, filter_arg_folder_get_type (), FilterArgFolder)
+#define FILTER_ARG_FOLDER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_arg_folder_get_type (), FilterArgFolderClass)
+#define IS_FILTER_ARG_FOLDER(obj) GTK_CHECK_TYPE (obj, filter_arg_folder_get_type ())
+
+typedef struct _FilterArgFolder FilterArgFolder;
+typedef struct _FilterArgFolderClass FilterArgFolderClass;
+
+struct _FilterArgFolder {
+ FilterArg arg;
+};
+
+struct _FilterArgFolderClass {
+ FilterArgClass parent_class;
+};
+
+guint filter_arg_folder_get_type (void);
+FilterArg *filter_arg_folder_new (char *name);
+void filter_arg_folder_add(FilterArg *, char *name);
+void filter_arg_folder_remove(FilterArg *, char *name);
+
+#endif /* ! _FILTER_ARG_TYPES_H */
diff --git a/filter/filter-arg.c b/filter/filter-arg.c
new file mode 100644
index 0000000000..44dc90471e
--- /dev/null
+++ b/filter/filter-arg.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Michael Zucchi <notzed@helixcode.com>
+ *
+ * Abstract filter argument class.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "filter-arg.h"
+
+
+static void filter_arg_class_init (FilterArgClass *class);
+static void filter_arg_init (FilterArg *gspaper);
+
+static GtkObjectClass *parent_class;
+
+enum {
+ CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+guint
+filter_arg_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterArg",
+ sizeof (FilterArg),
+ sizeof (FilterArgClass),
+ (GtkClassInitFunc) filter_arg_class_init,
+ (GtkObjectInitFunc) filter_arg_init,
+ (GtkArgSetFunc) NULL,
+ (GtkArgGetFunc) NULL
+ };
+
+ type = gtk_type_unique (gtk_object_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+write_html_nothing(FilterArg *arg, GtkHTML *html, GtkHTMLStreamHandle *stream)
+{
+ /* empty */
+}
+
+static void
+write_text_nothing(FilterArg *arg, GString *string)
+{
+ /* empty */
+}
+
+static void
+edit_values_nothing(FilterArg *arg)
+{
+ /* empty */
+}
+
+static void
+free_value_nothing(FilterArg *arg, void *v)
+{
+ /* empty */
+}
+
+static gint
+compare_pointers(gpointer a, gpointer b)
+{
+ return a==b;
+}
+
+static void
+filter_arg_class_init (FilterArgClass *class)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *) class;
+ parent_class = gtk_type_class (gtk_object_get_type ());
+
+ class->write_html = write_html_nothing;
+ class->write_text = write_text_nothing;
+ class->edit_values = edit_values_nothing;
+ class->free_value = free_value_nothing;
+
+ signals[CHANGED] =
+ gtk_signal_new ("changed",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (FilterArgClass, changed),
+ gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
+ gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
+}
+
+static void
+filter_arg_init (FilterArg *arg)
+{
+ arg->values = NULL;
+}
+
+/**
+ * filter_arg_new:
+ *
+ * Create a new FilterArg widget.
+ *
+ * Return value: A new FilterArg widget.
+ **/
+FilterArg *
+filter_arg_new (char *name)
+{
+ FilterArg *a = FILTER_ARG ( gtk_type_new (filter_arg_get_type ()));
+ if (name)
+ a->name = g_strdup(name);
+ return a;
+}
+
+void
+filter_arg_add(FilterArg *arg, void *v)
+{
+ arg->values = g_list_append(arg->values, v);
+ gtk_signal_emit(GTK_OBJECT(arg), signals[CHANGED]);
+}
+
+void
+filter_arg_remove(FilterArg *arg, void *v)
+{
+ arg->values = g_list_remove(arg->values, v);
+ ((FilterArgClass *)(arg->object.klass))->free_value(arg, v);
+ gtk_signal_emit(GTK_OBJECT(arg), signals[CHANGED]);
+}
+
+void
+filter_arg_write_html(FilterArg *arg, GtkHTML *html, GtkHTMLStreamHandle *stream)
+{
+ ((FilterArgClass *)(arg->object.klass))->write_html(arg, html, stream);
+}
+void
+filter_arg_write_text(FilterArg *arg, GString *string)
+{
+ ((FilterArgClass *)(arg->object.klass))->write_text(arg, string);
+}
+void
+filter_arg_edit_values(FilterArg *arg)
+{
+ ((FilterArgClass *)(arg->object.klass))->edit_values(arg);
+}
+
+xmlNodePtr
+filter_arg_values_get_xml(FilterArg *arg)
+{
+ return ((FilterArgClass *)(arg->object.klass))->values_get_xml(arg);
+}
+void
+filter_arg_values_add_xml(FilterArg *arg, xmlNodePtr node)
+{
+ ((FilterArgClass *)(arg->object.klass))->values_add_xml(arg, node);
+}
+
+/* returns the number of args in the arg list */
+int
+filter_arg_get_count(FilterArg *arg)
+{
+ int count=0;
+ GList *l;
+
+ for (l = arg->values;l;l=g_list_next(l))
+ count++;
+ return count;
+}
+
+void *
+filter_arg_get_value(FilterArg *arg, int index)
+{
+ int count=0;
+ GList *l;
+
+ for (l = arg->values;l && count<index;l=g_list_next(l))
+ count++;
+ if (l)
+ return l->data;
+ return NULL;
+}
+
+char *
+filter_arg_get_value_as_string(FilterArg *arg, int index)
+{
+ int count=0;
+ GList *l;
+ void *data;
+
+ data = filter_arg_get_value(arg, index);
+ if (data) {
+ return ((FilterArgClass *)(arg->object.klass))->get_value_as_string(arg, data);
+ } else {
+ return "";
+ }
+}
+
+
diff --git a/filter/filter-arg.h b/filter/filter-arg.h
new file mode 100644
index 0000000000..ecdba3436d
--- /dev/null
+++ b/filter/filter-arg.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Michael Zucchi <notzed@helixcode.com>
+ *
+ * Abstract class to hold filter arguments.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FILTER_ARG_H
+#define _FILTER_ARG_H
+
+#include <gtk/gtk.h>
+#include <gtkhtml/gtkhtml.h>
+#include <gnome-xml/tree.h>
+
+#define FILTER_ARG(obj) GTK_CHECK_CAST (obj, filter_arg_get_type (), FilterArg)
+#define FILTER_ARG_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_arg_get_type (), FilterArgClass)
+#define IS_FILTER_ARG(obj) GTK_CHECK_TYPE (obj, filter_arg_get_type ())
+
+typedef struct _FilterArg FilterArg;
+typedef struct _FilterArgClass FilterArgClass;
+
+struct _FilterArg {
+ GtkObject object;
+
+ char *name;
+ GList *values;
+};
+
+struct _FilterArgClass {
+ GtkObjectClass parent_class;
+
+ /* virtual methods */
+ void (*write_html)(FilterArg *arg, GtkHTML *html, GtkHTMLStreamHandle *stream);
+ void (*write_text)(FilterArg *arg, GString *string);
+ void (*free_value)(FilterArg *arg, void *v);
+ void (*edit_values)(FilterArg *arg);
+
+ void (*values_add_xml)(FilterArg *arg, xmlNodePtr node);
+ xmlNodePtr (*values_get_xml)(FilterArg *arg);
+
+ char * (*get_value_as_string)(FilterArg *arg, void *data);
+
+ /* signals */
+ void (*changed)(FilterArg *arg);
+};
+
+guint filter_arg_get_type (void);
+FilterArg *filter_arg_new (char *name);
+void filter_arg_value_add(FilterArg *a, void *v);
+
+xmlNodePtr filter_arg_values_get_xml(FilterArg *arg);
+void filter_arg_values_add_xml(FilterArg *arg, xmlNodePtr node);
+int filter_arg_get_count(FilterArg *arg);
+void *filter_arg_get_value(FilterArg *arg, int index);
+char *filter_arg_get_value_as_string(FilterArg *arg, int index);
+
+#endif /* ! _FILTER_ARG_H */
diff --git a/filter/filter-driver.c b/filter/filter-driver.c
new file mode 100644
index 0000000000..6df07e76b8
--- /dev/null
+++ b/filter/filter-driver.c
@@ -0,0 +1,176 @@
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gnome.h>
+#include <gtkhtml/gtkhtml.h>
+
+#include <gnome-xml/tree.h>
+#include <gnome-xml/parser.h>
+
+#include "filter-arg-types.h"
+#include "filter-xml.h"
+#include "filter-sexp.h"
+
+extern int filter_find_arg(FilterArg *a, char *name);
+
+/*
+ splices ${cc} lines into a single string
+*/
+int
+expand_variables(GString *out, char *source, GList *args, int index)
+{
+ GList *argl;
+ FilterArg *arg;
+ char *name= alloca(32);
+ char *start, *end, *newstart, *tmp;
+ int namelen=32;
+ int len=0;
+ int ok = 0;
+
+ start = source;
+ while ( (newstart = strstr(start, "${"))
+ && (end = strstr(newstart+2, "}")) ) {
+ len = end-newstart-2;
+ if (len+1>namelen) {
+ namelen = (len+1)*2;
+ name = alloca(namelen);
+ }
+ memcpy(name, newstart+2, len);
+ name[len] = 0;
+ argl = g_list_find_custom(args, name, filter_find_arg);
+ if (argl) {
+ arg = argl->data;
+ tmp = g_strdup_printf("%.*s%s", newstart-start, start, filter_arg_get_value_as_string(arg, index));
+ printf("appending: %s\n", tmp);
+ g_string_append(out, tmp);
+ g_free(tmp);
+ } else {
+ ok = 1;
+ tmp = g_strdup_printf("%.*s", end-start+1, start);
+ printf("appending: %s\n", tmp);
+ g_string_append(out, tmp);
+ g_free(tmp);
+ }
+ start = end+1;
+ }
+ g_string_append(out, start);
+
+ return ok;
+}
+
+/*
+ build an expression for the filter
+*/
+static void
+expand_filter_option(GString *s, struct filter_option *op)
+{
+ GList *optionl;
+ FilterArg *arg;
+
+ g_string_append(s, "(and ");
+ optionl = op->options;
+ while (optionl) {
+ struct filter_optionrule *or = optionl->data;
+ if (or->rule->type == FILTER_XML_MATCH) {
+ GList *argl;
+ int max=1, count;
+ int i;
+
+ /* find out how many values we have in each arg (rule
+ is repeated that many times for each arg) */
+ argl = or->args;
+ while (argl) {
+ arg = argl->data;
+ count = filter_arg_get_count(arg);
+ if (count>=max && max>1) {
+ g_warning("Rule '%s' has too many multi-valued values, ignored", or->rule->name);
+ goto next_rule;
+ }
+ if (count>max) {
+ max = count;
+ }
+ argl = g_list_next(argl);
+ }
+ g_string_append(s, "(or ");
+ for (i=0;i<max;i++) {
+ expand_variables(s, or->rule->code, or->args, i);
+ }
+ g_string_append(s, ") ");
+ }
+ next_rule:
+ optionl = g_list_next(optionl);
+ }
+#if 0
+ optionl = op->options;
+ while (optionl) {
+ struct filter_optionrule *or = optionl->data;
+ if (or->rule->type == FILTER_XML_EXCEPT) {
+ g_string_append(s, " (except \"");
+ g_string_append(s, or->rule->name);
+ g_string_append(s, "\" ");
+ g_string_append(s, or->rule->code);
+ g_string_append(s, " ) ");
+ }
+ optionl = g_list_next(optionl);
+ }
+#endif
+ g_string_append(s, ")");
+#if 0
+ optionl = op->options;
+ while (optionl) {
+ struct filter_optionrule *or = optionl->data;
+ if (or->rule->type == FILTER_XML_ACTION) {
+ g_string_append(s, or->rule->code);
+ g_string_append(s, " ");
+ }
+ optionl = g_list_next(optionl);
+ }
+ g_string_append(s, ")))");
+#endif
+ printf("combined rule '%s'\n", s->str);
+}
+
+int main(int argc, char **argv)
+{
+ FilterSEXP *f;
+ FilterSEXPResult *r;
+ GList *rules, *options;
+ xmlDocPtr doc, out, optionset, filteroptions;
+ GString *s;
+
+ gnome_init("Test", "0.0", argc, argv);
+
+ doc = xmlParseFile("filterdescription.xml");
+ rules = load_ruleset(doc);
+ options = load_optionset(doc, rules);
+ out = xmlParseFile("saveoptions.xml");
+ options = load_optionset(out, rules);
+
+ s = g_string_new("");
+ expand_filter_option(s, options->data);
+ g_string_append(s, "");
+
+ printf("total rule = '%s'\n", s->str);
+
+ f = filter_sexp_new();
+ filter_sexp_add_variable(f, 0, "sender", NULL);
+ filter_sexp_add_variable(f, 0, "receipient", NULL);
+ filter_sexp_add_variable(f, 0, "folder", NULL);
+
+ /* simple functions */
+ filter_sexp_add_function(f, 0, "header-get", NULL, NULL);
+ filter_sexp_add_function(f, 0, "header-contains", NULL, NULL);
+ filter_sexp_add_function(f, 0, "copy-to", NULL, NULL);
+
+ filter_sexp_add_ifunction(f, 0, "set", NULL, NULL);
+
+ /* control functions */
+ filter_sexp_add_ifunction(f, 0, "match-all", NULL, NULL);
+ filter_sexp_add_ifunction(f, 0, "match", NULL, NULL);
+ filter_sexp_add_ifunction(f, 0, "action", NULL, NULL);
+ filter_sexp_add_ifunction(f, 0, "except", NULL, NULL);
+
+ filter_sexp_input_text(f, s->str, strlen(s->str));
+ filter_sexp_parse(f);
+
+}
diff --git a/filter/filter-sexp.c b/filter/filter-sexp.c
new file mode 100644
index 0000000000..738ffa3380
--- /dev/null
+++ b/filter/filter-sexp.c
@@ -0,0 +1,1073 @@
+/*
+ * Copyright 2000 HelixCode (http://www.helixcode.com).
+ *
+ * A simple, extensible s-exp evaluation engine.
+ *
+ * Author :
+ * Michael Zucchi <notzed@helixcode.com>
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ The following built-in s-exp's are supported:
+
+ list = (and list*)
+ perform an intersection of a number of lists, and return that.
+
+ bool = (and bool*)
+ perform a boolean AND of boolean values.
+
+ list = (or list*)
+ perform a union of a number of lists, returning the new list.
+
+ bool = (or bool*)
+ perform a boolean OR of boolean values.
+
+ int = (+ int*)
+ Add integers.
+
+ string = (+ string*)
+ Concat strings.
+
+ int = (- int int*)
+ Subtract integers from the first.
+
+ Comparison operators:
+
+ bool = (< int int)
+ bool = (> int int)
+ bool = (= int int)
+
+ bool = (< string string)
+ bool = (> string string)
+ bool = (= string string)
+ Perform a comparision of 2 integers, or 2 string values.
+
+ Function flow:
+
+ type = (if bool function)
+ type = (if bool function function)
+ Choose a flow path based on a boolean value
+
+ type = (begin func func func)
+ Execute a sequence. The last function return is the return type.
+*/
+
+#include <glib.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+
+#include "filter-sexp.h"
+
+#define p(x) /* parse debug */
+#define r(x) /* run debug */
+#define d(x) /* general debug */
+
+
+static struct _FilterSEXPTerm * parse_list(FilterSEXP *f, int gotbrace);
+static struct _FilterSEXPTerm * parse_value(FilterSEXP *f);
+
+static void parse_dump_term(struct _FilterSEXPTerm *t, int depth);
+
+static GtkObjectClass *parent_class;
+
+
+
+static GScannerConfig scanner_config =
+{
+ ( " \t\r\n") /* cset_skip_characters */,
+ ( G_CSET_a_2_z
+ "_+<=>"
+ G_CSET_A_2_Z) /* cset_identifier_first */,
+ ( G_CSET_a_2_z
+ "_0123456789-<>"
+ G_CSET_A_2_Z
+ G_CSET_LATINS
+ G_CSET_LATINC ) /* cset_identifier_nth */,
+ ( ";\n" ) /* cpair_comment_single */,
+
+ FALSE /* case_sensitive */,
+
+ TRUE /* skip_comment_multi */,
+ TRUE /* skip_comment_single */,
+ TRUE /* scan_comment_multi */,
+ TRUE /* scan_identifier */,
+ TRUE /* scan_identifier_1char */,
+ FALSE /* scan_identifier_NULL */,
+ TRUE /* scan_symbols */,
+ FALSE /* scan_binary */,
+ TRUE /* scan_octal */,
+ TRUE /* scan_float */,
+ TRUE /* scan_hex */,
+ FALSE /* scan_hex_dollar */,
+ TRUE /* scan_string_sq */,
+ TRUE /* scan_string_dq */,
+ TRUE /* numbers_2_int */,
+ FALSE /* int_2_float */,
+ FALSE /* identifier_2_string */,
+ TRUE /* char_2_token */,
+ FALSE /* symbol_2_token */,
+ FALSE /* scope_0_fallback */,
+};
+
+struct _FilterSEXPResult *
+filter_sexp_result_new(int type)
+{
+ struct _FilterSEXPResult *r = g_malloc0(sizeof(*r));
+ r->type = type;
+ return r;
+}
+
+void
+filter_sexp_result_free(struct _FilterSEXPResult *t)
+{
+ if (t == NULL)
+ return;
+
+ switch(t->type) {
+ case FSEXP_RES_ARRAY_PTR:
+ g_ptr_array_free(t->value.ptrarray, TRUE);
+ break;
+ case FSEXP_RES_BOOL:
+ case FSEXP_RES_INT:
+ break;
+ case FSEXP_RES_STRING:
+ g_free(t->value.string);
+ break;
+ case FSEXP_RES_UNDEFINED:
+ break;
+ }
+ g_free(t);
+}
+
+/* implementations for the builtin functions */
+
+/* can you tell, i dont like glib? */
+/* we can only itereate a hashtable from a called function */
+struct _glib_sux_donkeys {
+ int count;
+ GPtrArray *uids;
+};
+
+/* ok, store any values that are in all sets */
+static void
+g_lib_sux_htand(char *key, int value, struct _glib_sux_donkeys *fuckup)
+{
+ if (value == fuckup->count) {
+ g_ptr_array_add(fuckup->uids, key);
+ }
+}
+
+/* or, store all unique values */
+static void
+g_lib_sux_htor(char *key, int value, struct _glib_sux_donkeys *fuckup)
+{
+ g_ptr_array_add(fuckup->uids, key);
+}
+
+static FilterSEXPResult *
+term_eval_and(struct _FilterSEXP *f, int argc, struct _FilterSEXPTerm **argv, void *data)
+{
+ struct _FilterSEXPResult *r, *r1, *r2;
+ GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
+ struct _glib_sux_donkeys lambdafoo;
+ int type=-1;
+ int bool = TRUE;
+ int i;
+
+ r(printf("( and\n"));
+
+ r = filter_sexp_result_new(FSEXP_RES_UNDEFINED);
+
+ for (i=0;bool && i<argc;i++) {
+ r1 = filter_sexp_term_eval(f, argv[i]);
+ if (type == -1)
+ type = r1->type;
+ if (type != r1->type) {
+ printf("invalid types in and operation, all types must be the same\n");
+ } else if ( r1->type == FSEXP_RES_ARRAY_PTR ) {
+ char **a1;
+ int l1, j;
+
+ a1 = (char **)r1->value.ptrarray->pdata;
+ l1 = r1->value.ptrarray->len;
+ for (j=0;i<l1;j++) {
+ int n;
+ n = (int)g_hash_table_lookup(ht, a1[i]);
+ g_hash_table_insert(ht, a1[i], (void *)n+1);
+ }
+ } else if ( r1->type == FSEXP_RES_BOOL ) {
+ bool &= r1->value.bool;
+ }
+ filter_sexp_result_free(r1);
+ }
+
+ if (type == FSEXP_RES_ARRAY_PTR) {
+ lambdafoo.count = argc;
+ lambdafoo.uids = g_ptr_array_new();
+ g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htand, &lambdafoo);
+ r->type = FSEXP_RES_ARRAY_PTR;
+ r->value.ptrarray = lambdafoo.uids;
+ } else if (type == FSEXP_RES_BOOL) {
+ r->type = FSEXP_RES_BOOL;
+ r->value.bool = bool;
+ }
+
+ g_hash_table_destroy(ht);
+
+ return r;
+}
+
+static FilterSEXPResult *
+term_eval_or(struct _FilterSEXP *f, int argc, struct _FilterSEXPTerm **argv, void *data)
+{
+ struct _FilterSEXPResult *r, *r1, *r2;
+ GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
+ struct _glib_sux_donkeys lambdafoo;
+ int type = -1;
+ int bool = FALSE;
+ int i;
+
+ r(printf("(or \n"));
+
+ r = filter_sexp_result_new(FSEXP_RES_UNDEFINED);
+
+ for (i=0;!bool && i<argc;i++) {
+ r1 = filter_sexp_term_eval(f, argv[i]);
+ if (type == -1)
+ type = r1->type;
+ if (r1->type != type) {
+ printf("wrong types in or operation\n");
+ } else if (r1->type == FSEXP_RES_ARRAY_PTR) {
+ char **a1;
+ int l1, j;
+
+ a1 = (char **)r1->value.ptrarray->pdata;
+ l1 = r1->value.ptrarray->len;
+ for (j=0;i<l1;j++) {
+ g_hash_table_insert(ht, a1[j], (void *)1);
+ }
+ } else if (r1->type == FSEXP_RES_BOOL) {
+ bool |= r1->value.bool;
+ }
+ filter_sexp_result_free(r1);
+ }
+
+ if (type == FSEXP_RES_ARRAY_PTR) {
+ lambdafoo.count = argc;
+ lambdafoo.uids = g_ptr_array_new();
+ g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htor, &lambdafoo);
+ r->type = FSEXP_RES_ARRAY_PTR;
+ r->value.ptrarray = lambdafoo.uids;
+ } else if (type == FSEXP_RES_BOOL) {
+ r->type = FSEXP_RES_BOOL;
+ r->value.bool = bool;
+ }
+ g_hash_table_destroy(ht);
+
+ return r;
+}
+
+/* this should support all arguments ...? */
+static FilterSEXPResult *
+term_eval_lt(struct _FilterSEXP *f, int argc, struct _FilterSEXPTerm **argv, void *data)
+{
+ struct _FilterSEXPResult *r, *r1, *r2;
+
+ r = filter_sexp_result_new(FSEXP_RES_UNDEFINED);
+
+ if (argc == 2) {
+ r1 = filter_sexp_term_eval(f, argv[0]);
+ r2 = filter_sexp_term_eval(f, argv[1]);
+ if (r1->type != r2->type) {
+ printf("error, invalid types in compare\n");
+ } else if (r1->type == FSEXP_RES_INT) {
+ r->type = FSEXP_RES_BOOL;
+ r->value.bool = r1->value.number < r2->value.number;
+ } else if (r1->type == FSEXP_RES_STRING) {
+ r->type = FSEXP_RES_BOOL;
+ r->value.bool = strcmp(r1->value.string, r2->value.string) < 0;
+ }
+ }
+ return r;
+}
+
+/* this should support all arguments ...? */
+static FilterSEXPResult *
+term_eval_gt(struct _FilterSEXP *f, int argc, struct _FilterSEXPTerm **argv, void *data)
+{
+ struct _FilterSEXPResult *r, *r1, *r2;
+
+ r = filter_sexp_result_new(FSEXP_RES_UNDEFINED);
+
+ if (argc == 2) {
+ r1 = filter_sexp_term_eval(f, argv[0]);
+ r2 = filter_sexp_term_eval(f, argv[1]);
+ if (r1->type != r2->type) {
+ printf("error, invalid types in compare\n");
+ } else if (r1->type == FSEXP_RES_INT) {
+ r->type = FSEXP_RES_BOOL;
+ r->value.bool = r1->value.number > r2->value.number;
+ } else if (r1->type == FSEXP_RES_STRING) {
+ r->type = FSEXP_RES_BOOL;
+ r->value.bool = strcmp(r1->value.string, r2->value.string) > 0;
+ }
+ }
+ return r;
+}
+
+/* this should support all arguments ...? */
+static FilterSEXPResult *
+term_eval_eq(struct _FilterSEXP *f, int argc, struct _FilterSEXPTerm **argv, void *data)
+{
+ struct _FilterSEXPResult *r, *r1, *r2;
+
+ r = filter_sexp_result_new(FSEXP_RES_BOOL);
+
+ if (argc == 2) {
+ r1 = filter_sexp_term_eval(f, argv[0]);
+ r2 = filter_sexp_term_eval(f, argv[1]);
+ if (r1->type != r2->type) {
+ r->value.bool = FALSE;
+ } else if (r1->type == FSEXP_RES_INT) {
+ r->value.bool = r1->value.number == r2->value.number;
+ } else if (r1->type == FSEXP_RES_BOOL) {
+ r->value.bool = r1->value.bool == r2->value.bool;
+ } else if (r1->type == FSEXP_RES_STRING) {
+ r->value.bool = strcmp(r1->value.string, r2->value.string) == 0;
+ }
+ }
+ return r;
+}
+
+static FilterSEXPResult *
+term_eval_plus(struct _FilterSEXP *f, int argc, struct _FilterSEXPResult **argv, void *data)
+{
+ struct _FilterSEXPResult *r=NULL, *r1, *r2;
+ int type;
+ int i;
+
+ if (argc>0) {
+ type = argv[0]->type;
+ switch(type) {
+ case FSEXP_RES_INT: {
+ int total = argv[0]->value.number;
+ for (i=1;i<argc && argv[i]->type == FSEXP_RES_INT;i++) {
+ total += argv[i]->value.number;
+ }
+ if (i<argc) {
+ g_warning("Wrong type trying to add integers: ignored");
+ }
+ r = filter_sexp_result_new(FSEXP_RES_INT);
+ r->value.number = total;
+ break; }
+ case FSEXP_RES_STRING: {
+ GString *s = g_string_new(argv[0]->value.string);
+ for (i=1;i<argc && argv[i]->type == FSEXP_RES_STRING;i++) {
+ g_string_append(s, argv[i]->value.string);
+ }
+ if (i<argc) {
+ g_warning("Wrong type trying to concat strings: ignored");
+ }
+ r = filter_sexp_result_new(FSEXP_RES_STRING);
+ r->value.string = s->str;
+ g_string_free(s, FALSE);
+ break; }
+
+ }
+ }
+
+ if (!r) {
+ r = filter_sexp_result_new(FSEXP_RES_INT);
+ r->value.number = 0;
+ }
+ return r;
+}
+
+static FilterSEXPResult *
+term_eval_sub(struct _FilterSEXP *f, int argc, struct _FilterSEXPResult **argv, void *data)
+{
+ struct _FilterSEXPResult *r=NULL, *r1, *r2;
+ int type;
+ int i;
+
+ if (argc>0) {
+ type = argv[0]->type;
+ switch(type) {
+ case FSEXP_RES_INT: {
+ int total = argv[0]->value.number;
+ for (i=1;i<argc && argv[i]->type == FSEXP_RES_INT;i++) {
+ total -= argv[i]->value.number;
+ }
+ if (i<argc) {
+ g_warning("Wrong type trying to subtract numbers: ignored");
+ }
+ r = filter_sexp_result_new(FSEXP_RES_INT);
+ r->value.number = total;
+ break; }
+ }
+ }
+
+ if (!r) {
+ r = filter_sexp_result_new(FSEXP_RES_INT);
+ r->value.number = 0;
+ }
+ return r;
+}
+
+/* implements 'if' function */
+static FilterSEXPResult *
+term_eval_if(struct _FilterSEXP *f, int argc, struct _FilterSEXPTerm **argv, void *data)
+{
+ struct _FilterSEXPResult *r, *r1, *r2;
+ int doit;
+
+ if (argc >=2 && argc<=3) {
+ r = filter_sexp_term_eval(f, argv[0]);
+ doit = (r->type == FSEXP_RES_BOOL && r->value.bool);
+ filter_sexp_result_free(r);
+ if (doit) {
+ return filter_sexp_term_eval(f, argv[1]);
+ } else if (argc>2) {
+ return filter_sexp_term_eval(f, argv[2]);
+ }
+ }
+ return filter_sexp_result_new(FSEXP_RES_UNDEFINED);
+}
+
+/* implements 'begin' statement */
+static FilterSEXPResult *
+term_eval_begin(struct _FilterSEXP *f, int argc, struct _FilterSEXPTerm **argv, void *data)
+{
+ struct _FilterSEXPResult *r=NULL, *r1, *r2;
+ int i;
+
+ for (i=0;i<argc;i++) {
+ if (r)
+ filter_sexp_result_free(r);
+ r = filter_sexp_term_eval(f, argv[i]);
+ }
+ if (r)
+ return r;
+ else
+ return filter_sexp_result_new(FSEXP_RES_UNDEFINED);
+}
+
+
+struct _FilterSEXPResult *
+filter_sexp_term_eval(struct _FilterSEXP *f, struct _FilterSEXPTerm *t)
+{
+ struct _FilterSEXPResult *r, *r1, *r2;
+ int i;
+
+ r(printf("eval term :\n"));
+ r(parse_dump_term(t, 0));
+
+ r = g_malloc0(sizeof(*r));
+ r->type = FSEXP_RES_UNDEFINED;
+
+ switch (t->type) {
+ case FSEXP_TERM_STRING:
+ r(printf(" (string \"%s\")\n", t->value.string));
+ r->type = FSEXP_RES_STRING;
+ /* erk, this shoul;dn't need to strdup this ... */
+ r->value.string = g_strdup(t->value.string);
+ break;
+ case FSEXP_TERM_INT:
+ r(printf(" (int %d)\n", t->value.number));
+ r->type = FSEXP_RES_INT;
+ r->value.number = t->value.number;
+ break;
+ case FSEXP_TERM_BOOL:
+ r(printf(" (int %d)\n", t->value.number));
+ r->type = FSEXP_RES_BOOL;
+ r->value.bool = t->value.bool;
+ break;
+ case FSEXP_TERM_IFUNC: {
+ if (t->value.func.sym->f.ifunc) {
+ r1 = t->value.func.sym->f.ifunc(f, t->value.func.termcount, t->value.func.terms, t->value.func.sym->data);
+ if (r1) {
+ filter_sexp_result_free(r);
+ r = r1;
+ }
+ }
+ break; }
+ case FSEXP_TERM_FUNC: {
+ struct _FilterSEXPResult **argv;
+
+ /* first evaluate all arguments to result types */
+ argv = alloca(sizeof(argv[0]) * t->value.func.termcount);
+ for (i=0;i<t->value.func.termcount;i++) {
+ argv[i] = filter_sexp_term_eval(f, t->value.func.terms[i]);
+ }
+ /* call the function */
+ if (t->value.func.sym->f.func) {
+ r1 = t->value.func.sym->f.func(f, t->value.func.termcount, argv, t->value.func.sym->data);
+ if (r1) {
+ filter_sexp_result_free(r);
+ r = r1;
+ }
+ }
+ for (i=0;i<t->value.func.termcount;i++) {
+ filter_sexp_result_free(argv[i]);
+ }
+ break; }
+ default:
+ printf("Warning: Unknown type encountered in parse tree: %d\n", t->type);
+ r->type = FSEXP_RES_UNDEFINED;
+ }
+
+ return r;
+}
+
+
+static void
+eval_dump_result(FilterSEXPResult *r, int depth)
+{
+ int dumpvals = FALSE;
+ int i;
+
+ if (r==NULL) {
+ printf("null result???\n");
+ return;
+ }
+
+ for (i=0;i<depth;i++)
+ printf(" ");
+
+ switch (r->type) {
+ case FSEXP_RES_ARRAY_PTR:
+ printf("array pointers\n");
+ break;
+ case FSEXP_RES_INT:
+ printf("int: %d\n", r->value.number);
+ break;
+ case FSEXP_RES_STRING:
+ printf("string: '%s'\n", r->value.string);
+ break;
+ case FSEXP_RES_BOOL:
+ printf("bool: %c\n", r->value.bool?'t':'f');
+ break;
+ case FSEXP_RES_UNDEFINED:
+ printf(" <undefined>\n");
+ break;
+ }
+ printf("\n");
+}
+
+static void
+parse_dump_term(struct _FilterSEXPTerm *t, int depth)
+{
+ int dumpvals = FALSE;
+ int i;
+
+ if (t==NULL) {
+ printf("null term??\n");
+ return;
+ }
+
+ for (i=0;i<depth;i++)
+ printf(" ");
+
+ switch (t->type) {
+ case FSEXP_TERM_STRING:
+ printf(" \"%s\"", t->value.string);
+ break;
+ case FSEXP_TERM_INT:
+ printf(" %d", t->value.number);
+ break;
+ case FSEXP_TERM_BOOL:
+ printf(" #%c", t->value.bool?'t':'f');
+ break;
+ case FSEXP_TERM_IFUNC:
+ case FSEXP_TERM_FUNC:
+ printf(" (function %s\n", t->value.func.sym->name);
+ /*printf(" [%d] ", t->value.func.termcount);*/
+ for (i=0;i<t->value.func.termcount;i++) {
+ parse_dump_term(t->value.func.terms[i], depth+1);
+ }
+ for (i=0;i<depth;i++)
+ printf(" ");
+ printf(" )");
+ break;
+ case FSEXP_TERM_VAR:
+ printf(" (variable %s )\n", t->value.var->name);
+ break;
+ default:
+ printf("unknown type: %d\n", t->type);
+ }
+
+ printf("\n");
+}
+
+/*
+ PARSER
+*/
+
+static struct _FilterSEXPTerm *
+parse_new_term(int type)
+{
+ struct _FilterSEXPTerm *s = g_malloc0(sizeof(*s));
+ s->type = type;
+ return s;
+}
+
+static void
+parse_term_free(struct _FilterSEXPTerm *t)
+{
+ int i;
+
+ if (t==NULL) {
+ return;
+ }
+
+ switch (t->type) {
+ case FSEXP_TERM_FUNC:
+ case FSEXP_TERM_IFUNC:
+ for (i=0;i<t->value.func.termcount;i++) {
+ parse_term_free(t->value.func.terms[i]);
+ }
+ g_free(t->value.func.terms);
+ break;
+ case FSEXP_TERM_VAR:
+ break;
+ case FSEXP_TERM_STRING:
+ g_free(t->value.string);
+ break;
+ case FSEXP_TERM_INT:
+ break;
+ default:
+ printf("parse_term_free: unknown type: %d\n", t->type);
+ }
+ g_free(t);
+}
+
+static struct _FilterSEXPTerm **
+parse_values(FilterSEXP *f, int *len)
+{
+ int token;
+ struct _FilterSEXPTerm **terms;
+ int i=0;
+ GScanner *gs = f->scanner;
+
+ p(printf("parsing values\n"));
+
+ /* FIXME: This hardcoded nonsense!!! :) */
+ terms = g_malloc0(20*sizeof(*terms));
+
+ while ( (token = g_scanner_peek_next_token(gs)) != G_TOKEN_EOF
+ && token != ')') {
+ terms[i]=parse_value(f);
+ i++;
+ }
+
+ p(printf("found %d subterms\n", i));
+ *len = i;
+
+ p(printf("dont parsing values\n"));
+ return terms;
+}
+
+static struct _FilterSEXPTerm *
+parse_value(FilterSEXP *f)
+{
+ int token;
+ struct _FilterSEXPTerm *t = NULL;
+ GScanner *gs = f->scanner;
+ struct _FilterSEXPSymbol *s;
+
+ p(printf("parsing value\n"));
+
+ token = g_scanner_get_next_token(gs);
+ switch(token) {
+ case G_TOKEN_LEFT_PAREN:
+ p(printf("got brace, its a list!\n"));
+ return parse_list(f, TRUE);
+ case G_TOKEN_STRING:
+ p(printf("got string\n"));
+ t = parse_new_term(FSEXP_TERM_STRING);
+ t->value.string = g_strdup(g_scanner_cur_value(gs).v_string);
+ break;
+ case G_TOKEN_INT:
+ t = parse_new_term(FSEXP_TERM_INT);
+ t->value.number = g_scanner_cur_value(gs).v_int;
+ p(printf("got int\n"));
+ break;
+ case '#':
+ printf("got bool?\n");
+ token = g_scanner_get_next_token(gs);
+ t = parse_new_term(FSEXP_TERM_BOOL);
+ t->value.bool = token=='t';
+ break;
+ case G_TOKEN_SYMBOL:
+ s = g_scanner_cur_value(gs).v_symbol;
+ switch (s->type) {
+ case FSEXP_TERM_FUNC:
+ case FSEXP_TERM_IFUNC:
+ /* this is basically invalid, since we can't use function
+ pointers, but let the runtime catch it ... */
+ t = parse_new_term(s->type);
+ t->value.func.sym = s;
+ t->value.func.terms = parse_values(f, &t->value.func.termcount);
+ break;
+ case FSEXP_TERM_VAR:
+ t = parse_new_term(s->type);
+ t->value.var = s;
+ break;
+ default:
+ printf("Invalid symbol type: %d\n", s->type);
+ }
+ break;
+ case G_TOKEN_IDENTIFIER:
+ printf("Unknown identifier encountered: %s\n", g_scanner_cur_value(gs).v_identifier);
+ break;
+ default:
+ printf("Innvalid token trying to parse a list of values\n");
+ }
+ p(printf("done parsing value\n"));
+ return t;
+}
+
+/* FIXME: this needs some robustification */
+static struct _FilterSEXPTerm *
+parse_list(FilterSEXP *f, int gotbrace)
+{
+ int token;
+ struct _FilterSEXPTerm *t = NULL;
+ GScanner *gs = f->scanner;
+
+ p(printf("parsing list\n"));
+ if (gotbrace)
+ token = '(';
+ else
+ token = g_scanner_get_next_token(gs);
+ if (token =='(') {
+ token = g_scanner_get_next_token(gs);
+ switch(token) {
+ case G_TOKEN_SYMBOL: {
+ struct _FilterSEXPSymbol *s;
+
+ s = g_scanner_cur_value(gs).v_symbol;
+ p(printf("got funciton: %s\n", s->name));
+ t = parse_new_term(s->type);
+ p(printf("created new list %p\n", t));
+ /* if we have a variable, find out its base type */
+ while (s->type == FSEXP_TERM_VAR) {
+ s = ((FilterSEXPTerm *)(s->data))->value.var;
+ }
+ if (s->type == FSEXP_TERM_FUNC
+ || s->type == FSEXP_TERM_IFUNC) {
+ t->value.func.sym = s;
+ t->value.func.terms = parse_values(f, &t->value.func.termcount);
+ } else {
+ printf("Error, trying to call variable as function\n");
+ }
+ break; }
+ case G_TOKEN_IDENTIFIER:
+ printf("Unknown identifier: %s\n", g_scanner_cur_value(gs).v_identifier);
+ break;
+ default:
+ printf("unknown sequence encountered, type = %d\n", token);
+ }
+ token = g_scanner_get_next_token(gs);
+ if (token != ')') {
+ printf("Error, expected ')' not found\n");
+ }
+ } else {
+ printf("Error, list term without opening (\n");
+ }
+
+ p(printf("returning list %p\n", t));
+ return t;
+}
+
+#if 0
+GList *
+camel_mbox_folder_search_by_expression(CamelFolder *folder, char *expression, CamelException *ex)
+{
+ GScanner *gs;
+ int i;
+ struct _FilterSEXPTerm *t;
+ struct _searchcontext *ctx;
+ struct _FilterSEXPResult *r;
+ GList *matches = NULL;
+
+ gs = g_scanner_new(&scanner_config);
+ for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++)
+ g_scanner_scope_add_symbol(gs, 0, symbols[i].name, &symbols[i]);
+
+ g_scanner_input_text(gs, expression, strlen(expression));
+ t = parse_list(gs, 0);
+
+ if (t) {
+ ctx = g_malloc0(sizeof(*ctx));
+ ctx->folder = folder;
+ ctx->summary = camel_folder_get_summary(folder, ex);
+ ctx->message_info = camel_folder_summary_get_message_info_list(ctx->summary);
+#ifdef HAVE_IBEX
+ ctx->index = ibex_open(CAMEL_MBOX_FOLDER(folder)->index_file_path, FALSE);
+ if (!ctx->index) {
+ perror("Cannot open index file, body searches will be ignored\n");
+ }
+#endif
+ r = term_eval(ctx, t);
+
+ /* now create a folder summary to return?? */
+ if (r
+ && r->type == FSEXP_RES_ARRAY_PTR) {
+ d(printf("got result ...\n"));
+ for (i=0;i<r->value.ptrarray->len;i++) {
+ d(printf("adding match: %s\n", (char *)g_ptr_array_index(r->value.ptrarray, i)));
+ matches = g_list_prepend(matches, g_strdup(g_ptr_array_index(r->value.ptrarray, i)));
+ }
+ filter_sexp_result_free(r);
+ }
+
+ if (ctx->index)
+ ibex_close(ctx->index);
+
+ gtk_object_unref((GtkObject *)ctx->summary);
+ g_free(ctx);
+ parse_term_free(t);
+ } else {
+ printf("Warning, Could not parse expression!\n %s\n", expression);
+ }
+
+ g_scanner_destroy(gs);
+
+ return matches;
+}
+#endif
+
+
+static void
+filter_sexp_class_init (FilterSEXPClass *class)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *) class;
+ parent_class = gtk_type_class (gtk_object_get_type ());
+}
+
+/* 'builtin' functions */
+static struct {
+ char *name;
+ FilterSEXPFunc *func;
+ int type; /* set to 1 if a function can perform shortcut evaluation, or
+ doesn't execute everything, 0 otherwise */
+} symbols[] = {
+ { "and", (FilterSEXPFunc *)term_eval_and, 1 },
+ { "or", (FilterSEXPFunc *)term_eval_or, 1 },
+ { "<", (FilterSEXPFunc *)term_eval_lt, 1 },
+ { ">", (FilterSEXPFunc *)term_eval_gt, 1 },
+ { "=", (FilterSEXPFunc *)term_eval_eq, 1 },
+ { "+", (FilterSEXPFunc *)term_eval_plus, 0 },
+ { "-", (FilterSEXPFunc *)term_eval_sub, 0 },
+ { "if", (FilterSEXPFunc *)term_eval_if, 1 },
+ { "begin", (FilterSEXPFunc *)term_eval_begin, 1 },
+};
+
+static void
+filter_sexp_init (FilterSEXP *s)
+{
+ int i;
+
+ s->scanner = g_scanner_new(&scanner_config);
+
+ /* load in builtin symbols? */
+ for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++) {
+ if (symbols[i].type == 1) {
+ filter_sexp_add_ifunction(s, 0, symbols[i].name, (FilterSEXPIFunc *)symbols[i].func, &symbols[i]);
+ } else {
+ filter_sexp_add_function(s, 0, symbols[i].name, symbols[i].func, &symbols[i]);
+ }
+ }
+}
+
+guint
+filter_sexp_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterSEXP",
+ sizeof (FilterSEXP),
+ sizeof (FilterSEXPClass),
+ (GtkClassInitFunc) filter_sexp_class_init,
+ (GtkObjectInitFunc) filter_sexp_init,
+ (GtkArgSetFunc) NULL,
+ (GtkArgGetFunc) NULL
+ };
+
+ type = gtk_type_unique (gtk_object_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+FilterSEXP *
+filter_sexp_new (void)
+{
+ FilterSEXP *f = FILTER_SEXP ( gtk_type_new (filter_sexp_get_type ()));
+
+ return f;
+}
+
+void
+filter_sexp_add_function(FilterSEXP *f, int scope, char *name, FilterSEXPFunc *func, void *data)
+{
+ struct _FilterSEXPSymbol *s;
+
+ g_return_if_fail(FILTER_IS_SEXP(f));
+ g_return_if_fail(name != NULL);
+
+ s = g_malloc0(sizeof(*s));
+ s->name = g_strdup(name);
+ s->f.func = func;
+ s->type = FSEXP_TERM_FUNC;
+ s->data = data;
+ g_scanner_scope_add_symbol(f->scanner, scope, s->name, s);
+}
+
+void
+filter_sexp_add_ifunction(FilterSEXP *f, int scope, char *name, FilterSEXPIFunc *ifunc, void *data)
+{
+ struct _FilterSEXPSymbol *s;
+
+ g_return_if_fail(FILTER_IS_SEXP(f));
+ g_return_if_fail(name != NULL);
+
+ s = g_malloc0(sizeof(*s));
+ s->name = g_strdup(name);
+ s->f.ifunc = ifunc;
+ s->type = FSEXP_TERM_IFUNC;
+ s->data = data;
+ g_scanner_scope_add_symbol(f->scanner, scope, s->name, s);
+}
+
+void
+filter_sexp_add_variable(FilterSEXP *f, int scope, char *name, FilterSEXPTerm *value)
+{
+ struct _FilterSEXPSymbol *s;
+
+ g_return_if_fail(FILTER_IS_SEXP(f));
+ g_return_if_fail(name != NULL);
+
+ s = g_malloc0(sizeof(*s));
+ s->name = g_strdup(name);
+ s->type = FSEXP_TERM_VAR;
+ s->data = value;
+ g_scanner_scope_add_symbol(f->scanner, scope, s->name, s);
+}
+
+void
+filter_sexp_remove_symbol(FilterSEXP *f, int scope, char *name)
+{
+ int oldscope;
+ struct _FilterSEXPSymbol *s;
+
+ g_return_if_fail(FILTER_IS_SEXP(f));
+ g_return_if_fail(name != NULL);
+
+ oldscope = g_scanner_set_scope(f->scanner, scope);
+ s = g_scanner_lookup_symbol(f->scanner, name);
+ g_scanner_scope_remove_symbol(f->scanner, scope, name);
+ g_scanner_set_scope(f->scanner, oldscope);
+ if (s) {
+ g_free(s->name);
+ g_free(s);
+ }
+}
+
+int
+filter_sexp_set_scope(FilterSEXP *f, int scope)
+{
+ g_return_val_if_fail(FILTER_IS_SEXP(f), 0);
+
+ return g_scanner_set_scope(f->scanner, scope);
+}
+
+void
+filter_sexp_input_text(FilterSEXP *f, char *text, int len)
+{
+ g_return_if_fail(FILTER_IS_SEXP(f));
+ g_return_if_fail(text != NULL);
+
+ g_scanner_input_text(f->scanner, text, len);
+}
+
+void
+filter_sexp_input_file (FilterSEXP *f, int fd)
+{
+ g_return_if_fail(FILTER_IS_SEXP(f));
+
+ g_scanner_input_file(f->scanner, fd);
+}
+
+/* needs some error return? */
+void
+filter_sexp_parse(FilterSEXP *f)
+{
+ g_return_if_fail(FILTER_IS_SEXP(f));
+
+ f->tree = parse_list(f, FALSE);
+
+ if (f->tree)
+ parse_dump_term(f->tree, 0);
+}
+
+struct _FilterSEXPResult *
+filter_sexp_eval(FilterSEXP *f)
+{
+ g_return_val_if_fail(FILTER_IS_SEXP(f), NULL);
+ g_return_val_if_fail(f->tree != NULL, NULL);
+
+ return filter_sexp_term_eval(f, f->tree);
+}
+
+#ifdef TESTER
+int main(int argc, char **argv)
+{
+ FilterSEXP *f;
+ char *t = "(+ \"foo\" \"\\\"\" \"bar\" \"\\\\ blah \\x \")";
+ FilterSEXPResult *r;
+
+ gtk_init(&argc, &argv);
+
+ f = filter_sexp_new();
+
+ filter_sexp_add_variable(f, 0, "test", NULL);
+
+ filter_sexp_input_text(f, t, strlen(t));
+ filter_sexp_parse(f);
+
+ if (f->tree) {
+ parse_dump_term(f->tree, 0);
+ }
+
+ r = filter_sexp_eval(f);
+ if (r) {
+ eval_dump_result(r, 0);
+ } else {
+ printf("no result?|\n");
+ }
+
+ return 0;
+}
+#endif
diff --git a/filter/filter-sexp.h b/filter/filter-sexp.h
new file mode 100644
index 0000000000..362b7261f9
--- /dev/null
+++ b/filter/filter-sexp.h
@@ -0,0 +1,117 @@
+/*
+ generic s-exp evaluator class
+*/
+#ifndef _FILTER_SEXP_H
+#define _FILTER_SEXP_H
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gtkhtml/gtkhtml.h>
+#include <gnome-xml/tree.h>
+
+#define FILTER_SEXP(obj) GTK_CHECK_CAST (obj, filter_sexp_get_type (), FilterSEXP)
+#define FILTER_SEXP_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_sexp_get_type (), FilterSEXPClass)
+#define FILTER_IS_SEXP(obj) GTK_CHECK_TYPE (obj, filter_sexp_get_type ())
+
+typedef struct _FilterSEXP FilterSEXP;
+typedef struct _FilterSEXPClass FilterSEXPClass;
+
+typedef struct _FilterSEXPSymbol FilterSEXPSymbol;
+typedef struct _FilterSEXPResult FilterSEXPResult;
+typedef struct _FilterSEXPTerm FilterSEXPTerm;
+
+typedef struct _FilterSEXPResult *(FilterSEXPFunc)(struct _FilterSEXP *sexp,
+ int argc,
+ struct _FilterSEXPResult **argv,
+ void *data);
+
+typedef struct _FilterSEXPResult *(FilterSEXPIFunc)(struct _FilterSEXP *sexp,
+ int argc,
+ struct _FilterSEXPTerm **argv,
+ void *data);
+enum _FilterSEXPResultType {
+ FSEXP_RES_ARRAY_PTR=0, /* type is a ptrarray, what it points to is implementation dependant */
+ FSEXP_RES_INT, /* type is a number */
+ FSEXP_RES_STRING, /* type is a pointer to a single string */
+ FSEXP_RES_BOOL, /* boolean type */
+ FSEXP_RES_UNDEFINED /* unknown type */
+};
+
+struct _FilterSEXPResult {
+ enum _FilterSEXPResultType type;
+ union {
+ GPtrArray *ptrarray;
+ int number;
+ char *string;
+ int bool;
+ } value;
+};
+
+enum _FilterSEXPTermType {
+ FSEXP_TERM_INT = 0, /* integer literal */
+ FSEXP_TERM_BOOL, /* boolean literal */
+ FSEXP_TERM_STRING, /* string literal */
+ FSEXP_TERM_FUNC, /* normal function, arguments are evaluated before calling */
+ FSEXP_TERM_IFUNC, /* immediate function, raw terms are arguments */
+ FSEXP_TERM_VAR, /* variable reference */
+};
+
+struct _FilterSEXPSymbol {
+ int type; /* FSEXP_TERM_FUNC or FSEXP_TERM_VAR */
+ char *name;
+ void *data;
+ union {
+ FilterSEXPFunc *func;
+ FilterSEXPIFunc *ifunc;
+ } f;
+};
+
+struct _FilterSEXPTerm {
+ enum _FilterSEXPTermType type;
+ union {
+ char *string;
+ int number;
+ int bool;
+ struct {
+ struct _FilterSEXPSymbol *sym;
+ struct _FilterSEXPTerm **terms;
+ int termcount;
+ } func;
+ struct _FilterSEXPSymbol *var;
+ } value;
+};
+
+
+
+struct _FilterSEXP {
+ GtkObject object;
+
+ GScanner *scanner; /* for parsing text version */
+ FilterSEXPTerm *tree; /* root of expression tree */
+};
+
+struct _FilterSEXPClass {
+ GtkObjectClass parent_class;
+
+};
+
+guint filter_sexp_get_type (void);
+FilterSEXP *filter_sexp_new (void);
+void filter_sexp_add_function (FilterSEXP *f, int scope, char *name, FilterSEXPFunc *func, void *data);
+void filter_sexp_add_ifunction (FilterSEXP *f, int scope, char *name, FilterSEXPIFunc *func, void *data);
+void filter_sexp_add_variable (FilterSEXP *f, int scope, char *name, FilterSEXPTerm *value);
+void filter_sexp_remove_symbol (FilterSEXP *f, int scope, char *name);
+int filter_sexp_set_scope (FilterSEXP *f, int scope);
+
+void filter_sexp_input_text (FilterSEXP *f, char *text, int len);
+void filter_sexp_input_file (FilterSEXP *f, int fd);
+
+
+void filter_sexp_parse (FilterSEXP *f);
+FilterSEXPResult *filter_sexp_eval (FilterSEXP *f);
+
+FilterSEXPResult *filter_sexp_term_eval (struct _FilterSEXP *f, struct _FilterSEXPTerm *t);
+FilterSEXPResult *filter_sexp_result_new (int type);
+void filter_sexp_result_free (struct _FilterSEXPResult *t);
+
+#endif /* _FILTER_SEXP_H */
diff --git a/filter/filter-xml.c b/filter/filter-xml.c
new file mode 100644
index 0000000000..de86749db9
--- /dev/null
+++ b/filter/filter-xml.c
@@ -0,0 +1,658 @@
+/* -*- Mode: C; c-file-style: "linux"; indent-tabs-mode: t; c-basic-offset: 8; -*- */
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gnome.h>
+#include <gtkhtml/gtkhtml.h>
+
+#include <gnome-xml/tree.h>
+#include <gnome-xml/parser.h>
+
+#include "filter-arg-types.h"
+#include "filter-xml.h"
+
+struct token_tab {
+ char *name;
+ enum filter_xml_token token;
+};
+
+struct token_tab token_table[] = {
+ { "action", FILTER_XML_ACTION },
+ { "address", FILTER_XML_ADDRESS },
+ { "code", FILTER_XML_CODE },
+ { "description", FILTER_XML_DESC },
+ { "except", FILTER_XML_EXCEPT },
+ { "folder", FILTER_XML_FOLDER },
+ { "match", FILTER_XML_MATCH },
+ { "name", FILTER_XML_NAME },
+ { "option", FILTER_XML_OPTION },
+ { "optionrule", FILTER_XML_OPTIONRULE },
+ { "optionset", FILTER_XML_OPTIONSET },
+ { "optionvalue", FILTER_XML_OPTIONVALUE },
+ { "receive", FILTER_XML_RECEIVE },
+ { "rule", FILTER_XML_RULE },
+ { "ruleset", FILTER_XML_RULESET },
+ { "send", FILTER_XML_SEND },
+ { "source", FILTER_XML_SOURCE },
+ { "text", FILTER_XML_TEXT },
+};
+
+/* convert a name to a token value */
+static int
+tokenise(const char *name)
+{
+ int i;
+ int len = sizeof(token_table)/sizeof(token_table[0]);
+
+ if (name) {
+ for (i=0;i<len;i++) {
+ if (strcmp(name, token_table[i].name) == 0)
+ return token_table[i].token;
+ }
+ }
+ return -1;
+}
+
+static char *
+detokenise(int token)
+{
+ int i;
+ int len = sizeof(token_table)/sizeof(token_table[0]);
+
+ if (token>=0) {
+ for (i=0;i<len;i++) {
+ if (token_table[i].token == token)
+ return token_table[i].name;
+ }
+ }
+ return "<unknown>";
+}
+
+
+xmlNodePtr find_node(xmlNodePtr start, char *name)
+{
+ printf("trying to find node '%s'\n", name);
+ while (start && strcmp(start->name, name))
+ start = start->next;
+ printf("node = %p\n", start);
+ return start;
+}
+
+xmlNodePtr find_node_attr(xmlNodePtr start, char *name, char *attrname, char *attrvalue)
+{
+ xmlNodePtr node;
+ char *s;
+
+ printf("looking for node named %s with attribute %s=%s\n", name, attrname, attrvalue);
+
+ while ( start && (start = find_node(start, name)) ) {
+ s = xmlGetProp(start, attrname);
+ printf(" comparing '%s' to '%s'\n", s, attrvalue);
+ if (s && !strcmp(s, attrvalue))
+ break;
+ start = start->next;
+ }
+ return start;
+}
+
+static int
+find_arg(FilterArg *a, char *name)
+{
+ printf("finding, is %s = %s?\n", a->name, name);
+ return strcmp(a->name, name);
+}
+
+static int
+find_rule(struct filter_rule *a, char *name)
+{
+ printf("finding, is %s = %s?\n", a->name, name);
+ return strcmp(a->name, name);
+}
+
+static int display_order[] = { FILTER_XML_MATCH, FILTER_XML_ACTION, FILTER_XML_EXCEPT };
+
+static struct filter_option *
+option_clone(struct filter_option *source)
+{
+ struct filter_option *dest = g_malloc0(sizeof(*dest));
+ GList *loptions;
+ struct filter_optionrule *old, *new;
+
+ dest->type = source->type;
+ dest->description = source->description;
+ loptions = dest->options;
+ while (loptions) {
+ old = loptions->data;
+ new = g_malloc0(sizeof(*new));
+ new->rule = old->rule;
+ /* FIXME: need to copy any args as well!!! */
+ dest->options = g_list_append(dest->options, new);
+ loptions = g_list_next(loptions);
+ }
+ return dest;
+}
+
+
+
+struct description_decode_lambda {
+ GString *str;
+ GList *args;
+ GtkHTML *html;
+ GtkHTMLStreamHandle *stream;
+};
+
+static char *
+arg_text(FilterArg *arg)
+{
+ char *out = NULL;
+ GList *value, *next;
+ GString *str;
+
+ value = arg->values;
+
+ if (value == NULL)
+ return NULL;
+
+ str = g_string_new("");
+ filter_arg_write_text(arg, str);
+ out = str->str;
+ g_string_free(str, FALSE);
+ return out;
+}
+
+static void
+description_decode_text(struct filter_desc *d, struct description_decode_lambda *l)
+{
+ GList *list;
+ char *txt;
+
+ switch (d->type) {
+ case FILTER_XML_TEXT:
+ case FILTER_XML_DESC:
+ dotext:
+ printf("appending '%s'\n", d->data);
+ printf("vartype = %s\n", detokenise(d->vartype));
+ printf("varname = %s\n", d->varname);
+ if (d->vartype !=-1 && d->varname
+ && (list = g_list_find_custom(l->args, d->varname, (GCompareFunc) find_arg))
+ && (txt = arg_text(list->data))) {
+ } else {
+ txt = d->data;
+ }
+ g_string_append(l->str, txt);
+ break;
+ default:
+ printf("WARN: unknown desc text type '%s' = %s\n", detokenise(d->type), d->data);
+ goto dotext;
+ }
+}
+
+static char *
+description_text(GList *description, GList *args)
+{
+ char *txt;
+ struct description_decode_lambda l;
+
+ printf("\ndecoding ...\n");
+
+ l.str = g_string_new("");
+ l.args = args;
+ g_list_foreach(description, (GFunc) description_decode_text, &l);
+
+ printf("string is '%s'\n", l.str->str);
+
+ txt = l.str->str;
+ g_string_free(l.str, FALSE);
+
+ return txt;
+}
+
+static void
+html_write(GtkHTML *html, GtkHTMLStreamHandle *stream, char *s)
+{
+ printf("appending html '%s'\n", s);
+ gtk_html_write(html, stream, s, strlen(s));
+}
+
+
+static void
+description_decode_html(struct filter_desc *d, struct description_decode_lambda *l)
+{
+ GList *list;
+ char *txt, *end;
+ int free;
+
+ switch (d->type) {
+ case FILTER_XML_TEXT:
+ case FILTER_XML_DESC:
+ dotext:
+ printf("appending '%s'\n", d->data);
+ printf("vartype = %s\n", detokenise(d->vartype));
+ printf("varname = %s\n", d->varname);
+ free = FALSE;
+ if (d->vartype !=-1 && d->varname) {
+ char *link;
+ list = g_list_find_custom(l->args, d->varname, (GCompareFunc) find_arg);
+ end = "</a>";
+ if (list) {
+ txt = arg_text(list->data);
+ if (txt == NULL)
+ txt = d->data;
+ else
+ free = TRUE;
+ link = g_strdup_printf("<a href=\"arg:%p %p\">", d, list->data);
+ } else {
+ printf("cannot find arg '%s'\n", d->varname);
+ link = g_strdup_printf("<a href=\"arg:%p %p\">", d, NULL);
+ txt = d->data;
+ }
+ html_write(l->html, l->stream, link);
+ g_free(link);
+ } else {
+ txt = d->data;
+ end = NULL;
+ }
+ html_write(l->html, l->stream, txt);
+ if (end) {
+ html_write(l->html, l->stream, end);
+ }
+ if (free)
+ g_free(txt);
+ break;
+ default:
+ printf("WARN: unknown desc text type '%s' = %s\n", detokenise(d->type), d->data);
+ goto dotext;
+ }
+}
+
+static void
+description_html_write(GList *description, GList *args, GtkHTML *html, GtkHTMLStreamHandle *stream)
+{
+ char *txt;
+ struct description_decode_lambda l;
+
+ printf("\ndecoding ...\n");
+
+ l.str = NULL;
+ l.args = args;
+ l.html = html;
+ l.stream = stream;
+ g_list_foreach(description, (GFunc) description_decode_html, &l);
+}
+
+
+static GList *
+load_desc(xmlNodePtr node, int type, int vartype, char *varname)
+{
+ struct filter_desc *desc;
+ xmlNodePtr n;
+ int newtype;
+ int newvartype;
+ char *newvarname;
+ GList *list = NULL;
+
+ while (node) {
+ if (node->content) {
+ desc = g_malloc0(sizeof(*desc));
+ desc->data = node->content;
+ desc->type = type;
+ desc->vartype = vartype;
+ desc->varname = varname?g_strdup(varname):0;
+ printf(" **** node name = %s var name = %s var type = %s\n", node->name, varname, detokenise(vartype));
+ list = g_list_append(list, desc);
+ printf("appending '%s'\n", node->content);
+ newtype = type;
+ newvartype = -1;
+ newvarname = NULL;
+ } else {
+ newtype = tokenise(node->name);
+ newvartype = tokenise(xmlGetProp(node, "type"));
+ newvarname = xmlGetProp(node, "name");
+ }
+ n = node->childs;
+ while (n) {
+ printf("adding child '%s'\n", n->name);
+ list = g_list_concat(list, load_desc(n, newtype, newvartype, newvarname));
+ n = n->next;
+ }
+ node = node->next;
+ }
+ return list;
+}
+
+GList *
+load_ruleset(xmlDocPtr doc)
+{
+ xmlNodePtr ruleset, rule, n;
+ struct filter_rule *r;
+ int type;
+ int ruletype;
+ GList *rules = NULL;
+
+ g_return_val_if_fail(doc!=NULL, NULL);
+
+ ruleset = find_node(doc->root->childs, "ruleset");
+
+ while (ruleset) {
+
+ rule = ruleset->childs;
+
+ ruletype = tokenise(xmlGetProp(ruleset, "type"));
+
+ printf("ruleset, name = %s\n", ruleset->name);
+
+ while (rule) {
+
+ n = rule->childs;
+ r = g_malloc0(sizeof(*r));
+ r->type = ruletype;
+ r->name = xmlGetProp(rule, "name");
+
+ printf(" rule, name = %s\n", r->name);
+
+ while (n) {
+ type = tokenise(n->name);
+ printf(" n, name = %s\n", n->name);
+ printf(" ncontent = %s\n", n->content);
+ printf(" childs = %p\n", n->childs);
+ if (n->childs) {
+ printf(" childs content = %s\n", n->childs->content);
+ }
+ switch(type) {
+ case FILTER_XML_CODE:
+ r->code = xmlNodeGetContent(n);
+ break;
+ case FILTER_XML_DESC:
+ printf(" ** loading description\n");
+ r->description = load_desc(n->childs, type, -1, NULL);
+ printf(" ** done loading description\n");
+ description_text(r->description, 0);
+ printf(" ** done dumping description\n");
+ break;
+ default:
+ printf("warning, unknown token encountered\n");
+ break;
+ }
+ n = n->next;
+ }
+ if (r)
+ rules = g_list_append(rules, r);
+ rule = rule->next;
+ }
+ ruleset = find_node(ruleset->next, "ruleset");
+ }
+ return rules;
+}
+
+int
+filter_find_rule(struct filter_rule *a, char *name)
+{
+ printf("finding, is %s = %s?\n", a->name, name);
+ return strcmp(a->name, name);
+}
+
+int
+filter_find_arg(FilterArg *a, char *name)
+{
+ printf("finding, is %s = %s?\n", a->name, name);
+ return strcmp(a->name, name);
+}
+
+static FilterArg *
+load_optionvalue(struct filter_desc *desc, xmlNodePtr node)
+{
+ xmlNodePtr n;
+ int token;
+ int lasttoken = -2;
+ FilterArg *arg = NULL;
+ char *name;
+
+ printf("creating arg entry for '%s'\n", desc->varname);
+
+ switch(desc->vartype) {
+ case FILTER_XML_ADDRESS:
+ arg = filter_arg_address_new(name);
+ break;
+ case FILTER_XML_FOLDER:
+ arg = filter_arg_folder_new(name);
+ break;
+ default:
+ printf("ok, maybe we're not\n");
+ /* unknown arg type, drop it */
+ return NULL;
+ }
+
+ if (node == NULL)
+ return arg;
+
+ filter_arg_values_add_xml(arg, node);
+
+ return arg;
+}
+
+/* loads a blank (empty args) optionrule from a rule */
+static struct filter_optionrule *
+optionrule_new(struct filter_rule *rule)
+{
+ GList *ldesc;
+ struct filter_desc *desc;
+ struct filter_optionrule *optionrule;
+
+ optionrule = g_malloc0(sizeof(*optionrule));
+ optionrule->rule = rule;
+
+ ldesc = rule->description;
+ while (ldesc) {
+ desc = ldesc->data;
+ if (desc->varname && desc->vartype!=-1) {
+ FilterArg *arg;
+ arg = load_optionvalue(desc, NULL);
+ if (arg)
+ optionrule->args = g_list_append(optionrule->args, arg);
+ }
+ ldesc = g_list_next(ldesc);
+ }
+ return optionrule;
+}
+
+GList *
+load_optionset(xmlDocPtr doc, GList *rules)
+{
+ xmlNodePtr optionset, option, o, or;
+ struct filter_option *op;
+ struct filter_optionrule *optionrule;
+ struct filter_rule *fr;
+ struct filter_desc *desc;
+ int type, token;
+ GList *l = NULL;
+ GList *lrule;
+ GList *ldesc;
+
+ g_return_val_if_fail(doc!=NULL, NULL);
+
+ optionset = find_node(doc->root->childs, "optionset");
+ if (optionset == NULL) {
+ printf("optionset not found\n");
+ return;
+ }
+ option = find_node(optionset->childs, "option");
+ while (option) {
+ o = option->childs;
+ op = g_malloc0(sizeof(*op));
+ printf("option = %s\n", o->name);
+ printf("option, type=%s\n", xmlGetProp(option, "type"));
+ op->type = tokenise(xmlGetProp(option, "type"));
+ while (o) {
+ type = tokenise(o->name);
+ switch (type) {
+ case FILTER_XML_OPTIONRULE:
+ lrule = g_list_find_custom(rules, xmlGetProp(o, "rule"), (GCompareFunc) filter_find_rule);
+ if (lrule) {
+ fr = lrule->data;
+ printf("found rule : %s\n", fr->name);
+ optionrule = g_malloc0(sizeof(*optionrule));
+ optionrule->rule = fr;
+ op->options = g_list_append(op->options, optionrule);
+
+ /* scan through all variables required, setup blank variables if they do not exist */
+ ldesc = fr->description;
+ while (ldesc) {
+ desc = ldesc->data;
+ if (desc->varname && desc->vartype!=-1) {
+ FilterArg *arg;
+ /* try and see if there is a setting for this value */
+ or = find_node_attr(o->childs, "optionvalue", "name", desc->varname);
+ arg = load_optionvalue(desc, or);
+ if (arg)
+ optionrule->args = g_list_append(optionrule->args, arg);
+ }
+ ldesc = g_list_next(ldesc);
+ }
+ } else {
+ printf("Cannot find rule: %s\n", xmlGetProp(o, "rule"));
+ }
+ break;
+ case FILTER_XML_DESC:
+ printf("loading option descriptiong\n");
+ op->description = load_desc(option->childs, type, -1, NULL);
+ break;
+ }
+ o = o->next;
+ }
+ l = g_list_append(l, op);
+ option = find_node(option->next, "option");
+ }
+ return l;
+}
+
+static xmlNodePtr
+save_optionset(xmlDocPtr doc, GList *optionl)
+{
+ xmlNodePtr root, cur, option, optionrule, optionvalue;
+ GList *optionrulel, *argl;
+ struct filter_optionrule *or;
+
+ root = xmlNewDocNode(doc, NULL, "optionset", NULL);
+
+ /* for all options */
+ while (optionl) {
+ struct filter_option *op = optionl->data;
+
+ option = xmlNewDocNode(doc, NULL, "option", NULL);
+ xmlSetProp(option, "type", detokenise(op->type));
+
+ optionrulel = op->options;
+ while (optionrulel) {
+ or = optionrulel->data;
+
+ optionrule = xmlNewDocNode(doc, NULL, "optionrule", NULL);
+ xmlSetProp(optionrule, "type", detokenise(or->rule->type));
+ xmlSetProp(optionrule, "rule", or->rule->name);
+
+ argl = or->args;
+ while (argl) {
+ FilterArg *arg = argl->data;
+
+ optionvalue = filter_arg_values_get_xml(arg);
+ if (optionvalue)
+ xmlAddChild(optionrule, optionvalue);
+
+ argl = g_list_next(argl);
+ }
+
+ xmlAddChild(option, optionrule);
+
+ optionrulel = g_list_next(optionrulel);
+ }
+
+ xmlAddChild(root, option);
+ optionl = g_list_next(optionl);
+ }
+
+ return root;
+}
+
+
+
+/*
+ build an expression for the filter
+*/
+static void
+filterme(struct filter_option *op)
+{
+ GList *optionl;
+ GString *s;
+
+ s = g_string_new("(if (and ");
+ optionl = op->options;
+ while (optionl) {
+ struct filter_optionrule *or = optionl->data;
+ if (or->rule->type == FILTER_XML_MATCH) {
+ g_string_append(s, "(match \"");
+ g_string_append(s, or->rule->name);
+ g_string_append(s, "\" ");
+ g_string_append(s, or->rule->code);
+ g_string_append(s, ") ");
+ }
+ optionl = g_list_next(optionl);
+ }
+ optionl = op->options;
+ while (optionl) {
+ struct filter_optionrule *or = optionl->data;
+ if (or->rule->type == FILTER_XML_EXCEPT) {
+ g_string_append(s, " (except \"");
+ g_string_append(s, or->rule->name);
+ g_string_append(s, "\" ");
+ g_string_append(s, or->rule->code);
+ g_string_append(s, " ) ");
+ }
+ optionl = g_list_next(optionl);
+ }
+ g_string_append(s, ") (begin ");
+ optionl = op->options;
+ while (optionl) {
+ struct filter_optionrule *or = optionl->data;
+ if (or->rule->type == FILTER_XML_ACTION) {
+ g_string_append(s, or->rule->code);
+ g_string_append(s, " ");
+ }
+ optionl = g_list_next(optionl);
+ }
+ g_string_append(s, "))");
+ printf("combined rule '%s'\n", s->str);
+}
+
+#ifdef TESTER
+int main(int argc, char **argv)
+{
+ GList *rules, *options;
+ xmlDocPtr doc, out, optionset, filteroptions;
+
+ gnome_init("Test", "0.0", argc, argv);
+
+ doc = xmlParseFile("filterdescription.xml");
+
+ rules = load_ruleset(doc);
+ options = load_optionset(doc, rules);
+
+ out = xmlParseFile("saveoptions.xml");
+ options = load_optionset(doc, rules);
+
+ while (options) {
+ printf("applying a rule ...\n");
+ filterme(options->data);
+ options = g_list_next(options);
+ }
+
+#if 0
+ out = xmlNewDoc("1.0");
+ optionset = save_optionset(out, options);
+ filteroptions = xmlNewDocNode(out, NULL, "filteroptions", NULL);
+ xmlAddChild(filteroptions, optionset);
+ xmlDocSetRootElement(out, filteroptions);
+ xmlSaveFile("saveoptions.xml", out);
+#endif
+ return 0;
+}
+#endif
+
diff --git a/filter/filter-xml.h b/filter/filter-xml.h
new file mode 100644
index 0000000000..a56b4baa2e
--- /dev/null
+++ b/filter/filter-xml.h
@@ -0,0 +1,51 @@
+
+#ifndef _FILTER_XML_H
+#define _FILTER_XML_H
+
+enum filter_xml_token {
+ FILTER_XML_TEXT=0,
+ FILTER_XML_RULE,
+ FILTER_XML_CODE,
+ FILTER_XML_DESC,
+ FILTER_XML_RULESET,
+ FILTER_XML_OPTION,
+ FILTER_XML_OPTIONRULE,
+ FILTER_XML_OPTIONSET,
+ FILTER_XML_OPTIONVALUE,
+ FILTER_XML_SOURCE,
+ FILTER_XML_SEND,
+ FILTER_XML_RECEIVE,
+ FILTER_XML_ADDRESS,
+ FILTER_XML_FOLDER,
+ FILTER_XML_NAME,
+ FILTER_XML_MATCH,
+ FILTER_XML_ACTION,
+ FILTER_XML_EXCEPT
+};
+
+struct filter_desc {
+ int type;
+ char *data;
+ char *varname; /* for named types */
+ int vartype;
+};
+
+struct filter_rule {
+ int type;
+ char *name;
+ char *code;
+ GList *description;
+};
+
+struct filter_optionrule {
+ struct filter_rule *rule;
+ GList *args; /* FilterArg objects */
+};
+
+struct filter_option {
+ int type; /* 'send' 'receive'? */
+ GList *description; /* filter_desc */
+ GList *options; /* option_rule */
+};
+
+#endif /* ! _FILTER_XML_H */