diff options
-rw-r--r-- | filter/ChangeLog | 4 | ||||
-rw-r--r-- | filter/Makefile | 11 | ||||
-rw-r--r-- | filter/filter-arg-types.c | 393 | ||||
-rw-r--r-- | filter/filter-arg-types.h | 75 | ||||
-rw-r--r-- | filter/filter-arg.c | 217 | ||||
-rw-r--r-- | filter/filter-arg.h | 72 | ||||
-rw-r--r-- | filter/filter-driver.c | 176 | ||||
-rw-r--r-- | filter/filter-sexp.c | 1073 | ||||
-rw-r--r-- | filter/filter-sexp.h | 117 | ||||
-rw-r--r-- | filter/filter-xml.c | 658 | ||||
-rw-r--r-- | filter/filter-xml.h | 51 |
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 */ |