aboutsummaryrefslogtreecommitdiffstats
path: root/filter
diff options
context:
space:
mode:
authorNot Zed <NotZed@HelixCode.com>2000-07-30 11:23:41 +0800
committerMichael Zucci <zucchi@src.gnome.org>2000-07-30 11:23:41 +0800
commita44d1c188b0bc166e5966ae3854a1c0bc8c44afd (patch)
treedf30c85510f2b55384f95f184ae4768eedc0bac7 /filter
parent4f1ecbb64b04048e1765f25e65799830316021d1 (diff)
downloadgsoc2013-evolution-a44d1c188b0bc166e5966ae3854a1c0bc8c44afd.tar.gz
gsoc2013-evolution-a44d1c188b0bc166e5966ae3854a1c0bc8c44afd.tar.zst
gsoc2013-evolution-a44d1c188b0bc166e5966ae3854a1c0bc8c44afd.zip
** Almost a total rewrite of every file, except for filter-driver which
2000-07-30 Not Zed <NotZed@HelixCode.com> ** Almost a total rewrite of every file, except for filter-driver which just had minor updates. The rule format has changed. svn path=/trunk/; revision=4418
Diffstat (limited to 'filter')
-rw-r--r--filter/ChangeLog7
-rw-r--r--filter/Makefile.am51
-rwxr-xr-xfilter/blank.xpm22
-rwxr-xr-xfilter/check.xpm22
-rw-r--r--filter/filter-arg-types.c788
-rw-r--r--filter/filter-arg-types.h101
-rw-r--r--filter/filter-arg.c541
-rw-r--r--filter/filter-arg.h92
-rw-r--r--filter/filter-code.c121
-rw-r--r--filter/filter-code.h53
-rw-r--r--filter/filter-colour.c220
-rw-r--r--filter/filter-colour.h55
-rw-r--r--filter/filter-context.c138
-rw-r--r--filter/filter-context.h59
-rw-r--r--filter/filter-driver.c194
-rw-r--r--filter/filter-driver.h12
-rw-r--r--filter/filter-druid.c728
-rw-r--r--filter/filter-druid.h76
-rw-r--r--filter/filter-editor.c541
-rw-r--r--filter/filter-editor.h37
-rw-r--r--filter/filter-element.c264
-rw-r--r--filter/filter-element.h77
-rw-r--r--filter/filter-filter.c411
-rw-r--r--filter/filter-filter.h60
-rw-r--r--filter/filter-folder.c269
-rw-r--r--filter/filter-folder.h56
-rw-r--r--filter/filter-format.c196
-rw-r--r--filter/filter-format.h11
-rw-r--r--filter/filter-input.c246
-rw-r--r--filter/filter-input.h59
-rw-r--r--filter/filter-option.c304
-rw-r--r--filter/filter-option.h63
-rw-r--r--filter/filter-part.c432
-rw-r--r--filter/filter-part.h75
-rw-r--r--filter/filter-rule.c525
-rw-r--r--filter/filter-rule.h88
-rw-r--r--filter/filter-xml.c591
-rw-r--r--filter/filter-xml.h78
-rw-r--r--filter/filter.glade383
-rw-r--r--filter/filtertypes.xml209
-rw-r--r--filter/rule-context.c349
-rw-r--r--filter/rule-context.h111
-rw-r--r--filter/score-context.c100
-rw-r--r--filter/score-context.h53
-rw-r--r--filter/score-editor.c311
-rw-r--r--filter/score-editor.h59
-rw-r--r--filter/score-rule.c190
-rw-r--r--filter/score-rule.h56
-rw-r--r--filter/vfolder-context.c115
-rw-r--r--filter/vfolder-context.h55
-rw-r--r--filter/vfolder-editor.c336
-rw-r--r--filter/vfolder-editor.h61
-rw-r--r--filter/vfoldertypes.xml148
53 files changed, 6294 insertions, 3905 deletions
diff --git a/filter/ChangeLog b/filter/ChangeLog
index 093a092723..c2008adab9 100644
--- a/filter/ChangeLog
+++ b/filter/ChangeLog
@@ -1,3 +1,10 @@
+2000-07-30 Not Zed <NotZed@HelixCode.com>
+
+ ** Almost a total rewrite of every file, except for filter-driver
+ which just had minor updates.
+
+ The rule format has changed.
+
2000-07-24 Dan Winship <danw@helixcode.com>
* filter-driver.c (do_delete, filter_driver_run): Update for
diff --git a/filter/Makefile.am b/filter/Makefile.am
index 2362e42c82..f6b31dcfc8 100644
--- a/filter/Makefile.am
+++ b/filter/Makefile.am
@@ -1,3 +1,7 @@
+
+gladedir = $(prefix)/share/evolution/glade
+glade_DATA = filter.glade
+
INCLUDES = \
-I $(top_srcdir) \
-I $(top_srcdir)/libibex \
@@ -8,6 +12,7 @@ INCLUDES = \
-I $(top_builddir)/shell \
-I $(GNOME_INCLUDEDIR) \
$(GTKHTML_CFLAGS) \
+ -DFILTER_GLADEDIR=\"$(gladedir)\" \
-DG_LOG_DOMAIN=\"filter\"
##
@@ -15,20 +20,42 @@ noinst_LTLIBRARIES = \
libfilter.la
libfilter_la_SOURCES = \
- filter-arg-types.c \
- filter-arg-types.h \
- filter-arg.c \
- filter-arg.h \
- filter-xml.c \
- filter-xml.h \
- filter-format.c \
- filter-format.h \
- filter-druid.c \
- filter-druid.h \
+ filter-code.c \
+ filter-code.h \
+ filter-colour.c \
+ filter-colour.h \
+ filter-context.c \
+ filter-context.h \
+ filter-driver.c \
+ filter-driver.h \
filter-editor.c \
filter-editor.h \
- filter-driver.c \
- filter-driver.h
+ filter-element.c \
+ filter-element.h \
+ filter-filter.c \
+ filter-filter.h \
+ filter-folder.c \
+ filter-folder.h \
+ filter-input.c \
+ filter-input.h \
+ filter-option.c \
+ filter-option.h \
+ filter-part.c \
+ filter-part.h \
+ filter-rule.c \
+ filter-rule.h \
+ rule-context.c \
+ rule-context.h \
+ score-context.c \
+ score-context.h \
+ score-editor.c \
+ score-editor.h \
+ score-rule.c \
+ score-rule.h \
+ vfolder-context.c \
+ vfolder-context.h \
+ vfolder-editor.c \
+ vfolder-editor.h
EXTRA_DIST = blank.xpm check.xpm \
filtertypes.xml vfoldertypes.xml
diff --git a/filter/blank.xpm b/filter/blank.xpm
deleted file mode 100755
index 499f7a04fc..0000000000
--- a/filter/blank.xpm
+++ /dev/null
@@ -1,22 +0,0 @@
-/* XPM */
-static char * blank_xpm[] = {
-"16 16 3 1",
-" c None",
-". c #000000",
-"+ c #FFFFFF",
-" ",
-" .............. ",
-" .++++++++++++. ",
-" .++++++++++++. ",
-" .++++++++++++. ",
-" .++++++++++++. ",
-" .++++++++++++. ",
-" .++++++++++++. ",
-" .++++++++++++. ",
-" .++++++++++++. ",
-" .++++++++++++. ",
-" .++++++++++++. ",
-" .++++++++++++. ",
-" .++++++++++++. ",
-" .............. ",
-" "};
diff --git a/filter/check.xpm b/filter/check.xpm
deleted file mode 100755
index 74f9b56122..0000000000
--- a/filter/check.xpm
+++ /dev/null
@@ -1,22 +0,0 @@
-/* XPM */
-static char * check_xpm[] = {
-"16 16 3 1",
-" c None",
-". c #000000",
-"+ c #FFFFFF",
-" ",
-" .............. ",
-" .++++++++++++. ",
-" .++++++++++++. ",
-" .+++++++++.++. ",
-" .++++++++..++. ",
-" .+++++++...++. ",
-" .++.+++...+++. ",
-" .++..+...++++. ",
-" .++.....+++++. ",
-" .+++...++++++. ",
-" .++++.+++++++. ",
-" .++++++++++++. ",
-" .++++++++++++. ",
-" .............. ",
-" "};
diff --git a/filter/filter-arg-types.c b/filter/filter-arg-types.c
deleted file mode 100644
index 5d09b4817b..0000000000
--- a/filter/filter-arg-types.c
+++ /dev/null
@@ -1,788 +0,0 @@
-/*
- * 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 <gnome.h>
-
-#include "evolution-shell-client.h"
-
-#include "filter-arg-types.h"
-
-/* ********************************************************************** */
-/* String */
-/* ********************************************************************** */
-
-/* Use for a superclass of any items which are simple strings */
-
-static void filter_arg_string_class_init (FilterArgStringClass *class);
-static void filter_arg_string_init (FilterArgString *gspaper);
-
-static FilterArg *string_parent_class;
-
-guint
-filter_arg_string_get_type (void)
-{
- static guint type = 0;
-
- if (!type) {
- GtkTypeInfo type_info = {
- "FilterArgString",
- sizeof (FilterArgString),
- sizeof (FilterArgStringClass),
- (GtkClassInitFunc) filter_arg_string_class_init,
- (GtkObjectInitFunc) filter_arg_string_init,
- (GtkArgSetFunc) NULL,
- (GtkArgGetFunc) NULL
- };
-
- type = gtk_type_unique (filter_arg_get_type (), &type_info);
- }
-
- return type;
-}
-
-static void
-arg_string_write_html(FilterArg *argin, GtkHTML *html, GtkHTMLStream *stream)
-{
- /* empty */
-}
-
-static void
-arg_string_write_text(FilterArg *argin, GString *string)
-{
- GList *l;
- char *a;
-
- l = argin->values;
- if (l == NULL) {
- g_string_append(string, "text");
- }
- 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_string_edit_values(FilterArg *arg)
-{
- printf("edit string values!\n");
-}
-
-/* pop up a dialogue, asking for a new string value */
-static int
-arg_string_edit_value (FilterArg *arg, int index)
-{
- GnomeDialog *dialogue;
- GtkWidget *hbox;
- GtkWidget *label;
- GtkWidget *entry;
- char *text = NULL;
- char *newtext;
-
- dialogue = (GnomeDialog *)gnome_dialog_new ("Edit value", "Ok", "Cancel", 0);
-
- hbox = gtk_hbox_new (FALSE, 0);
- label = gtk_label_new ("Text");
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- entry = gtk_entry_new();
- gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
- if (index >= 0) {
- text = filter_arg_get_value (arg, index);
- }
- if (text) {
- gtk_entry_set_text (GTK_ENTRY (entry), text);
- }
- gtk_box_pack_start (GTK_BOX (dialogue->vbox), hbox, TRUE, TRUE, 0);
- gtk_widget_show_all (hbox);
- gtk_object_ref (GTK_OBJECT (entry)); /* so we can get the text back afterwards */
- if (gnome_dialog_run_and_close (dialogue) == 0) {
- GList *node;
-
- newtext = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
- gtk_object_unref (GTK_OBJECT (entry));
- if (index >= 0 && (node = g_list_find (arg->values, text))) {
- node->data = newtext;
- } else {
- arg->values = g_list_append (arg->values, newtext);
- }
- g_free (text);
- return g_list_index (arg->values, newtext);
- }
- return -1;
-}
-
-static xmlNodePtr
-arg_string_values_get_xml(FilterArg *argin)
-{
- xmlNodePtr value;
- 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_string_values_add_xml(FilterArg *arg, xmlNodePtr node)
-{
- xmlNodePtr n;
-
- n = node->childs;
- while (n) {
- if (!strcmp(n->name, "folder")) {
- filter_arg_string_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_string_get_value_as_string(FilterArg *argin, void *data)
-{
- char *a = (char *)data;
-
- return a;
-}
-
-static void
-arg_string_free_value(FilterArg *arg, void *a)
-{
- g_free(a);
-}
-
-static void
-filter_arg_string_class_init (FilterArgStringClass *class)
-{
- GtkObjectClass *object_class;
-
- object_class = (GtkObjectClass *) class;
- if (string_parent_class == NULL)
- string_parent_class = gtk_type_class (gtk_object_get_type ());
-
- class->parent_class.write_html = arg_string_write_html;
- class->parent_class.write_text = arg_string_write_text;
- class->parent_class.edit_values = arg_string_edit_values;
- class->parent_class.edit_value = arg_string_edit_value;
- class->parent_class.free_value = arg_string_free_value;
- class->parent_class.get_value_as_string = arg_string_get_value_as_string;
-
- class->parent_class.values_get_xml = arg_string_values_get_xml;
- class->parent_class.values_add_xml = arg_string_values_add_xml;
-}
-
-static void
-filter_arg_string_init (FilterArgString *arg)
-{
- arg->arg.values = NULL;
-}
-
-/**
- * filter_arg_string_new:
- *
- * Create a new FilterArgString widget.
- *
- * Return value: A new FilterArgString widget.
- **/
-FilterArg *
-filter_arg_string_new (char *name)
-{
- FilterArg *a = FILTER_ARG ( gtk_type_new (filter_arg_string_get_type ()));
- a->name = g_strdup(name);
- return a;
-}
-
-
-void
-filter_arg_string_add(FilterArg *arg, char *name)
-{
- filter_arg_add(arg, g_strdup(name));
-}
-
-void
-filter_arg_string_remove(FilterArg *arg, char *name)
-{
- /* do it */
-}
-
-
-/* ********************************************************************** */
-/* 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, GtkHTMLStream *stream)
-{
- /* empty */
-}
-
-static void
-arg_address_write_text (FilterArg *argin, GString *string)
-{
- 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 int
-arg_address_edit_value (FilterArg *arg, int index)
-{
- GnomeDialog *dialogue;
- GtkWidget *hbox;
- GtkWidget *label;
- GtkWidget *entry;
- char *text = NULL;
- char *newtext;
- struct filter_arg_address *ad = NULL;
-
- dialogue = (GnomeDialog *)gnome_dialog_new ("Edit Address value", "Ok", "Cancel", 0);
-
- hbox = gtk_hbox_new (FALSE, 0);
- label = gtk_label_new ("Address");
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- entry = gtk_entry_new ();
- gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
- if (index >= 0 && (ad = filter_arg_get_value (arg, index))) {
- text = ad->email;
- }
- if (text) {
- gtk_entry_set_text (GTK_ENTRY (entry), text);
- }
- gtk_box_pack_start (GTK_BOX (dialogue->vbox), hbox, TRUE, TRUE, 0);
- gtk_widget_show_all (hbox);
- gtk_object_ref (GTK_OBJECT (entry)); /* so we can get the text back afterwards */
- if (gnome_dialog_run_and_close (dialogue) == 0) {
- GList *node;
-
- newtext = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
- gtk_object_unref (GTK_OBJECT (entry));
- if (index >= 0 && ad && (node = g_list_find(arg->values, ad))) {
- ad = node->data;
- g_free (ad->email);
- ad->email = newtext;
- } else {
- ad = g_malloc0 (sizeof(*ad));
- ad->email = newtext;
- arg->values = g_list_append (arg->values, ad);
- }
- g_free (text);
- return g_list_index (arg->values, ad);
- }
- return -1;
-}
-
-static xmlNodePtr
-arg_address_values_get_xml(FilterArg *argin)
-{
- xmlNodePtr value;
- 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")) {
- char *nm, *e;
- nm = xmlGetProp(n, "name");
- e = xmlGetProp(n, "email");
- filter_arg_address_add(arg, nm, e);
- free(nm);
- free(e);
- } 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)
-{
- 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, void *v)
-{
- struct filter_arg_address *a = v;
-
- 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.edit_value= arg_address_edit_value;
- 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)
-{
-}
-
-/**
- * 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 */
-/* ********************************************************************** */
-
-
-#include <bonobo/bonobo-object.h>
-#include <bonobo/bonobo-control.h>
-
-#include "Evolution.h"
-
-static void filter_arg_folder_class_init (FilterArgFolderClass *class);
-static void filter_arg_folder_init (FilterArgFolder *gspaper);
-
-static FilterArg *folder_parent_class;
-extern EvolutionShellClient *global_shell_client;
-
-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_string_get_type (), &type_info);
- }
-
- return type;
-}
-
-static void
-arg_folder_write_html(FilterArg *argin, GtkHTML *html, GtkHTMLStream *stream)
-{
- /* empty */
-}
-
-static void
-arg_folder_write_text(FilterArg *argin, GString *string)
-{
- 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 int
-arg_folder_edit_value (FilterArg *arg, int index)
-{
- const char *allowed_types[] = { "mail", NULL };
- char *def;
- char *physical_uri;
-
- printf ("folder edit value %d\n", index);
-
- if (index < 0) {
- def = "";
- } else {
- def = filter_arg_get_value (arg, index);
- }
-
- evolution_shell_client_user_select_folder (global_shell_client,
- _("Select Folder"),
- def, allowed_types, NULL, &physical_uri);
-
- if (physical_uri != NULL && physical_uri[0] != '\0') {
- GList *node;
-
- if (index >= 0 && (node = g_list_nth (arg->values, index)))
- node->data = physical_uri;
- else
- arg->values = g_list_append (arg->values, physical_uri);
-
- gtk_signal_emit_by_name (GTK_OBJECT (arg), "changed");
- } else {
- g_free (physical_uri);
- }
-
-#warning "What do we really want to return here???"
- return 0;
-}
-
-static void
-arg_folder_edit_values(FilterArg *argin)
-{
- /*FilterArgFolder *arg = (FilterArgFolder *)argin;*/
- GList *l;
- char *a, *start, *ptr, *ptrend, *ptrgap;
- char outbuf[128], *outptr; /* FIXME: dont use a bounded buffer! */
- GtkWidget *dialogue;
- GtkWidget *text;
- guint i;
-
- dialogue = gnome_dialog_new ("Edit addresses", "Ok", "Cancel", NULL);
- text = gtk_text_new (NULL, NULL);
- gtk_object_ref (GTK_OBJECT (text));
-
- l = argin->values;
- while (l) {
- a = l->data;
- gtk_text_insert(GTK_TEXT (text), NULL, NULL, NULL, a, strlen(a));
- gtk_text_insert(GTK_TEXT (text), NULL, NULL, NULL, "\n", 1);
- l = g_list_next(l);
- }
-
- gtk_box_pack_start(GTK_BOX (GNOME_DIALOG(dialogue)->vbox), text, TRUE, TRUE, 2);
- gtk_widget_show(text);
- gtk_text_set_editable(GTK_TEXT (text), TRUE);
-
- gnome_dialog_run_and_close(GNOME_DIALOG (dialogue));
-
- for (i = 0; i < g_list_length (argin->values); i++)
- g_free (g_list_nth_data (argin->values, i));
- g_list_free (argin->values);
-
- argin->values = NULL;
- ptr = GTK_TEXT(text)->text.ch;
- ptrend = ptr + GTK_TEXT(text)->text_end;
- ptrgap = ptr + GTK_TEXT(text)->gap_position;
-
- start = ptr;
- outptr = outbuf;
- while (ptr < ptrend) {
- printf("%c", *ptr);
- if (*ptr == '\n') {
- int len = outptr - outbuf;
- char *new;
-
- printf("(len = %d)", len);
-
- if (len>0) {
- new = g_malloc(len+1);
- new[len]=0;
- memcpy(new, outbuf, len);
- printf("(appending '%s')", new);
- argin->values = g_list_append(argin->values, new);
- }
- outptr = outbuf;
- } else {
- *outptr++ = *ptr;
- }
- ptr++;
- if (ptr==ptrgap) {
- ptr += GTK_TEXT(text)->gap_size;
- }
- }
- if (outptr > outbuf) {
- int len = outptr-outbuf;
- char *new;
-
- printf("(lastlen = %d)", len);
-
- new = g_malloc(len+1);
- new[len] = 0;
- memcpy(new, start, len);
- argin->values = g_list_append(argin->values, new);
- }
- printf("\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, "name", 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")) {
- char *name = xmlGetProp(n, "name");
- if (name) {
- filter_arg_folder_add(arg, name);
- free(name);
- } else
- g_warning("no xml prop 'name' on '%s'\n", n->name);
- } 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;
- FilterArgClass *filter_class;
-
- object_class = (GtkObjectClass *) class;
- filter_class = (FilterArgClass *) class;
- if (folder_parent_class == NULL)
- folder_parent_class = gtk_type_class (filter_arg_string_get_type ());
-
- /* FIXME: only need to over-ride the edit values right? */
- filter_class->edit_value = arg_folder_edit_value;
-
- filter_class->write_html = arg_folder_write_html;
- filter_class->write_text = arg_folder_write_text;
- filter_class->edit_values = arg_folder_edit_values;
- filter_class->free_value = arg_folder_free_value;
-
- filter_class->values_get_xml = arg_folder_values_get_xml;
- filter_class->values_add_xml = arg_folder_values_add_xml;
-
- filter_class->get_value_as_string = arg_folder_get_value_as_string;
-}
-
-static void
-filter_arg_folder_init (FilterArgFolder *arg)
-{
-}
-
-/**
- * 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
deleted file mode 100644
index 6a1d80bfae..0000000000
--- a/filter/filter-arg-types.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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 simple String */
-#define FILTER_ARG_STRING(obj) GTK_CHECK_CAST (obj, filter_arg_string_get_type (), FilterArgString)
-#define FILTER_ARG_STRING_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_arg_string_get_type (), FilterArgStringClass)
-#define IS_FILTER_ARG_STRING(obj) GTK_CHECK_TYPE (obj, filter_arg_string_get_type ())
-
-typedef struct _FilterArgString FilterArgString;
-typedef struct _FilterArgStringClass FilterArgStringClass;
-
-struct _FilterArgString {
- FilterArg arg;
-
- /* Name/property to save/load to xml */
- /* char *xmlname; */
- /* char *xmlprop; */
-};
-
-struct _FilterArgStringClass {
- FilterArgClass parent_class;
-};
-
-guint filter_arg_string_get_type (void);
-FilterArg *filter_arg_string_new (char *name);
-void filter_arg_string_add(FilterArg *, char *name);
-void filter_arg_string_remove(FilterArg *, char *name);
-
-/* A Folder, subclass of a string */
-#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 {
- FilterArgString arg;
-};
-
-struct _FilterArgFolderClass {
- FilterArgStringClass 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
deleted file mode 100644
index 622986ce43..0000000000
--- a/filter/filter-arg.c
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * 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 <gtk/gtk.h>
-#include <gnome.h>
-
-#include "filter-arg.h"
-
-
-static void filter_arg_class_init (FilterArgClass *class);
-static void filter_arg_init (FilterArg *gspaper);
-
-#define _PRIVATE(x) (((FilterArg *)(x))->priv)
-
-struct _FilterArgPrivate {
- GtkWidget *dialogue; /* editor widget */
- xmlNodePtr oldargs;
-};
-
-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 FilterArg *
-clone_default(FilterArg *a)
-{
- xmlNodePtr values;
- FilterArg *new = FILTER_ARG ( gtk_type_new (((GtkObject *)a)->klass->type) );
-
- /* clone values */
- new->name = g_strdup(a->name);
- values = filter_arg_values_get_xml(a);
- filter_arg_values_add_xml(new, values);
- xmlFreeNodeList(values);
-
- return new;
-}
-
-static void
-write_html_nothing(FilterArg *arg, GtkHTML *html, GtkHTMLStream *stream)
-{
- /* empty */
-}
-
-static void
-write_text_nothing(FilterArg *arg, GString *string)
-{
- /* empty */
-}
-
-static void
-edit_values_nothing(FilterArg *arg)
-{
- /* empty */
-}
-
-static int
-edit_value_nothing(FilterArg *arg, int index)
-{
- return index;
-}
-
-static void
-free_value_nothing(FilterArg *arg, void *v)
-{
- /* empty */
-}
-
-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->edit_value = edit_value_nothing;
- class->free_value = free_value_nothing;
- class->clone = clone_default;
-
- 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;
- arg->priv = g_malloc0(sizeof(*arg->priv));
-}
-
-/**
- * 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;
-}
-
-FilterArg *
-filter_arg_clone (FilterArg *arg)
-{
- return ((FilterArgClass *)(arg->object.klass))->clone(arg);
-}
-
-void
-filter_arg_copy(FilterArg *dst, FilterArg *src)
-{
- xmlNodePtr values;
-
- g_return_if_fail( ((GtkObject *)src)->klass->type == ((GtkObject *)dst)->klass->type );
-
- /* remove old values */
- while (dst->values) {
- filter_arg_remove(dst, dst->values->data);
- }
-
- /* clone values */
- values = filter_arg_values_get_xml(src);
- filter_arg_values_add_xml(dst, values);
- xmlFreeNodeList(values);
-}
-
-void
-filter_arg_add(FilterArg *arg, void *v)
-{
- g_return_if_fail(v != NULL);
-
- 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, GtkHTMLStream *stream)
-{
- ((FilterArgClass *)(arg->object.klass))->write_html(arg, html, stream);
-}
-
-void
-filter_arg_write_text(FilterArg *arg, GString *string)
-{
- int count, i;
-
- count = filter_arg_get_count(arg);
- for (i=0;i<count;i++) {
- g_string_append(string, filter_arg_get_value_as_string(arg, i));
- if (i<count-1) {
- g_string_append(string, ", ");
- }
- if (i==count-2 && count>1) {
- g_string_append(string, "or ");
- }
- }
-
-#if 0
- ((FilterArgClass *)(arg->object.klass))->write_text(arg, string);
-#endif
-}
-void
-filter_arg_edit_values(FilterArg *arg)
-{
- void filter_arg_edit_values_1(FilterArg *arg);
-
- g_return_if_fail(arg != NULL);
-
-
-#if 1
- filter_arg_edit_values_1(arg);
-#else
-
- if (((FilterArgClass *)(arg->object.klass))->edit_values)
- ((FilterArgClass *)(arg->object.klass))->edit_values(arg);
- else
- g_warning("No implementation of virtual method edit_values");
-#endif
-}
-
-int
-filter_arg_edit_value(FilterArg *arg, int index)
-{
- return ((FilterArgClass *)(arg->object.klass))->edit_value(arg, index);
-}
-
-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)
-{
- void *data;
-
- data = filter_arg_get_value(arg, index);
- if (data) {
- return ((FilterArgClass *)(arg->object.klass))->get_value_as_string(arg, data);
- } else {
- return "";
- }
-}
-
-
-struct filter_arg_edit {
- FilterArg *arg;
- GtkList *list;
- GList *items;
- GnomeDialog *dialogue;
- GtkWidget *add, *remove, *edit;
- GtkWidget *item_current;
-};
-
-static void
-filter_arg_edit_add(GtkWidget *w, struct filter_arg_edit *edata)
-{
- GtkWidget *listitem;
- int i;
-
- i = filter_arg_edit_value(edata->arg, -1);
- if (i>=0) {
- gtk_list_remove_items_no_unref(edata->list, edata->items);
- listitem = gtk_list_item_new_with_label(filter_arg_get_value_as_string(edata->arg, i));
- gtk_object_set_data(GTK_OBJECT (listitem), "arg_i", filter_arg_get_value(edata->arg, i));
- edata->items = g_list_append(edata->items, listitem);
- gtk_widget_show(listitem);
-
- /* this api is nonsense */
- gtk_list_append_items(edata->list, g_list_copy(edata->items));
- }
-}
-
-void dump_list(GList *list)
-{
- printf("dumping list:\n");
- for (;list;list = g_list_next(list)) {
- printf(" %p %p\n", list, list->data);
- }
-}
-
-static void
-fill_list(struct filter_arg_edit *edata)
-{
- GList *items = NULL;
- int i, count;
- GtkListItem *listitem;
-
- gtk_list_remove_items(edata->list, edata->items);
- g_list_free(edata->items);
-
- count = filter_arg_get_count(edata->arg);
- for (i=0;i<count;i++) {
- char *labeltext;
- labeltext = filter_arg_get_value_as_string(edata->arg, i);
- listitem = (GtkListItem *)gtk_list_item_new_with_label(labeltext);
- gtk_object_set_data((GtkObject *)listitem, "arg_i", filter_arg_get_value(edata->arg, i));
- items = g_list_append(items, listitem);
- gtk_widget_show(GTK_WIDGET(listitem));
- }
-
- edata->item_current = NULL;
- edata->items = items;
-
- gtk_list_append_items(edata->list, g_list_copy(edata->items));
-}
-
-static void
-filter_arg_edit_edit(GtkWidget *w, struct filter_arg_edit *edata)
-{
- char *name;
- int i;
-
- /* yurck */
- if (edata->item_current
- && (name = gtk_object_get_data(GTK_OBJECT (edata->item_current), "arg_i"))
- && (i = g_list_index(edata->arg->values, name)) >= 0
- && (i = filter_arg_edit_value(edata->arg, i)) >= 0) {
-
- fill_list(edata);
- }
-}
-
-static void
-filter_arg_edit_delete(GtkWidget *w, struct filter_arg_edit *edata)
-{
- char *name;
-
- /* yurck */
- name = gtk_object_get_data(GTK_OBJECT (edata->item_current), "arg_i");
- if (edata->item_current && name) {
- filter_arg_remove(edata->arg, name);
- fill_list(edata);
- }
-}
-
-static void
-edit_sensitise(struct filter_arg_edit *edata)
-{
- int state = edata->item_current != NULL;
- gtk_widget_set_sensitive(edata->remove, state);
- gtk_widget_set_sensitive(edata->edit, state);
-}
-
-static void
-filter_arg_edit_select(GtkWidget *w, GtkListItem *list, struct filter_arg_edit *edata)
-{
- edata->item_current = GTK_WIDGET (list);
- edit_sensitise(edata);
-}
-
-static void
-filter_arg_edit_unselect(GtkWidget *w, GtkListItem *list, struct filter_arg_edit *edata)
-{
- edata->item_current = NULL;
- edit_sensitise(edata);
-}
-
-static void
-filter_arg_edit_clicked(GnomeDialog *d, int button, struct filter_arg_edit *edata)
-{
- struct _FilterArgPrivate *p = _PRIVATE(edata->arg);
-
- if (button == 0) {
- gtk_signal_emit(GTK_OBJECT(edata->arg), signals[CHANGED]);
- } else {
- /* cancel button, restore old values ... */
- while (edata->arg->values) {
- filter_arg_remove(edata->arg, edata->arg->values->data);
- }
- filter_arg_values_add_xml(edata->arg, p->oldargs);
- }
- xmlFreeNodeList(p->oldargs);
- p->oldargs = NULL;
- p->dialogue = NULL;
- gnome_dialog_close(d);
-}
-
-static void
-filter_arg_edit_destroy(GnomeDialog *d, struct filter_arg_edit *edata)
-{
- struct _FilterArgPrivate *p = _PRIVATE(edata->arg);
-
- if (p->oldargs) {
- while (edata->arg->values) {
- filter_arg_remove(edata->arg, edata->arg->values->data);
- }
- filter_arg_values_add_xml(edata->arg, p->oldargs);
- xmlFreeNodeList(p->oldargs);
- p->oldargs = NULL;
- }
-
- if (p->dialogue) {
- p->dialogue = NULL;
- gnome_dialog_close(d);
- }
- g_free(edata);
-}
-
-void
-filter_arg_edit_values_1(FilterArg *arg)
-{
- GtkWidget *list;
- GnomeDialog *dialogue;
- GtkWidget *hbox;
- GtkWidget *vbox;
- GtkWidget *button;
- GtkWidget *scrolled_window, *frame;
- struct filter_arg_edit * edata;
- struct _FilterArgPrivate *p = _PRIVATE(arg);
-
- /* dont show more than 1 editor for each type */
- if (p->dialogue) {
- gdk_window_raise(GTK_WIDGET(p->dialogue)->window);
- return;
- }
-
- /* copy the current state */
- p->oldargs = filter_arg_values_get_xml(arg);
-
- edata = g_malloc0(sizeof(*edata));
- edata->item_current = NULL;
- edata->arg = arg;
-
- dialogue = (GnomeDialog *)gnome_dialog_new("Edit values", "Ok", "Cancel", 0);
- edata->dialogue = dialogue;
-
- p->dialogue = GTK_WIDGET (dialogue);
-
- hbox = gtk_hbox_new(FALSE, 0);
-
- list = gtk_list_new();
- edata->list = GTK_LIST (list);
- edata->items = NULL;
- fill_list(edata);
-
- scrolled_window = gtk_scrolled_window_new(NULL, NULL);
- frame = gtk_frame_new("Option values");
-
- gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), list);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_container_set_focus_vadjustment(GTK_CONTAINER (list),
- gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrolled_window)));
- gtk_container_add(GTK_CONTAINER(frame), scrolled_window);
- gtk_widget_set_usize(frame, 200, 300);
- gtk_box_pack_start(GTK_BOX (hbox), frame, TRUE, TRUE, 0);
-
- /* buttons */
- vbox = gtk_vbox_new(FALSE, 0);
-
- button = gtk_button_new_with_label ("Add");
- gtk_box_pack_start(GTK_BOX (vbox), button, FALSE, TRUE, 0);
- edata->add = button;
- button = gtk_button_new_with_label ("Remove");
- gtk_box_pack_start(GTK_BOX (vbox), button, FALSE, TRUE, 0);
- edata->remove = button;
- button = gtk_button_new_with_label ("Edit");
- gtk_box_pack_start(GTK_BOX (vbox), button, FALSE, TRUE, 0);
- edata->edit = button;
-
- gtk_box_pack_start(GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
-
- gtk_signal_connect(GTK_OBJECT (edata->add), "clicked", filter_arg_edit_add, edata);
- gtk_signal_connect(GTK_OBJECT (edata->edit), "clicked", filter_arg_edit_edit, edata);
- gtk_signal_connect(GTK_OBJECT (edata->remove), "clicked", filter_arg_edit_delete, edata);
- gtk_signal_connect(GTK_OBJECT (edata->list), "select_child", filter_arg_edit_select, edata);
- gtk_signal_connect(GTK_OBJECT (edata->list), "unselect_child", filter_arg_edit_unselect, edata);
-
- gtk_widget_show(list);
- gtk_widget_show_all(hbox);
- gtk_box_pack_start(GTK_BOX (dialogue->vbox), hbox, TRUE, TRUE, 0);
-
- gtk_signal_connect(GTK_OBJECT (dialogue), "clicked", filter_arg_edit_clicked, edata);
- gtk_signal_connect(GTK_OBJECT (dialogue), "destroy", filter_arg_edit_destroy, edata);
-
- edit_sensitise(edata);
-
- gtk_widget_show(GTK_WIDGET (dialogue));
-}
-
-
diff --git a/filter/filter-arg.h b/filter/filter-arg.h
deleted file mode 100644
index c7b038a996..0000000000
--- a/filter/filter-arg.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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> /* gnome-xml */
-
-#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;
-
- struct _FilterArgPrivate *priv;
-
- char *name;
- GList *values;
-};
-
-struct _FilterArgClass {
- GtkObjectClass parent_class;
-
- /* make a copy of yourself */
- struct _FilterArg * (*clone)(FilterArg *arg);
-
- /* virtual methods */
- void (*write_html)(FilterArg *arg, GtkHTML *html, GtkHTMLStream *stream);
- void (*write_text)(FilterArg *arg, GString *string);
- void (*free_value)(FilterArg *arg, void *v);
-
- void (*edit_values)(FilterArg *arg);
- int (*edit_value)(FilterArg *arg, int index);
-
- 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);
-FilterArg *filter_arg_clone(FilterArg *arg);
-void filter_arg_copy (FilterArg *dst, FilterArg *src);
-void filter_arg_value_add(FilterArg *a, void *v);
-
-void filter_arg_write_html(FilterArg *arg, GtkHTML *html,
- GtkHTMLStream *stream);
-void filter_arg_write_text(FilterArg *arg, GString *string);
-
-void filter_arg_edit_values(FilterArg *arg);
-int filter_arg_edit_value(FilterArg *arg, int index);
-
-void filter_arg_remove(FilterArg *arg, void *v);
-void filter_arg_add(FilterArg *arg, 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-code.c b/filter/filter-code.c
new file mode 100644
index 0000000000..cbab60359e
--- /dev/null
+++ b/filter/filter-code.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+
+#include "filter-code.h"
+
+static void build_code(FilterElement *fe, GString *out, struct _FilterPart *ff);
+static void format_sexp(FilterElement *, GString *);
+
+static void filter_code_class_init (FilterCodeClass *class);
+static void filter_code_init (FilterCode *gspaper);
+static void filter_code_finalise (GtkObject *obj);
+
+static FilterInputClass *parent_class;
+
+guint
+filter_code_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterCode",
+ sizeof(FilterCode),
+ sizeof(FilterCodeClass),
+ (GtkClassInitFunc)filter_code_class_init,
+ (GtkObjectInitFunc)filter_code_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(filter_input_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+filter_code_class_init (FilterCodeClass *class)
+{
+ GtkObjectClass *object_class;
+ FilterElementClass *filter_element = (FilterElementClass *)class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(filter_input_get_type ());
+
+ filter_element->build_code = build_code;
+ filter_element->format_sexp = format_sexp;
+
+ object_class->finalize = filter_code_finalise;
+ /* override methods */
+
+}
+
+static void
+filter_code_init (FilterCode *o)
+{
+ ((FilterInput *)o)->type = g_strdup("code");
+}
+
+static void
+filter_code_finalise(GtkObject *obj)
+{
+ FilterCode *o = (FilterCode *)obj;
+
+ o = o;
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * filter_code_new:
+ *
+ * Create a new FilterCode object.
+ *
+ * Return value: A new #FilterCode object.
+ **/
+FilterCode *
+filter_code_new(void)
+{
+ FilterCode *o = (FilterCode *)gtk_type_new(filter_code_get_type ());
+ return o;
+}
+
+/* here, the string IS the code */
+static void build_code(FilterElement *fe, GString *out, struct _FilterPart *ff)
+{
+ GList *l;
+ FilterInput *fi = (FilterInput *)fe;
+
+ l = fi->values;
+ while (l) {
+ g_string_append(out, (char *)l->data);
+ l = g_list_next(l);
+ }
+}
+
+/* and we have no value */
+static void format_sexp(FilterElement *fe, GString *out)
+{
+ return;
+}
diff --git a/filter/filter-code.h b/filter/filter-code.h
new file mode 100644
index 0000000000..c4bb04caab
--- /dev/null
+++ b/filter/filter-code.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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_CODE_H
+#define _FILTER_CODE_H
+
+#include <gtk/gtk.h>
+
+#include "filter-input.h"
+
+#define FILTER_CODE(obj) GTK_CHECK_CAST (obj, filter_code_get_type (), FilterCode)
+#define FILTER_CODE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_code_get_type (), FilterCodeClass)
+#define IS_FILTER_CODE(obj) GTK_CHECK_TYPE (obj, filter_code_get_type ())
+
+typedef struct _FilterCode FilterCode;
+typedef struct _FilterCodeClass FilterCodeClass;
+
+struct _FilterCode {
+ FilterInput parent;
+};
+
+struct _FilterCodeClass {
+ FilterInputClass parent_class;
+
+ /* virtual methods */
+
+ /* signals */
+};
+
+guint filter_code_get_type (void);
+FilterCode *filter_code_new (void);
+
+/* methods */
+
+#endif /* ! _FILTER_CODE_H */
+
diff --git a/filter/filter-colour.c b/filter/filter-colour.c
new file mode 100644
index 0000000000..202908d016
--- /dev/null
+++ b/filter/filter-colour.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+#include <gnome-xml/xmlmemory.h>
+
+#include "e-util/e-sexp.h"
+#include "filter-colour.h"
+
+#define d(x)
+
+static void xml_create(FilterElement *fe, xmlNodePtr node);
+static xmlNodePtr xml_encode(FilterElement *fe);
+static int xml_decode(FilterElement *fe, xmlNodePtr node);
+static GtkWidget *get_widget(FilterElement *fe);
+static void build_code(FilterElement *fe, GString *out, struct _FilterPart *ff);
+static void format_sexp(FilterElement *, GString *);
+
+static void filter_colour_class_init (FilterColourClass *class);
+static void filter_colour_init (FilterColour *gspaper);
+static void filter_colour_finalise (GtkObject *obj);
+
+#define _PRIVATE(x) (((FilterColour *)(x))->priv)
+
+struct _FilterColourPrivate {
+};
+
+static FilterElementClass *parent_class;
+
+enum {
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+guint
+filter_colour_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterColour",
+ sizeof(FilterColour),
+ sizeof(FilterColourClass),
+ (GtkClassInitFunc)filter_colour_class_init,
+ (GtkObjectInitFunc)filter_colour_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(filter_element_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+filter_colour_class_init (FilterColourClass *class)
+{
+ GtkObjectClass *object_class;
+ FilterElementClass *filter_element = (FilterElementClass *)class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(filter_element_get_type ());
+
+ object_class->finalize = filter_colour_finalise;
+
+ /* override methods */
+ filter_element->xml_create = xml_create;
+ filter_element->xml_encode = xml_encode;
+ filter_element->xml_decode = xml_decode;
+ filter_element->get_widget = get_widget;
+ filter_element->build_code = build_code;
+ filter_element->format_sexp = format_sexp;
+
+ /* signals */
+
+ gtk_object_class_add_signals(object_class, signals, LAST_SIGNAL);
+}
+
+static void
+filter_colour_init (FilterColour *o)
+{
+ o->priv = g_malloc0(sizeof(*o->priv));
+}
+
+static void
+filter_colour_finalise(GtkObject *obj)
+{
+ FilterColour *o = (FilterColour *)obj;
+
+ o = o;
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * filter_colour_new:
+ *
+ * Create a new FilterColour object.
+ *
+ * Return value: A new #FilterColour object.
+ **/
+FilterColour *
+filter_colour_new(void)
+{
+ FilterColour *o = (FilterColour *)gtk_type_new(filter_colour_get_type ());
+ return o;
+}
+
+static void xml_create(FilterElement *fe, xmlNodePtr node)
+{
+ /*FilterColour *fc = (FilterColour *)fe;*/
+
+ /* parent implementation */
+ ((FilterElementClass *)(parent_class))->xml_create(fe, node);
+}
+
+static xmlNodePtr xml_encode(FilterElement *fe)
+{
+ xmlNodePtr value;
+ FilterColour *fc = (FilterColour *)fe;
+ char hex[16];
+
+ d(printf("Encoding colour as xml\n"));
+ value = xmlNewNode(NULL, "value");
+ xmlSetProp(value, "name", fe->name);
+ xmlSetProp(value, "type", "colour");
+
+ sprintf(hex, "%04x", fc->r);
+ xmlSetProp(value, "red", hex);
+ sprintf(hex, "%04x", fc->g);
+ xmlSetProp(value, "green", hex);
+ sprintf(hex, "%04x", fc->b);
+ xmlSetProp(value, "blue", hex);
+ sprintf(hex, "%04x", fc->a);
+ xmlSetProp(value, "alpha", hex);
+
+ return value;
+}
+
+static guint16
+get_value(xmlNodePtr node, char *name)
+{
+ unsigned int ret;
+ char *value;
+
+ value = xmlGetProp(node, name);
+ sscanf(value, "%04x", &ret);
+ xmlFree(value);
+ return ret;
+}
+
+
+static int xml_decode(FilterElement *fe, xmlNodePtr node)
+{
+ FilterColour *fc = (FilterColour *)fe;
+
+ fe->name = xmlGetProp(node, "name");
+ fc->r = get_value(node, "red");
+ fc->g = get_value(node, "green");
+ fc->b = get_value(node, "blue");
+ fc->a = get_value(node, "alpha");
+
+ return 0;
+}
+
+static void set_colour(GnomeColorPicker *cp, guint r, guint g, guint b, guint a, FilterColour *fc)
+{
+ fc->r = r;
+ fc->g = g;
+ fc->b = b;
+ fc->a = a;
+}
+
+static GtkWidget *get_widget(FilterElement *fe)
+{
+ FilterColour *fc = (FilterColour *)fe;
+ GnomeColorPicker *cp;
+
+ cp = (GnomeColorPicker *)gnome_color_picker_new();
+ gnome_color_picker_set_i16(cp, fc->r, fc->g, fc->b, fc->a);
+ gtk_widget_show((GtkWidget *)cp);
+ gtk_signal_connect((GtkObject *)cp, "color_set", set_colour, fe);
+ return (GtkWidget *)cp;
+}
+
+static void build_code(FilterElement *fe, GString *out, struct _FilterPart *ff)
+{
+ return;
+}
+
+static void format_sexp(FilterElement *fe, GString *out)
+{
+ char *str;
+ FilterColour *fc = (FilterColour *)fe;
+
+ str =g_strdup_printf("rgb:%04x/%04x/%04x", fc->r, fc->g, fc->b);
+ e_sexp_encode_string(out, str);
+ g_free(str);
+}
diff --git a/filter/filter-colour.h b/filter/filter-colour.h
new file mode 100644
index 0000000000..3526dfcfda
--- /dev/null
+++ b/filter/filter-colour.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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_COLOUR_H
+#define _FILTER_COLOUR_H
+
+#include <gtk/gtk.h>
+#include "filter-element.h"
+
+#define FILTER_COLOUR(obj) GTK_CHECK_CAST (obj, filter_colour_get_type (), FilterColour)
+#define FILTER_COLOUR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_colour_get_type (), FilterColourClass)
+#define IS_FILTER_COLOUR(obj) GTK_CHECK_TYPE (obj, filter_colour_get_type ())
+
+typedef struct _FilterColour FilterColour;
+typedef struct _FilterColourClass FilterColourClass;
+
+struct _FilterColour {
+ FilterElement parent;
+ struct _FilterColourPrivate *priv;
+
+ guint16 r,g,b,a;
+};
+
+struct _FilterColourClass {
+ FilterElementClass parent_class;
+
+ /* virtual methods */
+
+ /* signals */
+};
+
+guint filter_colour_get_type (void);
+FilterColour *filter_colour_new (void);
+
+/* methods */
+
+#endif /* ! _FILTER_COLOUR_H */
+
diff --git a/filter/filter-context.c b/filter/filter-context.c
new file mode 100644
index 0000000000..701010fde9
--- /dev/null
+++ b/filter/filter-context.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+
+#include "filter-context.h"
+#include "filter-filter.h"
+
+#define d(x)
+
+static void filter_context_class_init (FilterContextClass *class);
+static void filter_context_init (FilterContext *gspaper);
+static void filter_context_finalise (GtkObject *obj);
+
+#define _PRIVATE(x) (((FilterContext *)(x))->priv)
+
+struct _FilterContextPrivate {
+};
+
+static RuleContextClass *parent_class;
+
+enum {
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+guint
+filter_context_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterContext",
+ sizeof(FilterContext),
+ sizeof(FilterContextClass),
+ (GtkClassInitFunc)filter_context_class_init,
+ (GtkObjectInitFunc)filter_context_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(rule_context_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+filter_context_class_init (FilterContextClass *class)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(rule_context_get_type ());
+
+ object_class->finalize = filter_context_finalise;
+ /* override methods */
+
+ /* signals */
+
+ gtk_object_class_add_signals(object_class, signals, LAST_SIGNAL);
+}
+
+static void
+filter_context_init (FilterContext *o)
+{
+ o->priv = g_malloc0(sizeof(*o->priv));
+
+ rule_context_add_part_set((RuleContext *)o, "partset", filter_part_get_type(),
+ rule_context_add_part, rule_context_next_part);
+ rule_context_add_part_set((RuleContext *)o, "actionset", filter_part_get_type(),
+ (RCPartFunc)filter_context_add_action,
+ (RCNextPartFunc)filter_context_next_action);
+
+ rule_context_add_rule_set((RuleContext *)o, "ruleset", filter_filter_get_type(),
+ (RCRuleFunc)rule_context_add_rule, rule_context_next_rule);
+}
+
+static void
+filter_context_finalise(GtkObject *obj)
+{
+ FilterContext *o = (FilterContext *)obj;
+
+ o = o;
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * filter_context_new:
+ *
+ * Create a new FilterContext object.
+ *
+ * Return value: A new #FilterContext object.
+ **/
+FilterContext *
+filter_context_new(void)
+{
+ FilterContext *o = (FilterContext *)gtk_type_new(filter_context_get_type ());
+ return o;
+}
+
+void filter_context_add_action(FilterContext *f, FilterPart *action)
+{
+ d(printf("find action : "));
+ f->actions = g_list_append(f->actions, action);
+}
+
+FilterPart *filter_context_find_action(FilterContext *f, char *name)
+{
+ d(printf("find action : "));
+ return filter_part_find_list(f->actions, name);
+}
+
+FilterPart *filter_context_next_action(FilterContext *f, FilterPart *last)
+{
+ return filter_part_next_list(f->actions, last);
+}
diff --git a/filter/filter-context.h b/filter/filter-context.h
new file mode 100644
index 0000000000..57ce961aaf
--- /dev/null
+++ b/filter/filter-context.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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_CONTEXT_H
+#define _FILTER_CONTEXT_H
+
+#include <gtk/gtk.h>
+#include "rule-context.h"
+
+#define FILTER_CONTEXT(obj) GTK_CHECK_CAST (obj, filter_context_get_type (), FilterContext)
+#define FILTER_CONTEXT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_context_get_type (), FilterContextClass)
+#define IS_FILTER_CONTEXT(obj) GTK_CHECK_TYPE (obj, filter_context_get_type ())
+
+typedef struct _FilterContext FilterContext;
+typedef struct _FilterContextClass FilterContextClass;
+
+struct _FilterContext {
+ RuleContext parent;
+ struct _FilterContextPrivate *priv;
+
+ GList *actions;
+};
+
+struct _FilterContextClass {
+ RuleContextClass parent_class;
+
+ /* virtual methods */
+
+ /* signals */
+};
+
+guint filter_context_get_type (void);
+FilterContext *filter_context_new (void);
+
+/* methods */
+void filter_context_add_action(FilterContext *f, FilterPart *action);
+FilterPart *filter_context_find_action(FilterContext *f, char *name);
+/*FilterPart *filter_context_create_action(FilterContext *f, char *name);*/
+FilterPart *filter_context_next_action(FilterContext *f, FilterPart *last);
+
+#endif /* ! _FILTER_CONTEXT_H */
+
diff --git a/filter/filter-driver.c b/filter/filter-driver.c
index baca92a6d4..abd11c76f0 100644
--- a/filter/filter-driver.c
+++ b/filter/filter-driver.c
@@ -29,17 +29,21 @@
#include <gnome-xml/tree.h>
#include <gnome-xml/parser.h>
-#include "filter-arg-types.h"
-#include "filter-xml.h"
-#include "e-sexp.h"
-#include "filter-format.h"
-
#include <camel/camel.h>
+#include "filter-context.h"
+#include "filter-filter.h"
+
+#include "e-util/e-sexp.h"
+
struct _FilterDriverPrivate {
- GList *rules, *options;
GHashTable *globals; /* global variables */
- FilterFolderFetcher fetcher;
+
+ FilterContext *context;
+
+ /* for callback */
+ FilterGetFolderFunc get_folder;
+ void *data;
/* run-time data */
GHashTable *folders; /* currently open folders */
@@ -69,6 +73,7 @@ static ESExpResult *do_delete(struct _ESExp *f, int argc, struct _ESExpResult **
static ESExpResult *mark_forward(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *);
static ESExpResult *mark_copy(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *);
static ESExpResult *do_stop(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *);
+static ESExpResult *do_colour(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *);
static struct {
char *name;
@@ -80,6 +85,7 @@ static struct {
{ "forward-to", (ESExpFunc *)mark_forward, 0 },
{ "copy-to", (ESExpFunc *)mark_copy, 0 },
{ "stop", (ESExpFunc *)do_stop, 0 },
+ { "set-colour", (ESExpFunc *)do_colour, 0 },
};
static GtkObjectClass *filter_driver_parent;
@@ -176,33 +182,25 @@ filter_driver_finalise (GtkObject *obj)
* filter_driver_new:
* @system: path to system rules
* @user: path to user rules
- * @fetcher: function to call to fetch folders
+ * @get_folder: function to call to fetch folders
*
* Create a new FilterDriver object.
*
* Return value: A new FilterDriver widget.
**/
FilterDriver *
-filter_driver_new (const char *system, const char *user, FilterFolderFetcher fetcher)
+filter_driver_new (FilterContext *context, FilterGetFolderFunc get_folder, void *data)
{
FilterDriver *new;
struct _FilterDriverPrivate *p;
- xmlDocPtr desc, filt;
new = FILTER_DRIVER (gtk_type_new (filter_driver_get_type ()));
p = _PRIVATE(new);
- p->fetcher = fetcher;
-
-#warning "fix leaks, free xml docs here"
- desc = xmlParseFile(system);
- p->rules = filter_load_ruleset(desc);
-
- filt = xmlParseFile(user);
- if (filt == NULL)
- p->options = NULL;
- else
- p->options = filter_load_optionset(filt, p->rules);
+ p->get_folder = get_folder;
+ p->data = data;
+ p->context = context;
+ gtk_object_ref((GtkObject *)context);
return new;
}
@@ -221,119 +219,6 @@ void filter_driver_set_global(FilterDriver *d, const char *name, const char *val
}
}
-extern int filter_find_arg(FilterArg *a, char *name);
-
-/*
-
- foreach rule
- find matches
-
- foreach action
- get all matches
-
- */
-
-/*
- splices ${cc} lines into a single string
-*/
-static int
-expand_variables(GString *out, char *source, GList *args, GHashTable *globals)
-{
- GList *argl;
- FilterArg *arg;
- char *name= alloca(32);
- char *start, *end, *newstart, *tmp, *val;
- 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, (GCompareFunc) filter_find_arg);
- if (argl) {
- int i, count;
-
- tmp = g_strdup_printf("%.*s", newstart-start, start);
- g_string_append(out, tmp);
- g_free(tmp);
-
- arg = argl->data;
- count = filter_arg_get_count(arg);
- for (i=0;i<count;i++) {
- g_string_append(out, " \"");
- g_string_append(out, filter_arg_get_value_as_string(arg, i));
- g_string_append(out, "\"");
- }
- } else if ( (val = g_hash_table_lookup(globals, name)) ) {
- tmp = g_strdup_printf("%.*s", newstart-start, start);
- g_string_append(out, tmp);
- g_free(tmp);
- g_string_append(out, " \"");
- g_string_append(out, val);
- g_string_append(out, "\"");
- } else {
- ok = 1;
- tmp = g_strdup_printf("%.*s", end-start+1, start);
- g_string_append(out, tmp);
- g_free(tmp);
- }
- start = end+1;
- }
- g_string_append(out, start);
-
- return ok;
-}
-
-/*
- build an expression for the filter
-*/
-void
-filter_driver_expand_option(FilterDriver *d, GString *s, GString *action, struct filter_option *op)
-{
- GList *optionl;
- FilterArg *arg;
- struct _FilterDriverPrivate *p = _PRIVATE(d);
-
- if (s) {
- g_string_append(s, "(and ");
- optionl = op->options;
- while (optionl) {
- struct filter_optionrule *or = optionl->data;
- if (or->rule->type == FILTER_XML_MATCH
- || or->rule->type == FILTER_XML_EXCEPT) {
- if (or->args)
- arg = or->args->data;
- expand_variables(s, or->rule->code, or->args, p->globals);
- }
- optionl = g_list_next(optionl);
- }
-
- g_string_append(s, ")");
- }
-
- if (action) {
- g_string_append(action, "(begin ");
- optionl = op->options;
- while (optionl) {
- struct filter_optionrule *or = optionl->data;
- if (or->rule->type == FILTER_XML_ACTION) {
- expand_variables(action, or->rule->code, or->args, p->globals);
- g_string_append(action, " ");
- }
- optionl = g_list_next(optionl);
- }
- g_string_append(action, ")");
- }
-}
-
static ESExpResult *
do_delete(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *d)
{
@@ -414,6 +299,13 @@ do_stop(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *d)
return NULL;
}
+static ESExpResult *
+do_colour(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *d)
+{
+ /* FIXME: implement */
+ return NULL;
+}
+
static CamelFolder *
open_folder(FilterDriver *d, const char *folder_url)
{
@@ -425,7 +317,7 @@ open_folder(FilterDriver *d, const char *folder_url)
if (camelfolder)
return camelfolder;
- camelfolder = p->fetcher(folder_url);
+ camelfolder = p->get_folder(d, folder_url, p->data);
if (camelfolder) {
g_hash_table_insert(p->folders, g_strdup(folder_url), camelfolder);
camel_folder_freeze(camelfolder);
@@ -461,6 +353,7 @@ close_folders(FilterDriver *d)
return 0;
}
+#if 0
int
filter_driver_rule_count(FilterDriver *d)
{
@@ -474,6 +367,7 @@ filter_driver_rule_get(FilterDriver *d, int n)
struct _FilterDriverPrivate *p = _PRIVATE(d);
return g_list_nth_data(p->options, n);
}
+#endif
static void
free_key (gpointer key, gpointer value, gpointer user_data)
@@ -486,13 +380,13 @@ filter_driver_run(FilterDriver *d, CamelFolder *source, CamelFolder *inbox)
{
struct _FilterDriverPrivate *p = _PRIVATE(d);
ESExpResult *r;
- GList *options;
GString *s, *a;
GPtrArray *all;
char *uid;
int i;
+ FilterFilter *rule;
-#warning "This must be made mega-robust"
+ /* FIXME: needs to check all failure cases */
p->source = source;
/* setup runtime data */
@@ -504,13 +398,18 @@ filter_driver_run(FilterDriver *d, CamelFolder *source, CamelFolder *inbox)
camel_exception_init(p->ex);
camel_folder_freeze(inbox);
- options = p->options;
- while (options) {
- struct filter_option *fo = options->data;
+ s = g_string_new("");
+ a = g_string_new("");
+
+ rule = NULL;
+ while ( (rule = (FilterFilter *)rule_context_next_rule((RuleContext *)p->context, (FilterRule *)rule)) ) {
+ g_string_truncate(s, 0);
+ g_string_truncate(a, 0);
+
+ filter_rule_build_code((FilterRule *)rule, s);
+ filter_filter_build_action(rule, a);
- s = g_string_new("");
- a = g_string_new("");
- filter_driver_expand_option(d, s, a, fo);
+ printf("applying rule %s\n action %s\n", s->str, a->str);
p->matches = camel_folder_search_by_expression (p->source, s->str, p->ex);
@@ -529,20 +428,19 @@ filter_driver_run(FilterDriver *d, CamelFolder *source, CamelFolder *inbox)
}
}
+#warning "Must check expression parsed and executed properly?"
e_sexp_input_text(p->eval, a->str, strlen(a->str));
e_sexp_parse(p->eval);
r = e_sexp_eval(p->eval);
e_sexp_result_free(r);
- g_string_free(s, TRUE);
- g_string_free(a, TRUE);
-
g_strfreev((char **)p->matches->pdata);
g_ptr_array_free(p->matches, FALSE);
-
- options = g_list_next(options);
}
+ g_string_free(s, TRUE);
+ g_string_free(a, TRUE);
+
/* Do any queued copies, and make sure everything is deleted from
* the source. If we have an inbox, anything that didn't get
* processed otherwise goes there.
diff --git a/filter/filter-driver.h b/filter/filter-driver.h
index a7a752aecd..9c3b56824a 100644
--- a/filter/filter-driver.h
+++ b/filter/filter-driver.h
@@ -25,7 +25,8 @@
#include <gtk/gtk.h>
#include <camel/camel-session.h>
#include <camel/camel-folder.h>
-#include "filter-xml.h"
+
+#include "filter-context.h"
#define FILTER_DRIVER(obj) GTK_CHECK_CAST (obj, filter_driver_get_type (), FilterDriver)
#define FILTER_DRIVER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_driver_get_type (), FilterDriverClass)
@@ -44,21 +45,24 @@ struct _FilterDriverClass {
GtkObjectClass parent_class;
};
-typedef CamelFolder *(*FilterFolderFetcher) (const char *uri);
+typedef CamelFolder * (*FilterGetFolderFunc) (FilterDriver *, const char *uri, void *data);
guint filter_driver_get_type (void);
-FilterDriver *filter_driver_new (const char *system, const char *user, FilterFolderFetcher fetcher);
+FilterDriver *filter_driver_new (FilterContext *ctx, FilterGetFolderFunc fetcher, void *data);
-void filter_driver_set_global(FilterDriver *, const char *name, const char *value);
+/*
+ void filter_driver_set_global(FilterDriver *, const char *name, const char *value);*/
/* apply rules to a folder, unmatched messages goto inbox, if not NULL */
int filter_driver_run(FilterDriver *d, CamelFolder *source, CamelFolder *inbox);
+#if 0
/* generate the search query/action string for a filter option */
void filter_driver_expand_option(FilterDriver *d, GString *s, GString *action, struct filter_option *op);
/* get info about rules (options) */
int filter_driver_rule_count(FilterDriver *d);
struct filter_option *filter_driver_rule_get(FilterDriver *d, int n);
+#endif
#endif /* ! _FILTER_DRIVER_H */
diff --git a/filter/filter-druid.c b/filter/filter-druid.c
deleted file mode 100644
index a90dd79a0e..0000000000
--- a/filter/filter-druid.c
+++ /dev/null
@@ -1,728 +0,0 @@
-/*
- * Copyright (C) 2000 Helix Code Inc.
- *
- * Authors: Michael Zucchi <notzed@helixcode.com>
- *
- * 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 <glib.h>
-#include <gtk/gtk.h>
-#include <gnome.h>
-#include <gtkhtml/gtkhtml.h>
-#include <string.h>
-
-#include <gnome-xml/tree.h>
-#include <gnome-xml/parser.h>
-
-#include "widgets/misc/e-scroll-frame.h"
-
-#include "filter-arg-types.h"
-#include "filter-xml.h"
-#include "filter-format.h"
-
-
-#include "filter-druid.h"
-
-static void filter_druid_class_init (FilterDruidClass *klass);
-static void filter_druid_init (FilterDruid *obj);
-
-#define _PRIVATE(x) (((FilterDruid *)(x))->priv)
-
-struct _FilterDruidPrivate {
- GtkWidget *notebook;
- int page;
-
- char *default_html;
-
- /* page 0 */
- GtkWidget *list0;
- GtkWidget *html0;
- GtkWidget *add0, *remove0, *up0, *down0;
- GList *items0;
- GtkFrame *listframe0;
-
- /* page 1 */
- GtkWidget *name1;
- GtkWidget *activate1;
- GtkHTML *html1;
-};
-
-/* forward ref's */
-static void build_druid(FilterDruid *d);
-static void update_display(FilterDruid *f, int initial);
-
-/* globals */
-static GtkNotebookClass *filter_druid_parent;
-
-enum SIGNALS {
- OPTION_SELECTED,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-guint
-filter_druid_get_type (void)
-{
- static guint type = 0;
-
- if (!type) {
- GtkTypeInfo type_info = {
- "FilterDruid",
- sizeof (FilterDruid),
- sizeof (FilterDruidClass),
- (GtkClassInitFunc) filter_druid_class_init,
- (GtkObjectInitFunc) filter_druid_init,
- (GtkArgSetFunc) NULL,
- (GtkArgGetFunc) NULL
- };
-
- type = gtk_type_unique (gtk_notebook_get_type (), &type_info);
- }
-
- return type;
-}
-
-static void
-object_destroy(GtkObject *obj)
-{
- struct _FilterDruidPrivate *p = _PRIVATE(obj);
-
- g_free(p->default_html);
-
- gtk_signal_disconnect_by_data((GtkObject *)p->list0, obj);
-
- /* FIXME: free lists? */
-
- GTK_OBJECT_CLASS(filter_druid_parent)->destroy(obj);
-}
-
-static void
-filter_druid_class_init (FilterDruidClass *klass)
-{
- GtkObjectClass *object_class = (GtkObjectClass *) klass;
-
- filter_druid_parent = gtk_type_class (gtk_notebook_get_type ());
-
- object_class->destroy = object_destroy;
-
- signals[OPTION_SELECTED] =
- gtk_signal_new ("option_selected",
- GTK_RUN_FIRST,
- object_class->type,
- GTK_SIGNAL_OFFSET (FilterDruidClass, option_selected),
- gtk_marshal_NONE__POINTER,
- GTK_TYPE_NONE, 1,
- GTK_TYPE_POINTER);
-
- gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
-}
-
-static void
-filter_druid_init (FilterDruid *obj)
-{
- struct _FilterDruidPrivate *priv;
-
- obj->priv = g_malloc0(sizeof(*obj->priv));
- priv = _PRIVATE(obj);
-}
-
-/**
- * filter_druid_new:
- *
- * Create a new FilterDruid object.
- *
- * Return value: A new FilterDruid widget.
- **/
-FilterDruid *
-filter_druid_new (void)
-{
- FilterDruid *new = FILTER_DRUID ( gtk_type_new (filter_druid_get_type ()));
-
- build_druid(new);
-
- return new;
-}
-
-
-extern int filter_find_arg(FilterArg *a, char *name);
-
-#include "check.xpm"
-#include "blank.xpm"
-
-
-struct filter_optionrule *
-find_optionrule(struct filter_option *option, char *name)
-{
- GList *optionrulel;
- struct filter_optionrule *or;
-
- optionrulel = option->options;
- while (optionrulel) {
- or = optionrulel->data;
- if (!strcmp(or->rule->name, name)) {
- return or;
- }
- optionrulel = g_list_next(optionrulel);
- }
- return NULL;
-}
-
-static int display_order[] = {
- FILTER_XML_MATCH,
- FILTER_XML_EXCEPT,
- FILTER_XML_ACTION,
-};
-static char *display_pretext[] = {
- "<b>For messages matching:</b><ul>",
- "<b>Unless:</b><ul>",
- "<b>Perform these actions:</b><ul>",
-};
-static char *display_posttext[] = {
- "</ul>",
- "</ul>",
- "</ul>",
-};
-
-void
-html_write_options(GtkHTML *html, struct filter_option *option, char *def)
-{
- GtkHTMLStream *stream;
- GList *optionrulel;
- int i;
-
- stream = gtk_html_begin(html);
-
- gtk_html_write(html, stream, "<body bgcolor=white alink=blue>", strlen("<body bgcolor=white alink=blue>"));
- if (option) {
- char *t;
-
- if (option->type == FILTER_XML_SEND) {
- t = "<p>When a message is <i>sent</i>.</p>";
- } else {
- t = "<p>When a message is <i>received</i>.</p>";
- }
- gtk_html_write(html, stream, t, strlen(t));
-
- for (i=0;i<sizeof(display_order)/sizeof(display_order[0]);i++) {
- int doneheader = FALSE;
- int donefirst = FALSE;
- optionrulel = option->options;
- while (optionrulel) {
- struct filter_optionrule *or = optionrulel->data;
-
- if (or->rule->type == display_order[i]) {
- if (!doneheader) {
- gtk_html_write(html, stream, display_pretext[i], strlen(display_pretext[i]));
- doneheader = TRUE;
- }
-
- if (donefirst) {
- gtk_html_write(html, stream, "&nbsp;&nbsp;&nbsp;<i>and</i> ", strlen("&nbsp;&nbsp;&nbsp;<i>and</i> "));
- }
- filter_description_html_write(or->rule->description, or->args, html, stream);
- donefirst = TRUE;
- gtk_html_write(html, stream, "<br>", strlen("<br>"));
- }
- optionrulel = g_list_next(optionrulel);
- }
- if (doneheader) {
- gtk_html_write(html, stream, display_posttext[i], strlen(display_posttext[i]));
- }
- }
- } else {
- if (def == NULL)
- def = "Select options.";
- gtk_html_write(html, stream, def, strlen(def));
- }
- gtk_html_end(html, stream, GTK_HTML_STREAM_OK);
-}
-
-GList *
-fill_rules(GList *rules, struct filter_option *option, int type)
-{
- GList *rulel;
- GtkWidget *listitem, *hbox, *checkbox, *label;
- GList *items = NULL;
-
- rulel = rules;
- while (rulel) {
- struct filter_rule *fr = rulel->data;
- char *labeltext;
-
- if (fr->type == type) {
- int state;
-
- state = find_optionrule(option, fr->name) != NULL;
-
- labeltext = filter_description_text(fr->description, NULL);
-
- hbox = gtk_hbox_new(FALSE, 3);
- checkbox = gnome_pixmap_new_from_xpm_d(state?check_xpm:blank_xpm);
- gtk_box_pack_start(GTK_BOX(hbox), checkbox, FALSE, FALSE, 0);
- label = gtk_label_new(labeltext);
- gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
- listitem = gtk_list_item_new();
- gtk_container_add(GTK_CONTAINER(listitem), hbox);
- gtk_widget_show_all(listitem);
-
- gtk_object_set_data(GTK_OBJECT(listitem), "checkbox", checkbox);
- gtk_object_set_data(GTK_OBJECT(listitem), "checkstate", (void *)state);
- gtk_object_set_data(GTK_OBJECT(listitem), "rule", fr);
-
- items = g_list_append(items, listitem);
- }
- rulel = g_list_next(rulel);
- }
- return items;
-}
-
-GList *
-fill_options(GList *options)
-{
- GList *optionl;
- GtkWidget *listitem;
- GList *items = NULL;
-
- optionl = options;
- while (optionl) {
- struct filter_option *op = optionl->data;
- char *labeltext;
-
- labeltext = filter_description_text(op->description, NULL);
- listitem = gtk_list_item_new_with_label(labeltext);
- g_free(labeltext);
- gtk_widget_show_all(listitem);
-
- gtk_object_set_data(GTK_OBJECT(listitem), "option", op);
-
- items = g_list_append(items, listitem);
- optionl = g_list_next(optionl);
- }
- return items;
-}
-
-static void
-select_rule_child(GtkList *list, GtkWidget *child, FilterDruid *f)
-{
- GtkWidget *w;
- struct filter_rule *fr = gtk_object_get_data(GTK_OBJECT(child), "rule");
- int state;
- struct filter_optionrule *rule;
- /*struct _FilterDruidPrivate *p = _PRIVATE(f);*/
-
- w = gtk_object_get_data(GTK_OBJECT(child), "checkbox");
- state = !(int) gtk_object_get_data(GTK_OBJECT(child), "checkstate");
-
- gnome_pixmap_load_xpm_d(GNOME_PIXMAP(w), state?check_xpm:blank_xpm);
- gtk_object_set_data(GTK_OBJECT(child), "checkstate", (void *)state);
-
- if (state) {
- rule = filter_optionrule_new_from_rule(fr);
- f->option_current->options = g_list_append(f->option_current->options, rule);
- } else {
- rule = find_optionrule(f->option_current, fr->name);
- if (rule) {
- f->option_current->options = g_list_remove(f->option_current->options, rule);
- filter_clone_optionrule_free(rule);
- }
- }
-
- update_display(f, 0);
-}
-
-
-
-static void
-select_option_child(GtkList *list, GtkWidget *child, FilterDruid *f)
-{
- struct filter_option *op;
- struct filter_option *new;
- GList *optionsl;
- struct _FilterDruidPrivate *p = _PRIVATE(f);
-
- switch (p->page) {
- case 1:
- case 2:
- case 3:
- select_rule_child(list, child, f);
- default:
- return;
- case 0:
- break;
- }
-
- if (f->option_current) {
- /* free option_current copy */
- optionsl = f->option_current->options;
- while (optionsl) {
- GList *op = optionsl;
- optionsl = g_list_next(optionsl);
- filter_clone_optionrule_free(op->data);
- }
- g_list_free(f->option_current->options);
- g_free(f->option_current);
- f->option_current = NULL;
- }
-
- if (child) {
- op = gtk_object_get_data(GTK_OBJECT(child), "option");
-
- /* clone the option */
- new = g_malloc(sizeof(*new));
- new->type = op->type;
- new->description = op->description;
- new->options = NULL;
- optionsl = op->options;
- while (optionsl) {
- struct filter_optionrule *ornew,
- *or = optionsl->data;
- ornew = filter_clone_optionrule(or);
- new->options = g_list_append(new->options, ornew);
- optionsl = g_list_next(optionsl);
- }
- f->option_current = new;
-
- gtk_signal_emit(GTK_OBJECT(f), signals[OPTION_SELECTED], op);
- }
-
- update_display(f, 0);
-}
-
-static void
-unselect_option_child(GtkList *list, GtkWidget *child, FilterDruid *f)
-{
- select_option_child(list, NULL, f);
-}
-
-static void
-arg_changed(FilterArg *arg, FilterDruid *f)
-{
- FilterArg *orig;
-
- orig = gtk_object_get_data(GTK_OBJECT (arg), "origin");
- if (orig) {
- filter_arg_copy(orig, arg);
- update_display(f, 0);
- } else {
- /* FIXME: uh, what the fuck to do here? */
- update_display(f, 0);
- }
-}
-
-static void
-arg_link_clicked(GtkHTML *html, const char *url, FilterDruid *f)
-{
- if (!strncmp(url, "arg:", 4)) {
- FilterArg *arg;
- void *dummy;
-
- if ((sscanf(url+4, "%p %p", &dummy, &arg) == 2) && arg) {
- gtk_signal_connect(GTK_OBJECT (arg), "changed", arg_changed, f);
- filter_arg_edit_values(arg);
- }
- }
-}
-
-static void
-option_name_changed(GtkEntry *entry, FilterDruid *f)
-{
- struct filter_desc *desc;
-
- if (f->option_current) {
- /* FIXME: lots of memory leaks */
- desc = g_malloc0(sizeof(*desc));
- desc->data = g_strdup(gtk_entry_get_text(entry));
- desc->type = FILTER_XML_TEXT;
- desc->vartype = -1;
- desc->varname = NULL;
-#warning "Zucchi: is this correct?"
- filter_description_free (f->option_current->description);
- f->option_current->description = g_list_append(NULL, desc);
- }
-}
-
-static void
-dialogue_clicked(FilterDruid *d, int button, void *data)
-{
- GString *s = g_string_new("");
- struct _FilterDruidPrivate *p = _PRIVATE(d);
- int initial=0;
-
- g_string_free(s, TRUE);
-
- switch(button) {
- case 1:
- if (p->page<4) {
- p->page++;
- initial =1;
- }
- break;
- case 0:
- if (p->page>0) {
- p->page--;
- initial = 1;
- }
- break;
- }
- update_display(d, initial);
-}
-
-static int filter_types[] = { FILTER_XML_MATCH, FILTER_XML_EXCEPT, FILTER_XML_ACTION };
-static char *filter_titles[] = {
- "Select rule(s), where messages match",
- "Select rule(s), where messages do not match",
- "Select action(s) to apply to messages"
-
-};
-static void
-update_display(FilterDruid *f, int initial)
-{
- struct _FilterDruidPrivate *p = _PRIVATE(f);
-
- switch (p->page) {
- case 0:
- if (initial) {
- gtk_signal_handler_block_by_data((GtkObject *)p->list0, f);
- gtk_list_remove_items((GtkList *)p->list0, p->items0);
- p->items0 = fill_options(f->options);
- gtk_list_append_items((GtkList *)p->list0, p->items0);
- gtk_signal_handler_unblock_by_data((GtkObject *)p->list0, f);
- gtk_frame_set_label(p->listframe0, "Select rule type");
- }
-
- html_write_options((GtkHTML *)p->html0, f->option_current, p->default_html);
- break;
- case 1:
- case 2:
- case 3:
- if (initial) {
- gtk_signal_handler_block_by_data((GtkObject *)p->list0, f);
- gtk_list_remove_items((GtkList *)p->list0, p->items0);
- p->items0 = fill_rules(f->rules, f->option_current, filter_types[p->page-1]);
- gtk_list_append_items((GtkList *)p->list0, p->items0);
- gtk_signal_handler_unblock_by_data((GtkObject *)p->list0, f);
- gtk_frame_set_label(p->listframe0, filter_titles[p->page-1]);
- gtk_notebook_set_page(GTK_NOTEBOOK(p->notebook), 0);
- }
-
- html_write_options((GtkHTML *)p->html0, f->option_current, p->default_html);
- break;
- case 4:
- if (initial) {
- char *text;
- text = filter_description_text(f->option_current->description, NULL);
- if (text == NULL) {
- /* maybe this could fudge something out of the first
- bits of the rule */
- if (f->option_current->type == FILTER_XML_SEND) {
- text = "Filter messages sent";
- } else {
- text = "Filter messages received";
- }
- gtk_entry_set_text(GTK_ENTRY(p->name1), text);
- } else {
- gtk_entry_set_text(GTK_ENTRY(p->name1), text);
- g_free(text);
- }
- gtk_notebook_set_page(GTK_NOTEBOOK(p->notebook), 1);
- }
-
- html_write_options((GtkHTML *)p->html1, f->option_current, p->default_html);
- break;
-
- }
-}
-
-void
-filter_druid_set_rules(FilterDruid *f, GList *options, GList *rules, struct filter_option *current)
-{
- struct filter_option *new;
- GList *optionsl;
-
- f->options = options;
- f->rules = rules;
- f->user = NULL;
-
- if (current) {
- /* FIXME: free this list if it isn't empty ... */
- /* clone the 'current' option */
- new = g_malloc(sizeof(*new));
- new->type = current->type;
- new->description = current->description;
- new->options = NULL;
- optionsl = current->options;
- while (optionsl) {
- struct filter_optionrule *ornew,
- *or = optionsl->data;
- ornew = filter_clone_optionrule(or);
- new->options = g_list_append(new->options, ornew);
- optionsl = g_list_next(optionsl);
- }
- f->option_current = new;
- } else {
- f->option_current = NULL;
- }
-
- update_display(f, 1);
-}
-
-static void
-build_druid(FilterDruid *d)
-{
- GtkWidget *vbox, *frame, *scrolled_window, *list, *html, *label;
- GtkWidget *table;
- struct _FilterDruidPrivate *p = _PRIVATE(d);
-
-#if 0
- gnome_dialog_append_buttons((GnomeDialog *)d, "Prev", "Next", "Finish", "Cancel", 0);
- gnome_dialog_set_close((GnomeDialog *)d, FALSE);
- gnome_dialog_set_sensitive((GnomeDialog *)d, 0, FALSE);
- gnome_dialog_set_sensitive((GnomeDialog *)d, 1, FALSE);
- gnome_dialog_set_sensitive((GnomeDialog *)d, 2, FALSE);
- gnome_dialog_set_default((GnomeDialog *)d, 1);
-#endif
-
- p->notebook = GTK_WIDGET (d);
- gtk_notebook_set_show_tabs(GTK_NOTEBOOK(p->notebook), FALSE);
- gtk_notebook_set_show_border(GTK_NOTEBOOK(p->notebook), FALSE);
-
- /* page0, initial setup page */
- vbox = gtk_vbox_new(FALSE, 3);
- frame = gtk_frame_new("Filters");
- p->listframe0 = (GtkFrame *)frame;
-
- list = gtk_list_new();
- scrolled_window = gtk_scrolled_window_new(NULL, NULL);
- gtk_widget_set_usize(scrolled_window, 400, 150);
- gtk_container_set_border_width(GTK_CONTAINER(scrolled_window), GNOME_PAD_SMALL);
- gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), list);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC);
- gtk_container_set_focus_vadjustment
- (GTK_CONTAINER (list),
- gtk_scrolled_window_get_vadjustment
- (GTK_SCROLLED_WINDOW (scrolled_window)));
- gtk_container_add(GTK_CONTAINER(frame), scrolled_window);
- gtk_box_pack_start((GtkBox *)vbox, frame, TRUE, TRUE, 0);
-
- frame = gtk_frame_new("Filter Description (click on values to edit)");
- html = gtk_html_new();
- scrolled_window = e_scroll_frame_new (NULL, NULL);
- gtk_widget_set_usize(scrolled_window, 400, 150);
- gtk_container_set_border_width(GTK_CONTAINER(scrolled_window), GNOME_PAD_SMALL);
- e_scroll_frame_set_policy (E_SCROLL_FRAME (scrolled_window),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC);
- e_scroll_frame_set_shadow_type (E_SCROLL_FRAME (scrolled_window),
- GTK_SHADOW_IN);
- /*gtk_container_add(GTK_CONTAINER(frame1), html);*/
- gtk_container_add(GTK_CONTAINER(scrolled_window), html);//frame1);
- gtk_container_add(GTK_CONTAINER(frame), scrolled_window);
- gtk_box_pack_start((GtkBox *)vbox, frame, TRUE, TRUE, 0);
-
- p->html0 = html;
- p->list0 = list;
-
- gtk_signal_connect(GTK_OBJECT(list), "select_child", select_option_child, d);
- gtk_signal_connect(GTK_OBJECT(list), "unselect_child", select_option_child, d);
-/* gtk_signal_connect(GTK_OBJECT(list), "unselect_child", unselect_option_child, d); */
-/* gtk_signal_connect(GTK_OBJECT(d), "clicked", dialogue_clicked, d);*/
-
- gtk_signal_connect(GTK_OBJECT(html), "link_clicked", arg_link_clicked, d);
-
- gtk_notebook_append_page(GTK_NOTEBOOK(p->notebook), vbox, NULL);
-
-
- /* page1, used for the final page display */
- vbox = gtk_vbox_new(FALSE, 3);
-
- frame = gtk_frame_new("Rule options");
- gtk_box_pack_start((GtkBox *)vbox, frame, FALSE, FALSE, 0);
-
- table = gtk_table_new (2, 2, FALSE);
- gtk_container_set_border_width (GTK_CONTAINER (table), GNOME_PAD_SMALL);
- gtk_table_set_row_spacings (GTK_TABLE (table), GNOME_PAD_SMALL);
- gtk_table_set_col_spacings (GTK_TABLE (table), GNOME_PAD_SMALL);
-
- gtk_container_add(GTK_CONTAINER(frame), table);
-
- label = gtk_label_new("Name of rule");
- p->name1 = gtk_entry_new();
- gtk_signal_connect(GTK_OBJECT(p->name1), "changed", option_name_changed, d);
-
- p->activate1 = gtk_check_button_new_with_label("Activate rule?");
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p->activate1), TRUE);
-
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, 0, 0, 0, 0);
- gtk_table_attach (GTK_TABLE (table), p->name1, 1, 2, 0, 1,
- GTK_FILL | GTK_EXPAND, 0, 0, 0);
- gtk_table_attach (GTK_TABLE (table), p->activate1, 0, 2, 1, 2,
- GTK_FILL | GTK_EXPAND, 0, 0, 0);
-
- /* another copy of the filter thingy */
- frame = gtk_frame_new("Filter Description (click on values to edit)");
- html = gtk_html_new();
- p->html1 = (GtkHTML *)html;
- scrolled_window = e_scroll_frame_new (NULL, NULL);
- gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), GNOME_PAD_SMALL);
- e_scroll_frame_set_shadow_type (E_SCROLL_FRAME (scrolled_window),
- GTK_SHADOW_IN);
- gtk_widget_set_usize(scrolled_window, 400, 150);
- e_scroll_frame_set_policy (E_SCROLL_FRAME (scrolled_window),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC);
- gtk_container_add(GTK_CONTAINER(scrolled_window), html);
- gtk_container_add(GTK_CONTAINER(frame), scrolled_window);
- gtk_box_pack_start((GtkBox *)vbox, frame, TRUE, TRUE, 0);
-
- /* finish off */
- gtk_notebook_append_page(GTK_NOTEBOOK(p->notebook), vbox, NULL);
-
- gtk_signal_connect(GTK_OBJECT(html), "link_clicked", arg_link_clicked, d);
-
- gtk_widget_show_all(p->notebook);
-}
-
-void
-filter_druid_set_page(FilterDruid *f, enum FilterDruidPage page)
-{
- struct _FilterDruidPrivate *p = _PRIVATE(f);
- int initial = p->page != page;
-
- p->page = page;
- update_display(f, initial);
-}
-
-
-void
-filter_druid_set_default_html(FilterDruid *f, const char *html)
-{
- struct _FilterDruidPrivate *p = _PRIVATE(f);
-
- g_free(p->default_html);
- p->default_html = g_strdup(html);
-}
-
-enum FilterDruidPage
-filter_druid_get_page(FilterDruid *f)
-{
- struct _FilterDruidPrivate *p = _PRIVATE(f);
-
- return p->page;
-}
-
diff --git a/filter/filter-druid.h b/filter/filter-druid.h
deleted file mode 100644
index 7927dc70dd..0000000000
--- a/filter/filter-druid.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2000 Helix Code Inc.
- *
- * Authors: Michael Zucchi <notzed@helixcode.com>
- *
- * 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_DRUID_H
-#define _FILTER_DRUID_H
-
-#include <gtk/gtk.h>
-
-#include "filter-xml.h"
-
-#define FILTER_DRUID(obj) GTK_CHECK_CAST (obj, filter_druid_get_type (), FilterDruid)
-#define FILTER_DRUID_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_druid_get_type (), FilterDruidClass)
-#define IS_FILTER_DRUID(obj) GTK_CHECK_TYPE (obj, filter_druid_get_type ())
-
-typedef struct _FilterDruid FilterDruid;
-typedef struct _FilterDruidClass FilterDruidClass;
-
-enum FilterDruidPage {
- FILTER_DRUID_SELECT_RULE,
- FILTER_DRUID_SELECT_MATCH,
- FILTER_DRUID_SELECT_NOMATCH,
- FILTER_DRUID_SELECT_ACTION,
- FILTER_DRUID_SELECT_FINISH
-};
-
-struct _FilterDruid {
- GtkNotebook parent;
-
- GList *options; /* all options */
- GList *rules; /* all rules */
- GList *user; /* current user options */
-
- struct filter_option *option_current;
-
- struct _FilterDruidPrivate *priv;
-};
-
-struct _FilterDruidClass {
- GtkNotebookClass parent_class;
-
- /* signals */
- void (*option_selected)(FilterDruid *f, struct filter_option *option);
-};
-
-guint filter_druid_get_type (void);
-FilterDruid *filter_druid_new (void);
-
-/* Hmm, glists suck, no typesafety */
-void filter_druid_set_rules(FilterDruid *f, GList *options, GList *rules, struct filter_option *userrule);
-void filter_druid_set_default_html(FilterDruid *f, const char *text);
-
-/* set the page of display */
-void filter_druid_set_page(FilterDruid *f, enum FilterDruidPage page);
-enum FilterDruidPage filter_druid_get_page(FilterDruid *f);
-
-/* check if the druid is allowed to finish at this point */
-gboolean filter_druid_can_finish(FilterDruid *f);
-
-#endif /* ! _FILTER_DRUID_H */
diff --git a/filter/filter-editor.c b/filter/filter-editor.c
index 3bd239befa..368a5fbcfc 100644
--- a/filter/filter-editor.c
+++ b/filter/filter-editor.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2000 Helix Code Inc.
*
- * Authors: Michael Zucchi <notzed@helixcode.com>
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
@@ -18,30 +18,29 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <gnome-xml/parser.h>
-#include "filter-druid.h"
-#include "filter-editor.h"
+#include <gtk/gtk.h>
+#include <gnome.h>
+#include <glade/glade.h>
+#include "filter-editor.h"
+#include "filter-context.h"
+#include "filter-filter.h"
-static void filter_editor_class_init (FilterEditorClass *klass);
-static void filter_editor_init (FilterEditor *obj);
+#define d(x)
-static GnomeDialogClass *filter_editor_parent;
+#if 0
+static void filter_editor_class_init (FilterEditorClass *class);
+static void filter_editor_init (FilterEditor *gspaper);
+static void filter_editor_finalise (GtkObject *obj);
#define _PRIVATE(x) (((FilterEditor *)(x))->priv)
struct _FilterEditorPrivate {
- FilterDruid *druid;
-
- GtkWidget *edit, *add, *remove, *up, *down;
-
- /* for sub-druid */
- struct filter_option *druid_option;
- GtkWidget *druid_dialogue;
- FilterDruid *druid_druid;
};
-enum SIGNALS {
+static GnomeDialogClass *parent_class;
+
+enum {
LAST_SIGNAL
};
@@ -55,354 +54,296 @@ filter_editor_get_type (void)
if (!type) {
GtkTypeInfo type_info = {
"FilterEditor",
- sizeof (FilterEditor),
- sizeof (FilterEditorClass),
- (GtkClassInitFunc) filter_editor_class_init,
- (GtkObjectInitFunc) filter_editor_init,
- (GtkArgSetFunc) NULL,
- (GtkArgGetFunc) NULL
+ sizeof(FilterEditor),
+ sizeof(FilterEditorClass),
+ (GtkClassInitFunc)filter_editor_class_init,
+ (GtkObjectInitFunc)filter_editor_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
};
- type = gtk_type_unique (gnome_dialog_get_type (), &type_info);
+ type = gtk_type_unique(gnome_dialog_get_type (), &type_info);
}
return type;
}
static void
-object_destroy(GtkObject *obj)
+filter_editor_class_init (FilterEditorClass *class)
{
- struct _FilterEditorPrivate *p = _PRIVATE(obj);
-
- if (p->druid_druid)
- gtk_object_unref(GTK_OBJECT (p->druid_dialogue));
-
- GTK_OBJECT_CLASS(filter_editor_parent)->destroy(GTK_OBJECT (obj));
-}
-
-static void
-filter_editor_class_init (FilterEditorClass *klass)
-{
- GtkObjectClass *object_class = (GtkObjectClass *) klass;
+ GtkObjectClass *object_class;
- filter_editor_parent = gtk_type_class (gnome_dialog_get_type ());
-
- object_class->destroy = object_destroy;
-
- gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
-}
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(gnome_dialog_get_type ());
-static void
-filter_editor_init (FilterEditor *obj)
-{
- obj->priv = g_malloc0(sizeof(*obj->priv));
-}
+ object_class->finalize = filter_editor_finalise;
+ /* override methods */
+ /* signals */
-static void
-sensitise(FilterEditor *e)
-{
- struct _FilterEditorPrivate *p = _PRIVATE(e);
-
- gtk_widget_set_sensitive(p->add, TRUE);
- gtk_widget_set_sensitive(p->edit, e->option_current != NULL);
- gtk_widget_set_sensitive(p->remove, e->option_current != NULL);
- gtk_widget_set_sensitive(p->up, g_list_index(e->useroptions, e->option_current)>0);
- gtk_widget_set_sensitive(p->down, g_list_index(e->useroptions, e->option_current)!=g_list_length(e->useroptions)-1);
+ gtk_object_class_add_signals(object_class, signals, LAST_SIGNAL);
}
static void
-druid_option_selected(FilterDruid *f, struct filter_option *option, FilterEditor *e)
+filter_editor_init (FilterEditor *o)
{
- e->option_current = option;
- sensitise(e);
+ o->priv = g_malloc0(sizeof(*o->priv));
}
static void
-druid_dialogue_clicked(GnomeDialog *d, int button, FilterEditor *e)
+filter_editor_finalise(GtkObject *obj)
{
- struct _FilterEditorPrivate *p = _PRIVATE(e);
- int page = filter_druid_get_page(p->druid_druid);
+ FilterEditor *o = (FilterEditor *)obj;
- switch(button) {
- case 1:
- if (page<4) {
- page++;
- }
- break;
- case 0:
- if (page>0) {
- page--;
- }
- break;
- case 2:
- if (p->druid_druid->option_current) {
-#warning "what is going on here?"
- /* FIXME: should this be struct filter_option?? */
- struct filter_option *or;
-
- printf("refcount = %d\n", ((GtkObject *)p->druid_druid)->ref_count);
-
- or = p->druid_druid->option_current;
- if (p->druid_option) {
- GList *node;
-
- node = g_list_find(e->useroptions, p->druid_option);
- if (node) {
- /* FIXME: free old one */
- /* we need to know what type or is supposed to be before
- we can free old data */
- node->data = or;
- } else {
- g_warning("Cannot find node I edited, appending instead");
- e->useroptions = g_list_append(e->useroptions, or);
- }
- } else {
- e->useroptions = g_list_append(e->useroptions, or);
- }
- filter_druid_set_rules(p->druid, e->useroptions, e->rules, or);
- }
- case 3:
- p->druid_dialogue = NULL;
- gnome_dialog_close(d);
- return;
- }
- filter_druid_set_page(p->druid_druid, page);
-
- gnome_dialog_set_sensitive(GNOME_DIALOG (p->druid_dialogue), 0, page > 0);
- gnome_dialog_set_sensitive(GNOME_DIALOG (p->druid_dialogue), 1, page < 4);
- /* FIXME: make this depenedant on when the rules are actually done */
- gnome_dialog_set_sensitive(GNOME_DIALOG (p->druid_dialogue), 2, page == 4);
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
}
-static void
-druid_dialogue_option_selected(FilterDruid *f, struct filter_option *option, FilterEditor *e)
+/**
+ * filter_editor_new:
+ *
+ * Create a new FilterEditor object.
+ *
+ * Return value: A new #FilterEditor object.
+ **/
+FilterEditor *
+filter_editor_new(void)
{
- struct _FilterEditorPrivate *p = _PRIVATE(e);
-
- gnome_dialog_set_sensitive(GNOME_DIALOG (p->druid_dialogue), 1, TRUE);
+ FilterEditor *o = (FilterEditor *)gtk_type_new(filter_editor_get_type ());
+ return o;
}
-static void
-add_or_edit(FilterEditor *e, struct filter_option *option)
-{
- GnomeDialog *dialogue;
- FilterDruid *druid;
- struct _FilterEditorPrivate *p = _PRIVATE(e);
-
- if (p->druid_dialogue) {
- gdk_window_raise(GTK_WIDGET(p->druid_dialogue)->window);
- return;
- }
-
- dialogue = GNOME_DIALOG (gnome_dialog_new (option ? _("Edit Filter") : _("Create filter"), NULL));
- p->druid_dialogue = GTK_WIDGET (dialogue);
- {
- const char *pixmaps[] = {
- GNOME_STOCK_BUTTON_PREV,
- GNOME_STOCK_BUTTON_NEXT,
- GNOME_STOCK_BUTTON_APPLY,
- GNOME_STOCK_BUTTON_CANCEL,
- NULL
- };
- const char *names[] = {
- N_("Back"),
- N_("Next"),
- N_("Finish"),
- N_("Cancel"),
- NULL
- };
- if (option)
- names[2] = N_("Apply");
- gnome_dialog_append_buttons_with_pixmaps(dialogue, names, pixmaps);
- }
-
- gnome_dialog_set_close(dialogue, FALSE);
- gnome_dialog_set_sensitive(dialogue, 0, FALSE);
- gnome_dialog_set_sensitive(dialogue, 1, FALSE);
- gnome_dialog_set_sensitive(dialogue, 2, FALSE);
- gnome_dialog_set_default(dialogue, 1);
-
- gtk_signal_connect(GTK_OBJECT (dialogue), "clicked", druid_dialogue_clicked, e);
-
- druid = FILTER_DRUID (filter_druid_new());
-
- p->druid_druid = druid;
-
- filter_druid_set_default_html(p->druid_druid,
- _("<h2>Create Filtering Rule</h2>"
- "<p>Select one of the base rules above, then continue "
- "forwards to customise it.</p>"));
-
- filter_druid_set_rules(druid, e->systemoptions, e->rules, option);
- gtk_box_pack_start(GTK_BOX (dialogue->vbox), GTK_WIDGET (druid), TRUE, TRUE, 0);
-
- if (option) {
- druid_dialogue_clicked(dialogue, 1, e);
- }
-
- p->druid_option = option;
+#endif
- gtk_signal_connect(GTK_OBJECT (druid), "option_selected", druid_dialogue_option_selected, e);
- gtk_widget_show(GTK_WIDGET (druid));
- gtk_widget_show(GTK_WIDGET (dialogue));
-}
+enum {
+ BUTTON_ADD,
+ BUTTON_EDIT,
+ BUTTON_DELETE,
+ BUTTON_UP,
+ BUTTON_DOWN,
+ BUTTON_LAST
+};
-static void
-add_clicked(GtkWidget *w, FilterEditor *e)
-{
- add_or_edit(e, NULL);
-}
+struct _editor_data {
+ RuleContext *f;
+ FilterRule *current;
+ GtkList *list;
+ GtkButton *buttons[BUTTON_LAST];
+};
-static void
-edit_clicked(GtkWidget *w, FilterEditor *e)
-{
- add_or_edit(e, e->option_current);
-}
+static void set_sensitive(struct _editor_data *data);
-static void
-remove_clicked(GtkWidget *w, FilterEditor *e)
+static void rule_add(GtkWidget *widget, struct _editor_data *data)
{
- printf("remove current ...\n");
+ FilterFilter *rule;
+ int result;
+ GnomeDialog *gd;
+ GtkWidget *w;
+ FilterPart *part;
+
+ d(printf("add rule\n"));
+ /* create a new rule with 1 match and 1 action */
+ rule = filter_filter_new();
+
+ part = rule_context_next_part(data->f, NULL);
+ filter_rule_add_part((FilterRule *)rule, filter_part_clone(part));
+ part = filter_context_next_action((FilterContext *)data->f, NULL);
+ filter_filter_add_action(rule, filter_part_clone(part));
+
+ w = filter_rule_get_widget((FilterRule *)rule, data->f);
+ gd = (GnomeDialog *)gnome_dialog_new("Add Rule", "Ok", "Cancel", NULL);
+ gtk_box_pack_start((GtkBox *)gd->vbox, w, FALSE, TRUE, 0);
+ gtk_widget_show((GtkWidget *)gd);
+ result = gnome_dialog_run_and_close(gd);
+ if (result == 0) {
+ GtkListItem *item = (GtkListItem *)gtk_list_item_new_with_label(((FilterRule *)rule)->name);
+ GList *l = NULL;
+
+ gtk_object_set_data((GtkObject *)item, "rule", rule);
+ gtk_widget_show((GtkWidget *)item);
+ l = g_list_append(l, item);
+ gtk_list_append_items(data->list, l);
+ gtk_list_select_child(data->list, (GtkWidget *)item);
+ data->current = (FilterRule *)rule;
+ rule_context_add_rule(data->f, (FilterRule *)rule);
+ set_sensitive(data);
+ } else {
+ gtk_object_unref((GtkObject *)rule);
+ }
}
-static void
-up_clicked(GtkWidget *w, FilterEditor *e)
+static void rule_edit(GtkWidget *widget, struct _editor_data *data)
{
- printf("up ...\n");
+ GtkWidget *w;
+ int result;
+ GnomeDialog *gd;
+ FilterRule *rule;
+ int pos;
+
+ d(printf("edit rule\n"));
+ rule = data->current;
+ w = filter_rule_get_widget(rule, data->f);
+ gd = (GnomeDialog *)gnome_dialog_new("Edit Rule", "Ok", NULL);
+ gtk_box_pack_start((GtkBox *)gd->vbox, w, FALSE, TRUE, 0);
+ gtk_widget_show((GtkWidget *)gd);
+ result = gnome_dialog_run_and_close(gd);
+
+ if (result == 0) {
+ pos = rule_context_get_rank_rule(data->f, data->current);
+ if (pos != -1) {
+ GtkListItem *item = g_list_nth_data(data->list->children, pos);
+ gtk_label_set_text((GtkLabel *)(((GtkBin *)item)->child), data->current->name);
+ }
+ }
}
-static void
-down_clicked(GtkWidget *w, FilterEditor *e)
+static void rule_delete(GtkWidget *widget, struct _editor_data *data)
{
- printf("down ...\n");
+ int pos;
+ GList *l;
+ GtkListItem *item;
+
+ d(printf("ddelete rule\n"));
+ pos = rule_context_get_rank_rule(data->f, data->current);
+ if (pos != -1) {
+ rule_context_remove_rule(data->f, data->current);
+
+ item = g_list_nth_data(data->list->children, pos);
+ l = g_list_append(NULL, item);
+ gtk_list_remove_items(data->list, l);
+ g_list_free(l);
+
+ gtk_object_unref((GtkObject *)data->current);
+ data->current = NULL;
+ }
+ set_sensitive(data);
}
-/* build the contents of the editor */
-static void
-build_editor(FilterEditor *e)
+static void rule_move(struct _editor_data *data, int from, int to)
{
- struct _FilterEditorPrivate *p = _PRIVATE(e);
- GtkWidget *hbox;
- GtkWidget *vbox;
+ GList *l;
+ GtkListItem *item;
- hbox = gtk_hbox_new(FALSE, 3);
-
- p->druid = FILTER_DRUID (filter_druid_new());
- gtk_box_pack_start(GTK_BOX (hbox), GTK_WIDGET (p->druid), TRUE, TRUE, 0);
-
- vbox = gtk_vbox_new(FALSE, 0);
+ d(printf("moving %d to %d\n", from, to));
+ rule_context_rank_rule(data->f, data->current, to);
- p->edit = gtk_button_new_with_label ("Edit");
- p->add = gtk_button_new_with_label ("Add");
- p->remove = gtk_button_new_with_label ("Remove");
- p->up = gtk_button_new_with_label ("Up");
- p->down = gtk_button_new_with_label ("Down");
-
- gtk_box_pack_start(GTK_BOX (vbox), p->edit, FALSE, TRUE, 0);
- gtk_box_pack_start(GTK_BOX (vbox), p->add, FALSE, TRUE, 3);
- gtk_box_pack_start(GTK_BOX (vbox), p->remove, FALSE, TRUE, 0);
- gtk_box_pack_start(GTK_BOX (vbox), p->up, FALSE, TRUE, 3);
- gtk_box_pack_start(GTK_BOX (vbox), p->down, FALSE, TRUE, 0);
-
- gtk_box_pack_start(GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
-
- gtk_box_pack_start(GTK_BOX (e->parent.vbox), hbox, TRUE, TRUE, 0);
-
- gtk_signal_connect(GTK_OBJECT (p->druid), "option_selected", druid_option_selected, e);
-
- gtk_signal_connect(GTK_OBJECT (p->edit), "clicked", edit_clicked, e);
- gtk_signal_connect(GTK_OBJECT (p->add), "clicked", add_clicked, e);
- gtk_signal_connect(GTK_OBJECT (p->remove), "clicked", remove_clicked, e);
- gtk_signal_connect(GTK_OBJECT (p->up), "clicked", up_clicked, e);
- gtk_signal_connect(GTK_OBJECT (p->down), "clicked", down_clicked, e);
-
- filter_druid_set_default_html(p->druid, "<h2>Filtering Rules</h2>"
- "<p>Select one of the rules above to <i>view</i>, and "
- "<i>edit</i>. Or <i>Add</i> a new rule.</p>");
-
- gtk_widget_show_all(hbox);
- sensitise(e);
+ item = g_list_nth_data(data->list->children, from);
+ l = g_list_append(NULL, item);
+ gtk_list_remove_items_no_unref(data->list, l);
+ gtk_list_insert_items(data->list, l, to);
+ gtk_list_select_child(data->list, (GtkWidget *)item);
+ set_sensitive(data);
}
-
-/**
- * filter_editor_new:
- *
- * Create a new FilterEditor object.
- *
- * Return value: A new FilterEditor widget.
- **/
-FilterEditor *
-filter_editor_new (void)
+static void rule_up(GtkWidget *widget, struct _editor_data *data)
{
- FilterEditor *new = FILTER_EDITOR ( gtk_type_new (filter_editor_get_type ()));
-
- build_editor(new);
+ int pos;
- return new;
+ d(printf("up rule\n"));
+ pos = rule_context_get_rank_rule(data->f, data->current);
+ if (pos>0) {
+ rule_move(data, pos, pos-1);
+ }
}
-void
-filter_editor_set_rules(FilterEditor *e, GList *rules, GList *systemoptions, GList *useroptions)
+static void rule_down(GtkWidget *widget, struct _editor_data *data)
{
- struct _FilterEditorPrivate *p = _PRIVATE(e);
+ int pos;
- e->rules= rules;
- e->systemoptions = systemoptions;
- e->useroptions = useroptions;
-
- filter_druid_set_rules(p->druid, useroptions, rules, NULL);
+ d(printf("down rule\n"));
+ pos = rule_context_get_rank_rule(data->f, data->current);
+ rule_move(data, pos, pos+1);
}
-void
-filter_editor_set_rule_files(FilterEditor *e, const char *systemrules, const char *userrules)
-{
- GList *rules, *options = NULL, *options2;
- xmlDocPtr doc, out;
-
- doc = xmlParseFile(systemrules);
- if( doc == NULL ) {
- g_warning( "Couldn't load system rules file %s", systemrules );
- rules = NULL;
- options2 = NULL;
- } else {
- rules = filter_load_ruleset(doc);
- options2 = filter_load_optionset(doc, rules);
- }
+static struct {
+ char *name;
+ GtkSignalFunc func;
+} edit_buttons[] = {
+ { "rule_add", rule_add },
+ { "rule_edit", rule_edit },
+ { "rule_delete", rule_delete },
+ { "rule_up", rule_up },
+ { "rule_down", rule_down },
+};
- out = xmlParseFile(userrules);
- if (out)
- options = filter_load_optionset(out, rules);
+static void
+set_sensitive(struct _editor_data *data)
+{
+ FilterRule *rule = NULL;
+ int index=-1, count=0;
- filter_editor_set_rules(e, rules, options2, options);
+ while ((rule = rule_context_next_rule(data->f, rule))) {
+ if (rule == data->current)
+ index=count;
+ count++;
+ }
+ d(printf("index = %d count=%d\n", index, count));
+ count--;
+ gtk_widget_set_sensitive((GtkWidget *)data->buttons[BUTTON_EDIT], index != -1);
+ gtk_widget_set_sensitive((GtkWidget *)data->buttons[BUTTON_DELETE], index != -1);
+ gtk_widget_set_sensitive((GtkWidget *)data->buttons[BUTTON_UP], index > 0);
+ gtk_widget_set_sensitive((GtkWidget *)data->buttons[BUTTON_DOWN], index >=0 && index<count);
}
-int
-filter_editor_save_rules(FilterEditor *e, const char *userrules)
+static void
+select_rule(GtkWidget *w, GtkWidget *child, struct _editor_data *data)
{
- return filter_write_optionset_file(userrules, e->useroptions);
+ data->current = gtk_object_get_data((GtkObject *)child, "rule");
+ if (data->current)
+ d(printf("seledct rule: %s\n", data->current->name));
+ else
+ d(printf("bad data?\n"));
+ set_sensitive(data);
}
-#ifdef STANDALONE
-
-int main(int argc, char **argv)
+GtkWidget *filter_editor_construct (struct _FilterContext *f)
{
- FilterEditor *fe;
+ GladeXML *gui;
+ GtkWidget *d, *w;
+ GList *l;
+ FilterRule *rule = NULL;
+ struct _editor_data *data;
+ int i;
+
+ g_assert(IS_FILTER_CONTEXT(f));
+
+ data = g_malloc0(sizeof(*data));
+ data->f = (RuleContext *)f;
+
+ gui = glade_xml_new(FILTER_GLADEDIR "/filter.glade", "edit_filter");
+ d = glade_xml_get_widget (gui, "edit_filter");
+ gtk_object_set_data_full((GtkObject *)d, "data", data, g_free);
+
+ gtk_window_set_title((GtkWindow *)d, "Edit Filters");
+ for (i=0;i<BUTTON_LAST;i++) {
+ data->buttons[i] = (GtkButton *)w = glade_xml_get_widget (gui, edit_buttons[i].name);
+ gtk_signal_connect((GtkObject *)w, "clicked", edit_buttons[i].func, data);
+ }
- gnome_init("Test", "0.0", argc, argv);
- gdk_rgb_init ();
- gtk_widget_set_default_colormap (gdk_rgb_get_cmap ());
- gtk_widget_set_default_visual (gdk_rgb_get_visual ());
+ /* to be defined yet */
+#if 0
+ w = glade_xml_get_widget (gui, "filter_source");
+ l = GTK_MENU_SHELL(GTK_OPTION_MENU(w)->menu)->children;
+ while (l) {
+ b = l->data;
+ l = l->next;
+ }
+#endif
- fe = filter_editor_new();
- filter_editor_set_rule_files(fe, "/home/notzed/gnome/evolution/filter/filterdescription.xml", "/home/notzed/filters.xml");
- gtk_widget_show(fe);
+ w = glade_xml_get_widget (gui, "rule_list");
+ data->list = (GtkList *)w;
+ l = NULL;
+ while ((rule = rule_context_next_rule((RuleContext *)f, rule))) {
+ GtkListItem *item = (GtkListItem *)gtk_list_item_new_with_label(rule->name);
+ gtk_object_set_data((GtkObject *)item, "rule", rule);
+ gtk_widget_show((GtkWidget *)item);
+ l = g_list_append(l, item);
+ }
+ gtk_list_append_items(data->list, l);
+ gtk_signal_connect((GtkObject *)w, "select_child", select_rule, data);
- gtk_main();
+ set_sensitive(data);
+ gtk_object_unref((GtkObject *)gui);
- return 0;
+ return d;
}
-
-#endif
diff --git a/filter/filter-editor.h b/filter/filter-editor.h
index 66f7a81e11..20369a9536 100644
--- a/filter/filter-editor.h
+++ b/filter/filter-editor.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2000 Helix Code Inc.
*
- * Authors: Michael Zucchi <notzed@helixcode.com>
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
@@ -22,37 +22,40 @@
#define _FILTER_EDITOR_H
#include <gtk/gtk.h>
-#include <gnome.h>
-#include "filter-xml.h"
+#include <libgnomeui/gnome-dialog.h>
-#define FILTER_EDITOR(obj) GTK_CHECK_CAST (obj, filter_editor_get_type (), FilterEditor)
-#define FILTER_EDITOR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_editor_get_type (), FilterEditorClass)
+#if 0
+/* NOTE: object stuff not used (yet?), this is just a holder file for a static factory */
+
+#define FILTER_EDITOR(obj) GTK_CHECK_CAST (obj, filter_editor_get_type (), FilterEditor)
+#define FILTER_EDITOR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_editor_get_type (), FilterEditorClass)
#define IS_FILTER_EDITOR(obj) GTK_CHECK_TYPE (obj, filter_editor_get_type ())
-typedef struct _FilterEditor FilterEditor;
-typedef struct _FilterEditorClass FilterEditorClass;
+typedef struct _FilterEditor FilterEditor;
+typedef struct _FilterEditorClass FilterEditorClass;
struct _FilterEditor {
GnomeDialog parent;
-
struct _FilterEditorPrivate *priv;
- GList *rules;
- GList *systemoptions;
- GList *useroptions;
-
- struct filter_option *option_current;
};
struct _FilterEditorClass {
GnomeDialogClass parent_class;
+
+ /* virtual methods */
+
+ /* signals */
};
guint filter_editor_get_type (void);
-FilterEditor *filter_editor_new (void);
+FilterEditor *filter_editor_new (void);
+#endif
+
+struct _FilterContext;
-void filter_editor_set_rules(FilterEditor *e, GList *rules, GList *systemoptions, GList *useroptions);
-void filter_editor_set_rule_files(FilterEditor *e, const char *systemrules, const char *userrules);
-int filter_editor_save_rules(FilterEditor *e, const char *userrules);
+/* methods */
+GtkWidget *filter_editor_construct (struct _FilterContext *f);
#endif /* ! _FILTER_EDITOR_H */
+
diff --git a/filter/filter-element.c b/filter/filter-element.c
new file mode 100644
index 0000000000..049b15727b
--- /dev/null
+++ b/filter/filter-element.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+
+#include "filter-element.h"
+#include "filter-input.h"
+#include "filter-option.h"
+#include "filter-code.h"
+#include "filter-colour.h"
+#include "filter-folder.h"
+
+static void xml_create(FilterElement *fe, xmlNodePtr node);
+static FilterElement *clone(FilterElement *fe);
+
+static void filter_element_class_init (FilterElementClass *class);
+static void filter_element_init (FilterElement *gspaper);
+static void filter_element_finalise (GtkObject *obj);
+
+#define _PRIVATE(x) (((FilterElement *)(x))->priv)
+struct _FilterElementPrivate {
+};
+
+static GtkObjectClass *parent_class;
+
+enum {
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+guint
+filter_element_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterElement",
+ sizeof(FilterElement),
+ sizeof(FilterElementClass),
+ (GtkClassInitFunc)filter_element_class_init,
+ (GtkObjectInitFunc)filter_element_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(gtk_object_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+filter_element_class_init (FilterElementClass *class)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(gtk_object_get_type ());
+
+ object_class->finalize = filter_element_finalise;
+
+ /* override methods */
+ class->xml_create = xml_create;
+ class->clone = clone;
+
+ /* signals */
+
+ gtk_object_class_add_signals(object_class, signals, LAST_SIGNAL);
+}
+
+static void
+filter_element_init (FilterElement *o)
+{
+ o->priv = g_malloc0(sizeof(*o->priv));
+}
+
+static void
+filter_element_finalise(GtkObject *obj)
+{
+ FilterElement *o = (FilterElement *)obj;
+
+ o = o;
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * filter_element_new:
+ *
+ * Create a new FilterElement object.
+ *
+ * Return value: A new #FilterElement object.
+ **/
+FilterElement *
+filter_element_new(void)
+{
+ FilterElement *o = (FilterElement *)gtk_type_new(filter_element_get_type ());
+ return o;
+}
+
+/**
+ * filter_element_xml_create:
+ * @fe:
+ * @node:
+ *
+ * Create a new filter element based on an xml definition of
+ * that element.
+ **/
+void filter_element_xml_create (FilterElement *fe, xmlNodePtr node)
+{
+ return ((FilterElementClass *)((GtkObject *)fe)->klass)->xml_create(fe, node);
+}
+
+/**
+ * filter_element_xml_encode:
+ * @fe:
+ *
+ * Encode the values of a filter element into xml format.
+ *
+ * Return value:
+ **/
+xmlNodePtr filter_element_xml_encode (FilterElement *fe)
+{
+ return ((FilterElementClass *)((GtkObject *)fe)->klass)->xml_encode(fe);
+}
+
+/**
+ * filter_element_xml_decode:
+ * @fe:
+ * @node:
+ *
+ * Decode the values of a fitler element from xml format.
+ *
+ * Return value:
+ **/
+int filter_element_xml_decode (FilterElement *fe, xmlNodePtr node)
+{
+ return ((FilterElementClass *)((GtkObject *)fe)->klass)->xml_decode(fe, node);
+}
+
+/**
+ * filter_element_clone:
+ * @fe:
+ *
+ * Clones the FilterElement @fe.
+ *
+ * Return value:
+ **/
+FilterElement *filter_element_clone (FilterElement *fe)
+{
+ return ((FilterElementClass *)((GtkObject *)fe)->klass)->clone(fe);
+}
+
+/**
+ * filter_element_get_widget:
+ * @fe:
+ * @node:
+ *
+ * Create a widget to represent this element.
+ *
+ * Return value:
+ **/
+GtkWidget *filter_element_get_widget (FilterElement *fe)
+{
+ return ((FilterElementClass *)((GtkObject *)fe)->klass)->get_widget(fe);
+}
+
+/**
+ * filter_element_build_code:
+ * @fe:
+ * @out:
+ * @ff:
+ *
+ * Add the code representing this element to the output string @out.
+ **/
+void filter_element_build_code (FilterElement *fe, GString *out, struct _FilterPart *ff)
+{
+ return ((FilterElementClass *)((GtkObject *)fe)->klass)->build_code(fe, out, ff);
+}
+
+/**
+ * filter_element_format_sexp:
+ * @fe:
+ * @out:
+ *
+ * Format the value(s) of this element in a method suitable for the context of
+ * sexp where it is used. Usually as space separated, double-quoted strings.
+ **/
+void filter_element_format_sexp (FilterElement *fe, GString *out)
+{
+ return ((FilterElementClass *)((GtkObject *)fe)->klass)->format_sexp(fe, out);
+}
+
+/**
+ * filter_element_new_type_name:
+ * @type:
+ *
+ * Create a new filter element based on its type name.
+ *
+ * Return value:
+ **/
+FilterElement *filter_element_new_type_name (const char *type)
+{
+ if (type == NULL)
+ return NULL;
+
+ if (!strcmp(type, "string")) {
+ return (FilterElement *)filter_input_new();
+ } else if (!strcmp(type, "folder")) {
+ return (FilterElement *)filter_folder_new();
+ } else if (!strcmp(type, "address")) {
+ /* FIXME: temporary ... need real address type */
+ return (FilterElement *)filter_input_new_type_name(type);
+ } else if (!strcmp(type, "code")) {
+ return (FilterElement *)filter_code_new();
+ } else if (!strcmp(type, "colour")) {
+ return (FilterElement *)filter_colour_new();
+ } else if (!strcmp(type, "optionlist")) {
+ return (FilterElement *)filter_option_new();
+ } else {
+ g_warning("Unknown filter type '%s'", type);
+ return 0;
+ }
+}
+
+/* default implementations */
+static void xml_create(FilterElement *fe, xmlNodePtr node)
+{
+ fe->name = xmlGetProp(node, "name");
+}
+
+static FilterElement *clone(FilterElement *fe)
+{
+ xmlNodePtr node;
+ FilterElement *new;
+
+ new = (FilterElement *)gtk_type_new( ((GtkObject *)fe)->klass->type );
+ node = filter_element_xml_encode(fe);
+ filter_element_xml_decode(new, node);
+ xmlFreeNodeList(node);
+ return new;
+}
+
+
diff --git a/filter/filter-element.h b/filter/filter-element.h
new file mode 100644
index 0000000000..8fe82402ee
--- /dev/null
+++ b/filter/filter-element.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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_ELEMENT_H
+#define _FILTER_ELEMENT_H
+
+#include <gtk/gtk.h>
+#include <gnome-xml/parser.h>
+
+#define FILTER_ELEMENT(obj) GTK_CHECK_CAST (obj, filter_element_get_type (), FilterElement)
+#define FILTER_ELEMENT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_element_get_type (), FilterElementClass)
+#define IS_FILTER_ELEMENT(obj) GTK_CHECK_TYPE (obj, filter_element_get_type ())
+
+typedef struct _FilterElement FilterElement;
+typedef struct _FilterElementClass FilterElementClass;
+
+struct _FilterElement {
+ GtkObject parent;
+ struct _FilterElementPrivate *priv;
+
+ char *name;
+};
+
+struct _FilterPart;
+
+struct _FilterElementClass {
+ GtkObjectClass parent_class;
+
+ /* virtual methods */
+ void (*xml_create)(FilterElement *, xmlNodePtr);
+ xmlNodePtr (*xml_encode)(FilterElement *);
+ int (*xml_decode)(FilterElement *, xmlNodePtr);
+
+ FilterElement *(*clone)(FilterElement *fe);
+
+ GtkWidget *(*get_widget)(FilterElement *);
+ void (*build_code)(FilterElement *, GString *, struct _FilterPart *ff);
+ void (*format_sexp)(FilterElement *, GString *);
+
+ /* signals */
+};
+
+guint filter_element_get_type (void);
+FilterElement *filter_element_new (void);
+
+FilterElement *filter_element_new_type_name (const char *type);
+
+/* methods */
+void filter_element_xml_create (FilterElement *fe, xmlNodePtr node);
+
+xmlNodePtr filter_element_xml_encode (FilterElement *fe);
+int filter_element_xml_decode (FilterElement *fe, xmlNodePtr node);
+FilterElement *filter_element_clone (FilterElement *fe);
+
+GtkWidget *filter_element_get_widget (FilterElement *fe);
+void filter_element_build_code (FilterElement *fe, GString *out, struct _FilterPart *ff);
+void filter_element_format_sexp (FilterElement *fe, GString *out);
+
+#endif /* ! _FILTER_ELEMENT_H */
+
diff --git a/filter/filter-filter.c b/filter/filter-filter.c
new file mode 100644
index 0000000000..9e902dbbd8
--- /dev/null
+++ b/filter/filter-filter.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+#include <gnome-xml/xmlmemory.h>
+
+#include "filter-filter.h"
+#include "filter-context.h"
+
+#define d(x) x
+
+static xmlNodePtr xml_encode(FilterRule *);
+static int xml_decode(FilterRule *, xmlNodePtr, struct _RuleContext *f);
+/*static void build_code(FilterRule *, GString *out);*/
+static GtkWidget *get_widget(FilterRule *fr, struct _RuleContext *f);
+
+static void filter_filter_class_init (FilterFilterClass *class);
+static void filter_filter_init (FilterFilter *gspaper);
+static void filter_filter_finalise (GtkObject *obj);
+
+#define _PRIVATE(x) (((FilterFilter *)(x))->priv)
+
+struct _FilterFilterPrivate {
+};
+
+static FilterRuleClass *parent_class;
+
+enum {
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+guint
+filter_filter_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterFilter",
+ sizeof(FilterFilter),
+ sizeof(FilterFilterClass),
+ (GtkClassInitFunc)filter_filter_class_init,
+ (GtkObjectInitFunc)filter_filter_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(filter_rule_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+filter_filter_class_init (FilterFilterClass *class)
+{
+ GtkObjectClass *object_class;
+ FilterRuleClass *filter_rule = (FilterRuleClass *)class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(filter_rule_get_type ());
+
+ object_class->finalize = filter_filter_finalise;
+
+ /* override methods */
+ filter_rule->xml_encode = xml_encode;
+ filter_rule->xml_decode = xml_decode;
+ /*filter_rule->build_code = build_code;*/
+ filter_rule->get_widget = get_widget;
+
+ /* signals */
+
+ gtk_object_class_add_signals(object_class, signals, LAST_SIGNAL);
+}
+
+static void
+filter_filter_init (FilterFilter *o)
+{
+ o->priv = g_malloc0(sizeof(*o->priv));
+}
+
+static void
+unref_list(GList *l)
+{
+ while (l) {
+ gtk_object_unref((GtkObject *)l->data);
+ l = g_list_next(l);
+ }
+}
+
+static void
+filter_filter_finalise(GtkObject *obj)
+{
+ FilterFilter *o = (FilterFilter *)obj;
+
+ unref_list(o->actions);
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * filter_filter_new:
+ *
+ * Create a new FilterFilter object.
+ *
+ * Return value: A new #FilterFilter object.
+ **/
+FilterFilter *
+filter_filter_new(void)
+{
+ FilterFilter *o = (FilterFilter *)gtk_type_new(filter_filter_get_type ());
+ return o;
+}
+
+void filter_filter_add_action (FilterFilter *fr, FilterPart *fp)
+{
+ fr->actions = g_list_append(fr->actions, fp);
+}
+
+void filter_filter_remove_action (FilterFilter *fr, FilterPart *fp)
+{
+ fr->actions = g_list_remove(fr->actions, fp);
+}
+
+void filter_filter_replace_action(FilterFilter *fr, FilterPart *fp, FilterPart *new)
+{
+ GList *l;
+
+ l = g_list_find(fr->actions, fp);
+ if (l) {
+ l->data = new;
+ } else {
+ fr->actions = g_list_append(fr->actions, new);
+ }
+}
+
+void filter_filter_build_action (FilterFilter *fr, GString *out)
+{
+ g_string_append(out, "(begin\n");
+ filter_part_build_code_list(fr->actions, out);
+ g_string_append(out, ")\n");
+}
+
+static xmlNodePtr xml_encode(FilterRule *fr)
+{
+ xmlNodePtr node, set, work;
+ GList *l;
+ FilterFilter *ff = (FilterFilter *)fr;
+
+ node = ((FilterRuleClass *)(parent_class))->xml_encode(fr);
+ g_assert(node != NULL);
+ set = xmlNewNode(NULL, "actionset");
+ xmlAddChild(node, set);
+ l = ff->actions;
+ while (l) {
+ work = filter_part_xml_encode((FilterPart *)l->data);
+ xmlAddChild(set, work);
+ l = g_list_next(l);
+ }
+ return node;
+
+}
+
+static void load_set(xmlNodePtr node, FilterFilter *ff, RuleContext *f)
+{
+ xmlNodePtr work;
+ char *rulename;
+ FilterPart *part;
+
+ work = node->childs;
+ while (work) {
+ if (!strcmp(work->name, "part")) {
+ rulename = xmlGetProp(work, "name");
+ part = filter_context_find_action((FilterContext *)f, rulename);
+ if (part) {
+ part = filter_part_clone(part);
+ filter_part_xml_decode(part, work);
+ filter_filter_add_action(ff, part);
+ } else {
+ g_warning("cannot find rule part '%s'\n", rulename);
+ }
+ xmlFree(rulename);
+ } else {
+ g_warning("Unknwon xml node in part: %s", work->name);
+ }
+ work = work->next;
+ }
+}
+
+static int xml_decode(FilterRule *fr, xmlNodePtr node, struct _RuleContext *f)
+{
+ xmlNodePtr work;
+ FilterFilter *ff = (FilterFilter *)fr;
+ int result;
+
+ result = ((FilterRuleClass *)(parent_class))->xml_decode(fr, node, f);
+ if (result != 0)
+ return result;
+
+ work = node->childs;
+ while (work) {
+ if (!strcmp(work->name, "actionset")) {
+ load_set(work, ff, f);
+ }
+ work = work->next;
+ }
+ return 0;
+}
+
+/*static void build_code(FilterRule *fr, GString *out)
+{
+ return ((FilterRuleClass *)(parent_class))->build_code(fr, out);
+}*/
+
+struct _part_data {
+ FilterRule *fr;
+ FilterContext *f;
+ FilterPart *part;
+ GtkWidget *partwidget, *container;
+};
+
+static void option_activate(GtkMenuItem *item, struct _part_data *data)
+{
+ FilterPart *part = gtk_object_get_data((GtkObject *)item, "part");
+ FilterPart *newpart;
+
+ /* dont update if we haven't changed */
+ if (!strcmp(part->title, data->part->title))
+ return;
+
+ /* here we do a widget shuffle, throw away the old widget/rulepart,
+ and create another */
+ if (data->partwidget)
+ gtk_container_remove((GtkContainer *)data->container, data->partwidget);
+ newpart = filter_part_clone(part);
+ filter_filter_replace_action((FilterFilter *)data->fr, data->part, newpart);
+ gtk_object_unref((GtkObject *)data->part);
+ data->part = newpart;
+ data->partwidget = filter_part_get_widget(newpart);
+ if (data->partwidget)
+ gtk_box_pack_start((GtkBox *)data->container, data->partwidget, FALSE, FALSE, 0);
+}
+
+static GtkWidget *
+get_rule_part_widget(FilterContext *f, FilterPart *newpart, FilterRule *fr)
+{
+ FilterPart *part = NULL;
+ GtkMenu *menu;
+ GtkMenuItem *item;
+ GtkOptionMenu *omenu;
+ GtkHBox *hbox;
+ GtkWidget *p;
+ int index=0, current=0;
+ struct _part_data *data;
+
+ data = g_malloc0(sizeof(*data));
+ data->fr = fr;
+ data->f = f;
+ data->part = newpart;
+
+ hbox = (GtkHBox *)gtk_hbox_new(FALSE, 0);
+ p = filter_part_get_widget(newpart);
+
+ data->partwidget = p;
+ data->container = (GtkWidget *)hbox;
+
+ menu = (GtkMenu *)gtk_menu_new();
+ while ((part=filter_context_next_action(f, part))) {
+ item = (GtkMenuItem *)gtk_menu_item_new_with_label(part->title);
+ gtk_object_set_data((GtkObject *)item, "part", part);
+ gtk_signal_connect((GtkObject *)item, "activate", option_activate, data);
+ gtk_menu_append(menu, (GtkWidget *)item);
+ gtk_widget_show((GtkWidget *)item);
+ if (!strcmp(newpart->title, part->title)) {
+ current = index;
+ }
+ index++;
+ }
+
+ omenu = (GtkOptionMenu *)gtk_option_menu_new();
+ gtk_option_menu_set_menu(omenu, (GtkWidget *)menu);
+ gtk_option_menu_set_history(omenu, current);
+ gtk_widget_show((GtkWidget *)omenu);
+
+ gtk_box_pack_start((GtkBox *)hbox, (GtkWidget *)omenu, FALSE, FALSE, 0);
+ if (p) {
+ gtk_box_pack_start((GtkBox *)hbox, p, FALSE, FALSE, 0);
+ }
+ gtk_widget_show_all((GtkWidget *)hbox);
+
+ return (GtkWidget *)hbox;
+}
+
+struct _rule_data {
+ FilterRule *fr;
+ FilterContext *f;
+ GtkWidget *parts;
+};
+
+static void
+less_parts(GtkWidget *button, struct _rule_data *data)
+{
+ GList *l;
+ FilterPart *part;
+ GtkWidget *w;
+
+ l = ((FilterFilter *)data->fr)->actions;
+ if (g_list_length(l) < 2)
+ return;
+
+ /* remove the last one from the list */
+ l = g_list_last(l);
+ part = l->data;
+ filter_filter_remove_action((FilterFilter *)data->fr, part);
+ gtk_object_unref((GtkObject *)part);
+
+ /* and from the display */
+ l = g_list_last(GTK_BOX(data->parts)->children);
+ w = ((GtkBoxChild *)l->data)->widget;
+ gtk_container_remove((GtkContainer *)data->parts, w);
+}
+
+static void
+more_parts(GtkWidget *button, struct _rule_data *data)
+{
+ FilterPart *new;
+ GtkWidget *w;
+
+ /* create a new rule entry, use the first type of rule */
+ new = filter_context_next_action((FilterContext *)data->f, NULL);
+ if (new) {
+ new = filter_part_clone(new);
+ filter_filter_add_action((FilterFilter *)data->fr, new);
+ w = get_rule_part_widget(data->f, new, data->fr);
+ gtk_box_pack_start((GtkBox *)data->parts, w, FALSE, FALSE, 0);
+ }
+}
+
+static GtkWidget *get_widget(FilterRule *fr, struct _RuleContext *f)
+{
+ GtkWidget *widget;
+ GtkVBox *parts, *inframe;
+ GtkHBox *hbox;
+ GtkWidget *w;
+ GtkFrame *frame;
+ GList *l;
+ FilterPart *part;
+ struct _rule_data *data;
+ FilterFilter *ff = (FilterFilter *)fr;
+
+ d(printf("filter filter.get widget\n"));
+
+ widget = ((FilterRuleClass *)(parent_class))->get_widget(fr, f);
+
+ /* and now for the action area */
+ frame = (GtkFrame *)gtk_frame_new("Perform actions");
+ inframe = (GtkVBox *)gtk_vbox_new(FALSE, 3);
+ gtk_container_add((GtkContainer *)frame, (GtkWidget *)inframe);
+
+ parts = (GtkVBox *)gtk_vbox_new(FALSE, 3);
+ data = g_malloc0(sizeof(*data));
+ data->f = (FilterContext *)f;
+ data->fr = fr;
+ data->parts = (GtkWidget *)parts;
+
+ l = ff->actions;
+ while (l) {
+ part = l->data;
+ d(printf("adding action %s\n", part->title));
+ w = get_rule_part_widget((FilterContext *)f, part, fr);
+ gtk_box_pack_start((GtkBox *)parts, (GtkWidget *)w, FALSE, FALSE, 3);
+ l = g_list_next(l);
+ }
+ gtk_box_pack_start((GtkBox *)inframe, (GtkWidget *)parts, FALSE, FALSE, 3);
+
+ hbox = (GtkHBox *)gtk_hbox_new(FALSE, 3);
+ w = gtk_button_new_with_label("Less");
+ gtk_signal_connect((GtkObject *)w, "clicked", less_parts, data);
+ gtk_box_pack_end((GtkBox *)hbox, (GtkWidget *)w, FALSE, FALSE, 0);
+ w = gtk_button_new_with_label("More");
+ gtk_signal_connect((GtkObject *)w, "clicked", more_parts, data);
+ gtk_box_pack_end((GtkBox *)hbox, (GtkWidget *)w, FALSE, FALSE, 0);
+ gtk_box_pack_start((GtkBox *)inframe, (GtkWidget *)hbox, FALSE, FALSE, 3);
+
+ gtk_widget_show_all((GtkWidget *)frame);
+
+ gtk_box_pack_start((GtkBox *)widget, (GtkWidget *)frame, FALSE, FALSE, 3);
+
+ return widget;
+}
+
diff --git a/filter/filter-filter.h b/filter/filter-filter.h
new file mode 100644
index 0000000000..944aba42ae
--- /dev/null
+++ b/filter/filter-filter.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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_FILTER_H
+#define _FILTER_FILTER_H
+
+#include <gtk/gtk.h>
+#include "filter-rule.h"
+
+#define FILTER_FILTER(obj) GTK_CHECK_CAST (obj, filter_filter_get_type (), FilterFilter)
+#define FILTER_FILTER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_filter_get_type (), FilterFilterClass)
+#define IS_FILTER_FILTER(obj) GTK_CHECK_TYPE (obj, filter_filter_get_type ())
+
+typedef struct _FilterFilter FilterFilter;
+typedef struct _FilterFilterClass FilterFilterClass;
+
+struct _FilterFilter {
+ FilterRule parent;
+ struct _FilterFilterPrivate *priv;
+
+ GList *actions;
+};
+
+struct _FilterFilterClass {
+ FilterRuleClass parent_class;
+
+ /* virtual methods */
+
+ /* signals */
+};
+
+guint filter_filter_get_type (void);
+FilterFilter *filter_filter_new (void);
+
+/* methods */
+void filter_filter_add_action (FilterFilter *fr, FilterPart *fp);
+void filter_filter_remove_action (FilterFilter *fr, FilterPart *fp);
+void filter_filter_replace_action (FilterFilter *fr, FilterPart *fp, FilterPart *new);
+
+void filter_filter_build_action (FilterFilter *fr, GString *out);
+
+#endif /* ! _FILTER_FILTER_H */
+
diff --git a/filter/filter-folder.c b/filter/filter-folder.c
new file mode 100644
index 0000000000..fa3fe913ae
--- /dev/null
+++ b/filter/filter-folder.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+
+#define SHELL
+
+#include "filter-folder.h"
+#ifdef SHELL
+#include "shell/evolution-shell-client.h"
+#endif
+#include "e-util/e-sexp.h"
+
+#define d(x)
+
+static void xml_create(FilterElement *fe, xmlNodePtr node);
+static xmlNodePtr xml_encode(FilterElement *fe);
+static int xml_decode(FilterElement *fe, xmlNodePtr node);
+static GtkWidget *get_widget(FilterElement *fe);
+static void build_code(FilterElement *fe, GString *out, struct _FilterPart *ff);
+static void format_sexp(FilterElement *, GString *);
+
+#ifdef SHELL
+extern EvolutionShellClient *global_shell_client;
+#endif
+
+static void filter_folder_class_init (FilterFolderClass *class);
+static void filter_folder_init (FilterFolder *gspaper);
+static void filter_folder_finalise (GtkObject *obj);
+
+#define _PRIVATE(x) (((FilterFolder *)(x))->priv)
+
+struct _FilterFolderPrivate {
+};
+
+static FilterElementClass *parent_class;
+
+guint
+filter_folder_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterFolder",
+ sizeof(FilterFolder),
+ sizeof(FilterFolderClass),
+ (GtkClassInitFunc)filter_folder_class_init,
+ (GtkObjectInitFunc)filter_folder_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(filter_element_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+filter_folder_class_init (FilterFolderClass *class)
+{
+ GtkObjectClass *object_class;
+ FilterElementClass *filter_element = (FilterElementClass *)class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(filter_element_get_type ());
+
+ object_class->finalize = filter_folder_finalise;
+
+ /* override methods */
+ filter_element->xml_create = xml_create;
+ filter_element->xml_encode = xml_encode;
+ filter_element->xml_decode = xml_decode;
+ filter_element->get_widget = get_widget;
+ filter_element->build_code = build_code;
+ filter_element->format_sexp = format_sexp;
+}
+
+static void
+filter_folder_init (FilterFolder *o)
+{
+ o->priv = g_malloc0(sizeof(*o->priv));
+}
+
+static void
+filter_folder_finalise(GtkObject *obj)
+{
+ FilterFolder *o = (FilterFolder *)obj;
+
+ g_free(o->uri);
+ g_free(o->name);
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * filter_folder_new:
+ *
+ * Create a new FilterFolder object.
+ *
+ * Return value: A new #FilterFolder object.
+ **/
+FilterFolder *
+filter_folder_new(void)
+{
+ FilterFolder *o = (FilterFolder *)gtk_type_new(filter_folder_get_type ());
+ return o;
+}
+
+static void xml_create(FilterElement *fe, xmlNodePtr node)
+{
+ /* parent implementation */
+ ((FilterElementClass *)(parent_class))->xml_create(fe, node);
+}
+
+static xmlNodePtr xml_encode(FilterElement *fe)
+{
+ xmlNodePtr value, work;
+ FilterFolder *ff = (FilterFolder *)fe;
+
+ d(printf("Encoding folder as xml\n"));
+
+ value = xmlNewNode(NULL, "value");
+ xmlSetProp(value, "name", fe->name);
+ xmlSetProp(value, "type", "folder");
+
+ work = xmlNewChild(value, NULL, "folder", NULL);
+ xmlSetProp(work, "name", ff->name);
+ xmlSetProp(work, "uri", ff->uri);
+
+ return value;
+}
+
+static int xml_decode(FilterElement *fe, xmlNodePtr node)
+{
+ FilterFolder *ff = (FilterFolder *)fe;
+ xmlNodePtr n;
+
+ d(printf("Decoding folder from xml %p\n", fe));
+
+ fe->name = xmlGetProp(node, "name");
+
+ n = node->childs;
+ while (n) {
+ if (!strcmp(n->name, "folder")) {
+ ff->name = xmlGetProp(n, "name");
+ ff->uri = xmlGetProp(n, "uri");
+ break;
+ }
+ n = n->next;
+ }
+ return 0;
+}
+
+static void button_clicked(GtkButton *button, FilterFolder *ff)
+{
+#ifdef SHELL
+ const char *allowed_types[] = { "mail", NULL };
+ char *def, *uri, *str;
+
+ def = ff->uri?ff->uri:"";
+ evolution_shell_client_user_select_folder (global_shell_client,
+ _("Select Folder"),
+ def, allowed_types, NULL, &uri);
+
+ if (uri != NULL && uri[0] != '\0') {
+ g_free(ff->uri);
+ g_free(ff->name);
+ ff->uri = uri;
+
+ str = strstr(uri, "//");
+ if (str)
+ str = strchr(str+2, '/');
+ if (str)
+ str++;
+ else
+ str = uri;
+
+ ff->name = g_strdup(str);
+ gtk_label_set_text(GTK_BIN(button)->child, ff->name);
+ } else {
+ g_free(uri);
+ }
+#else
+ GnomeDialog *gd;
+ GtkEntry *entry;
+ char *uri, *str;
+
+ gd = (GnomeDialog *)gnome_dialog_new("Enter folder URI", "Ok", "Cancel", 0);
+ entry = (GtkEntry *)gtk_entry_new();
+ if (ff->uri) {
+ gtk_entry_set_text(entry, ff->uri);
+ }
+ gtk_box_pack_start((GtkBox *)gd->vbox, (GtkWidget *)entry, TRUE, TRUE, 3);
+ gtk_widget_show((GtkWidget *)entry);
+ switch (gnome_dialog_run(gd)) {
+ case 0:
+ g_free(ff->uri);
+ g_free(ff->name);
+ uri = gtk_entry_get_text(entry);
+ ff->uri = g_strdup(uri);
+ str = strstr(uri, "//");
+ if (str)
+ str = strchr(str+2, '/');
+ if (str)
+ str++;
+ else
+ str = uri;
+ ff->name = g_strdup(str);
+ gtk_label_set_text((GtkLabel *)GTK_BIN(button)->child, ff->name);
+ case 1:
+ gnome_dialog_close(gd);
+ case -1:
+ /* nothing */
+ }
+
+#endif
+}
+
+static GtkWidget *get_widget(FilterElement *fe)
+{
+ FilterFolder *ff = (FilterFolder *)fe;
+ GtkButton *button;
+ GtkLabel *label;
+ char *name;
+
+ if (ff->name && ff->name[0])
+ name = ff->name;
+ else
+ name = "<click to select folder>";
+ label = (GtkLabel *)gtk_label_new(name);
+ button = (GtkButton *)gtk_button_new();
+ gtk_container_add((GtkContainer *)button, (GtkWidget *)label);
+ gtk_widget_show((GtkWidget *)button);
+ gtk_widget_show((GtkWidget *)label);
+ gtk_signal_connect((GtkObject *)button, "clicked", button_clicked, ff);
+ return (GtkWidget *)button;
+}
+
+static void build_code(FilterElement *fe, GString *out, struct _FilterPart *ff)
+{
+ return;
+}
+
+static void format_sexp(FilterElement *fe, GString *out)
+{
+ FilterFolder *ff = (FilterFolder *)fe;
+
+ e_sexp_encode_string(out, ff->uri);
+}
diff --git a/filter/filter-folder.h b/filter/filter-folder.h
new file mode 100644
index 0000000000..ee52d7037b
--- /dev/null
+++ b/filter/filter-folder.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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_FOLDER_H
+#define _FILTER_FOLDER_H
+
+#include <gtk/gtk.h>
+#include "filter-element.h"
+
+#define FILTER_FOLDER(obj) GTK_CHECK_CAST (obj, filter_folder_get_type (), FilterFolder)
+#define FILTER_FOLDER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_folder_get_type (), FilterFolderClass)
+#define IS_FILTER_FOLDER(obj) GTK_CHECK_TYPE (obj, filter_folder_get_type ())
+
+typedef struct _FilterFolder FilterFolder;
+typedef struct _FilterFolderClass FilterFolderClass;
+
+struct _FilterFolder {
+ FilterElement parent;
+ struct _FilterFolderPrivate *priv;
+
+ char *uri;
+ char *name; /* name of folder for display? */
+};
+
+struct _FilterFolderClass {
+ FilterElementClass parent_class;
+
+ /* virtual methods */
+
+ /* signals */
+};
+
+guint filter_folder_get_type (void);
+FilterFolder *filter_folder_new (void);
+
+/* methods */
+
+#endif /* ! _FILTER_FOLDER_H */
+
diff --git a/filter/filter-format.c b/filter/filter-format.c
deleted file mode 100644
index 7f8f388ef5..0000000000
--- a/filter/filter-format.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* -*- 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"
-
-#define d(x)
-
-struct description_decode_lambda {
- GString *str;
- GList *args;
- GtkHTML *html;
- GtkHTMLStream *stream;
-};
-
-static char *
-arg_text(FilterArg *arg)
-{
- char *out = NULL;
- GList *value;
- GString *str;
-
- value = arg->values;
-
- d(printf("getting text from arg %s\n", arg->name));
-
- 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:
- d(printf("appending '%s'\n", d->data));
- /* printf("vartype = %s\n", detokenise(d->vartype)); */
- d(printf("varname = %s\n", d->varname));
- if (d->vartype !=-1 && d->varname
- && (list = g_list_find_custom(l->args, d->varname, (GCompareFunc) filter_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 '%d' = %s\n", d->type, d->data);
- goto dotext;
- }
-}
-
-char *
-filter_description_text(GList *description, GList *args)
-{
- char *txt;
- struct description_decode_lambda l;
-
- d(printf("\ndecoding ...\n"));
-
- l.str = g_string_new("");
- l.args = args;
- g_list_foreach(description, (GFunc) description_decode_text, &l);
-
- d(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, GtkHTMLStream *stream, char *s)
-{
- d(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:
- d(printf("appending '%s'\n", d->data));
- /*printf("vartype = %s\n", detokenise(d->vartype));*/
- d(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) filter_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;
- }
-}
-
-void
-filter_description_html_write(GList *description, GList *args, GtkHTML *html, GtkHTMLStream *stream)
-{
- struct description_decode_lambda l;
-
- d(printf("\ndecoding ...\n"));
-
- l.str = NULL;
- l.args = args;
- l.html = html;
- l.stream = stream;
- g_list_foreach(description, (GFunc) description_decode_html, &l);
-}
-
-#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-format.h b/filter/filter-format.h
deleted file mode 100644
index 82c5d9fb13..0000000000
--- a/filter/filter-format.h
+++ /dev/null
@@ -1,11 +0,0 @@
-
-#ifndef _FILTER_FORMAT_H
-#define _FILTER_FORMAT_H
-
-#include <glib.h>
-
-char *filter_description_text(GList *description, GList *args);
-void filter_description_html_write(GList *description, GList *args,
- GtkHTML *html, GtkHTMLStream *stream);
-
-#endif /* _FILTER_FORMAT_H */
diff --git a/filter/filter-input.c b/filter/filter-input.c
new file mode 100644
index 0000000000..eca5afd2ff
--- /dev/null
+++ b/filter/filter-input.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+
+#include "filter-input.h"
+#include "e-util/e-sexp.h"
+
+#define d(x)
+
+static void xml_create(FilterElement *fe, xmlNodePtr node);
+static xmlNodePtr xml_encode(FilterElement *fe);
+static int xml_decode(FilterElement *fe, xmlNodePtr node);
+static GtkWidget *get_widget(FilterElement *fe);
+static void build_code(FilterElement *fe, GString *out, struct _FilterPart *ff);
+static void format_sexp(FilterElement *, GString *);
+
+static void filter_input_class_init (FilterInputClass *class);
+static void filter_input_init (FilterInput *gspaper);
+static void filter_input_finalise (GtkObject *obj);
+
+#define _PRIVATE(x) (((FilterInput *)(x))->priv)
+
+struct _FilterInputPrivate {
+};
+
+static FilterElementClass *parent_class;
+
+enum {
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+guint
+filter_input_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterInput",
+ sizeof(FilterInput),
+ sizeof(FilterInputClass),
+ (GtkClassInitFunc)filter_input_class_init,
+ (GtkObjectInitFunc)filter_input_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(filter_element_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+filter_input_class_init (FilterInputClass *class)
+{
+ GtkObjectClass *object_class;
+ FilterElementClass *filter_element = (FilterElementClass *)class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(filter_element_get_type ());
+
+ object_class->finalize = filter_input_finalise;
+
+ /* override methods */
+ filter_element->xml_create = xml_create;
+ filter_element->xml_encode = xml_encode;
+ filter_element->xml_decode = xml_decode;
+ filter_element->get_widget = get_widget;
+ filter_element->build_code = build_code;
+ filter_element->format_sexp = format_sexp;
+
+ /* signals */
+
+ gtk_object_class_add_signals(object_class, signals, LAST_SIGNAL);
+}
+
+static void
+filter_input_init (FilterInput *o)
+{
+ o->priv = g_malloc0(sizeof(*o->priv));
+}
+
+static void
+filter_input_finalise(GtkObject *obj)
+{
+ FilterInput *o = (FilterInput *)obj;
+
+ o = o;
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * filter_input_new:
+ *
+ * Create a new FilterInput object.
+ *
+ * Return value: A new #FilterInput object.
+ **/
+FilterInput *
+filter_input_new(void)
+{
+ FilterInput *o = (FilterInput *)gtk_type_new(filter_input_get_type ());
+ return o;
+}
+
+FilterInput *filter_input_new_type_name (const char *type)
+{
+ FilterInput *o = filter_input_new();
+ o->type = g_strdup(type);
+
+ d(printf("new type %s = %p\n", type, o));
+ return o;
+}
+
+static void xml_create(FilterElement *fe, xmlNodePtr node)
+{
+ /* parent implementation */
+ ((FilterElementClass *)(parent_class))->xml_create(fe, node);
+
+}
+
+static xmlNodePtr xml_encode(FilterElement *fe)
+{
+ xmlNodePtr value;
+ GList *l;
+ FilterInput *fi = (FilterInput *)fe;
+ char *type;
+
+ type = fi->type?fi->type:"string";
+
+ d(printf("Encoding %s as xml\n", type));
+
+ value = xmlNewNode(NULL, "value");
+ xmlSetProp(value, "name", fe->name);
+ xmlSetProp(value, "type", type);
+ l = fi->values;
+ while (l) {
+ xmlNodePtr cur;
+ char *str = l->data;
+
+ cur = xmlNewChild(value, NULL, type, NULL);
+ xmlNodeSetContent(cur, str);
+ l = g_list_next(l);
+ }
+ return value;
+}
+
+static int xml_decode(FilterElement *fe, xmlNodePtr node)
+{
+ FilterInput *fi = (FilterInput *)fe;
+ char *name, *str, *type;
+ xmlNodePtr n;
+
+ type = fi->type?fi->type:"string";
+
+ d(printf("Decoding %s from xml %p\n", type, fe));
+
+ name = xmlGetProp(node, "name");
+ d(printf("Name = %s\n", name));
+ fe->name = name;
+ fi->type = xmlGetProp(node, "type");
+ n = node->childs;
+ while (n) {
+ if (!strcmp(n->name, type)) {
+ str = xmlNodeGetContent(n);
+ d(printf(" '%s'\n", str));
+ fi->values = g_list_append(fi->values, str);
+ } else {
+ g_warning("Unknown node type '%s' encountered decoding a %s\n", n->name, type);
+ }
+ n = n->next;
+ }
+ return 0;
+}
+
+static void entry_changed(GtkEntry *entry, FilterElement *fe)
+{
+ char *new;
+ FilterInput *fi = (FilterInput *)fe;
+ GList *l;
+
+ new = gtk_entry_get_text(entry);
+
+ /* NOTE: entry only supports a single value ... */
+ l = fi->values;
+ while (l) {
+ g_free(l->data);
+ l = g_list_next(l);
+ }
+ g_list_free(fi->values);
+
+ fi->values = g_list_append(NULL, g_strdup(new));
+}
+
+static GtkWidget *get_widget(FilterElement *fe)
+{
+ GtkEntry *entry;
+ FilterInput *fi = (FilterInput *)fe;
+
+ entry = (GtkEntry *)gtk_entry_new();
+ if (fi->values && fi->values->data) {
+ gtk_entry_set_text(entry, fi->values->data);
+ }
+ gtk_signal_connect((GtkObject *)entry, "changed", entry_changed, fe);
+ return (GtkWidget *)entry;
+}
+
+static void build_code(FilterElement *fe, GString *out, struct _FilterPart *ff)
+{
+ return;
+}
+
+static void format_sexp(FilterElement *fe, GString *out)
+{
+ GList *l;
+ FilterInput *fi = (FilterInput *)fe;
+
+ l = fi->values;
+ while (l) {
+ e_sexp_encode_string(out, l->data);
+ l = g_list_next(l);
+ }
+}
diff --git a/filter/filter-input.h b/filter/filter-input.h
new file mode 100644
index 0000000000..0ce43d980d
--- /dev/null
+++ b/filter/filter-input.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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_INPUT_H
+#define _FILTER_INPUT_H
+
+#include <gtk/gtk.h>
+#include "filter-element.h"
+
+#define FILTER_INPUT(obj) GTK_CHECK_CAST (obj, filter_input_get_type (), FilterInput)
+#define FILTER_INPUT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_input_get_type (), FilterInputClass)
+#define IS_FILTER_INPUT(obj) GTK_CHECK_TYPE (obj, filter_input_get_type ())
+
+typedef struct _FilterInput FilterInput;
+typedef struct _FilterInputClass FilterInputClass;
+
+struct _FilterInput {
+ FilterElement parent;
+ struct _FilterInputPrivate *priv;
+
+ char *type; /* name of type */
+ GList *values; /* strings */
+};
+
+struct _FilterInputClass {
+ FilterElementClass parent_class;
+
+ /* virtual methods */
+
+ /* signals */
+};
+
+guint filter_input_get_type (void);
+FilterInput *filter_input_new (void);
+
+FilterInput *filter_input_new_type_name (const char *type);
+
+/* methods */
+void filter_input_set_value(FilterInput *fi, const char *value);
+
+#endif /* ! _FILTER_INPUT_H */
+
diff --git a/filter/filter-option.c b/filter/filter-option.c
new file mode 100644
index 0000000000..31be216f25
--- /dev/null
+++ b/filter/filter-option.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+#include <gnome-xml/xmlmemory.h>
+
+#include "filter-option.h"
+#include "filter-part.h"
+#include "e-util/e-sexp.h"
+
+#define d(x)
+
+static void xml_create(FilterElement *fe, xmlNodePtr node);
+static xmlNodePtr xml_encode(FilterElement *fe);
+static int xml_decode(FilterElement *fe, xmlNodePtr node);
+static FilterElement *clone(FilterElement *fe);
+static GtkWidget *get_widget(FilterElement *fe);
+static void build_code(FilterElement *fe, GString *out, struct _FilterPart *ff);
+static void format_sexp(FilterElement *, GString *);
+
+static void filter_option_class_init (FilterOptionClass *class);
+static void filter_option_init (FilterOption *gspaper);
+static void filter_option_finalise (GtkObject *obj);
+
+#define _PRIVATE(x) (((FilterOption *)(x))->priv)
+
+struct _FilterOptionPrivate {
+};
+
+static FilterElementClass *parent_class;
+
+enum {
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+guint
+filter_option_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterOption",
+ sizeof(FilterOption),
+ sizeof(FilterOptionClass),
+ (GtkClassInitFunc)filter_option_class_init,
+ (GtkObjectInitFunc)filter_option_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(filter_element_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+filter_option_class_init (FilterOptionClass *class)
+{
+ GtkObjectClass *object_class;
+ FilterElementClass *filter_element = (FilterElementClass *)class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(filter_element_get_type ());
+
+ object_class->finalize = filter_option_finalise;
+
+ /* override methods */
+ filter_element->xml_create = xml_create;
+ filter_element->xml_encode = xml_encode;
+ filter_element->xml_decode = xml_decode;
+ filter_element->clone = clone;
+ filter_element->get_widget = get_widget;
+ filter_element->build_code = build_code;
+ filter_element->format_sexp = format_sexp;
+
+ /* signals */
+
+ gtk_object_class_add_signals(object_class, signals, LAST_SIGNAL);
+}
+
+static void
+filter_option_init (FilterOption *o)
+{
+ o->priv = g_malloc0(sizeof(*o->priv));
+}
+
+static void
+filter_option_finalise(GtkObject *obj)
+{
+ FilterOption *o = (FilterOption *)obj;
+
+ o = o;
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * filter_option_new:
+ *
+ * Create a new FilterOption object.
+ *
+ * Return value: A new #FilterOption object.
+ **/
+FilterOption *
+filter_option_new(void)
+{
+ FilterOption *o = (FilterOption *)gtk_type_new(filter_option_get_type ());
+ return o;
+}
+
+static struct _filter_option *
+find_option(FilterOption *fo, const char *name)
+{
+ GList *l = fo->options;
+ struct _filter_option *op;
+
+ while (l) {
+ op = l->data;
+ if (!strcmp(name, op->value)) {
+ return op;
+ }
+ l = g_list_next(l);
+ }
+ return NULL;
+}
+
+static void xml_create(FilterElement *fe, xmlNodePtr node)
+{
+ FilterOption *fo = (FilterOption *)fe;
+ xmlNodePtr n, work;
+ struct _filter_option *op;
+
+ /* parent implementation */
+ ((FilterElementClass *)(parent_class))->xml_create(fe, node);
+
+ n = node->childs;
+ while (n) {
+ if (!strcmp(n->name, "option")) {
+ op = g_malloc0(sizeof(*op));
+ op->value = xmlGetProp(n, "value");
+ work = n->childs;
+ while (work) {
+ if (!strcmp(work->name, "title")) {
+ if (!op->title) {
+ op->title = xmlNodeGetContent(work);
+ }
+ } else if (!strcmp(work->name, "code")) {
+ if (!op->code) {
+ op->code = xmlNodeGetContent(work);
+ }
+ }
+ work = work->next;
+ }
+ d(printf("creating new option:\n title %s\n value %s\n code %s\n", op->title, op->value, op->code));
+ fo->options = g_list_append(fo->options, op);
+ if (fo->current == NULL)
+ fo->current = op;
+ } else {
+ g_warning("Unknown xml node within optionlist: %s\n", n->name);
+ }
+ n = n->next;
+ }
+}
+
+static xmlNodePtr xml_encode(FilterElement *fe)
+{
+ xmlNodePtr value;
+ FilterOption *fo = (FilterOption *)fe;
+
+ d(printf("Encoding option as xml\n"));
+ value = xmlNewNode(NULL, "value");
+ xmlSetProp(value, "name", fe->name);
+ xmlSetProp(value, "type", "option");
+ if (fo->current) {
+ xmlSetProp(value, "value", fo->current->value);
+ }
+ return value;
+}
+
+static int xml_decode(FilterElement *fe, xmlNodePtr node)
+{
+ FilterOption *fo = (FilterOption *)fe;
+ char *value;
+
+ d(printf("Decoding option from xml\n"));
+ fe->name = xmlGetProp(node, "name");
+ value = xmlGetProp(node, "value");
+ if (value) {
+ fo->current = find_option(fo, value);
+ xmlFree(value);
+ } else {
+ fo->current = NULL;
+ }
+ return 0;
+}
+
+static void option_activate(GtkMenuItem *item, FilterOption *fo)
+{
+ fo->current = gtk_object_get_data((GtkObject *)item, "option");
+ d(printf("option changed to %s\n", fo->current->title));
+}
+
+static GtkWidget *get_widget(FilterElement *fe)
+{
+ FilterOption *fo = (FilterOption *)fe;
+ GtkMenu *menu;
+ GtkOptionMenu *omenu;
+ GtkMenuItem *item;
+ GList *l = fo->options;
+ struct _filter_option *op;
+ int index = 0, current=0;
+
+ menu = (GtkMenu *)gtk_menu_new();
+ while (l) {
+ op = l->data;
+ item = (GtkMenuItem *)gtk_menu_item_new_with_label(op->title);
+ gtk_object_set_data((GtkObject *)item, "option", op);
+ gtk_signal_connect((GtkObject *)item, "activate", option_activate, fo);
+ gtk_menu_append(menu, (GtkWidget *)item);
+ gtk_widget_show((GtkWidget *)item);
+ if (op == fo->current) {
+ current = index;
+ }
+ l = g_list_next(l);
+ index++;
+ }
+
+ omenu = (GtkOptionMenu *)gtk_option_menu_new();
+ gtk_option_menu_set_menu(omenu, (GtkWidget *)menu);
+ gtk_option_menu_set_history(omenu, current);
+
+ return (GtkWidget *)omenu;
+}
+
+static void build_code(FilterElement *fe, GString *out, struct _FilterPart *ff)
+{
+ FilterOption *fo = (FilterOption *)fe;
+
+ d(printf("building option code %p, current = %p\n", fo, fo->current));
+
+ if (fo->current) {
+ filter_part_expand_code(ff, fo->current->code, out);
+ }
+}
+
+static void format_sexp(FilterElement *fe, GString *out)
+{
+ FilterOption *fo = (FilterOption *)fe;
+
+ if (fo->current) {
+ e_sexp_encode_string(out, fo->current->value);
+ }
+}
+
+static FilterElement *clone(FilterElement *fe)
+{
+ FilterOption *fo = (FilterOption *)fe, *new;
+ GList *l;
+ struct _filter_option *fn, *op;
+
+ d(printf("cloning option\n"));
+
+ new = FILTER_OPTION(((FilterElementClass *)(parent_class))->clone(fe));
+ l = fo->options;
+ while (l) {
+ op = l->data;
+ fn = g_malloc(sizeof(*fn));
+ d(printf(" option %s\n", op->title));
+ fn->title = g_strdup(op->title);
+ fn->value = g_strdup(op->value);
+ fn->code = g_strdup(op->code);
+ new->options = g_list_append(new->options, fn);
+ l = g_list_next(l);
+
+ if (new->current == NULL)
+ new->current = fn;
+ }
+
+ d(printf("cloning option code %p, current = %p\n", new, new->current));
+
+ return (FilterElement *)new;
+}
diff --git a/filter/filter-option.h b/filter/filter-option.h
new file mode 100644
index 0000000000..1645b333a1
--- /dev/null
+++ b/filter/filter-option.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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_OPTION_H
+#define _FILTER_OPTION_H
+
+#include <gtk/gtk.h>
+
+#include "filter-element.h"
+
+#define FILTER_OPTION(obj) GTK_CHECK_CAST (obj, filter_option_get_type (), FilterOption)
+#define FILTER_OPTION_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_option_get_type (), FilterOptionClass)
+#define IS_FILTER_OPTION(obj) GTK_CHECK_TYPE (obj, filter_option_get_type ())
+
+typedef struct _FilterOption FilterOption;
+typedef struct _FilterOptionClass FilterOptionClass;
+
+struct _filter_option {
+ char *title; /* button title */
+ char *value; /* value, if it has one */
+ char *code; /* used to string code segments together */
+};
+
+struct _FilterOption {
+ FilterElement parent;
+ struct _FilterOptionPrivate *priv;
+
+ GList *options;
+ struct _filter_option *current;
+};
+
+struct _FilterOptionClass {
+ FilterElementClass parent_class;
+
+ /* virtual methods */
+
+ /* signals */
+};
+
+guint filter_option_get_type (void);
+FilterOption *filter_option_new (void);
+
+/* methods */
+
+#endif /* ! _FILTER_OPTION_H */
+
diff --git a/filter/filter-part.c b/filter/filter-part.c
new file mode 100644
index 0000000000..b38cc8e20f
--- /dev/null
+++ b/filter/filter-part.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+
+#include <gnome-xml/xmlmemory.h>
+
+#include "filter-part.h"
+#include "filter-element.h"
+
+#define d(x)
+
+static void filter_part_class_init (FilterPartClass *class);
+static void filter_part_init (FilterPart *gspaper);
+static void filter_part_finalise (GtkObject *obj);
+
+#define _PRIVATE(x) (((FilterPart *)(x))->priv)
+
+struct _FilterPartPrivate {
+};
+
+static GtkObjectClass *parent_class;
+
+enum {
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+guint
+filter_part_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterPart",
+ sizeof(FilterPart),
+ sizeof(FilterPartClass),
+ (GtkClassInitFunc)filter_part_class_init,
+ (GtkObjectInitFunc)filter_part_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(gtk_object_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+filter_part_class_init (FilterPartClass *class)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(gtk_object_get_type ());
+
+ object_class->finalize = filter_part_finalise;
+ /* override methods */
+
+ /* signals */
+
+ gtk_object_class_add_signals(object_class, signals, LAST_SIGNAL);
+}
+
+static void
+filter_part_init (FilterPart *o)
+{
+ o->priv = g_malloc0(sizeof(*o->priv));
+}
+
+static void
+filter_part_finalise(GtkObject *obj)
+{
+ FilterPart *o = (FilterPart *)obj;
+
+ o = o;
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * filter_part_new:
+ *
+ * Create a new FilterPart object.
+ *
+ * Return value: A new #FilterPart object.
+ **/
+FilterPart *
+filter_part_new(void)
+{
+ FilterPart *o = (FilterPart *)gtk_type_new(filter_part_get_type ());
+ return o;
+}
+
+
+
+int filter_part_xml_create (FilterPart *ff, xmlNodePtr node)
+{
+ xmlNodePtr n;
+ char *type;
+ FilterElement *el;
+
+ ff->name = xmlGetProp(node, "name");
+ n = node->childs;
+ while (n) {
+ if (!strcmp(n->name, "input")) {
+ type = xmlGetProp(n, "type");
+ d(printf("creating new element type input '%s'\n", type));
+ if (type != NULL
+ && (el = filter_element_new_type_name(type)) != NULL) {
+ filter_element_xml_create(el, n);
+ xmlFree(type);
+ d(printf("adding element part %p %s\n", el, el->name));
+ ff->elements = g_list_append(ff->elements, el);
+ } else {
+ g_warning("Invalid xml format, missing/unknown input type");
+ }
+ } else if (!strcmp(n->name, "title")) {
+ if (!ff->title)
+ ff->title = xmlNodeGetContent(n);
+ } else if (!strcmp(n->name, "code")) {
+ if (!ff->code)
+ ff->code = xmlNodeGetContent(n);
+ } else {
+ g_warning("Unknwon part element in xml: %s\n", n->name);
+ }
+ n = n->next;
+ }
+ return 0;
+}
+
+xmlNodePtr filter_part_xml_encode (FilterPart *fp)
+{
+ GList *l;
+ FilterElement *fe;
+ xmlNodePtr part, value;
+
+ g_return_val_if_fail(fp != NULL, NULL);
+
+ part = xmlNewNode(NULL, "part");
+ xmlSetProp(part, "name", fp->name);
+ l = fp->elements;
+ while (l) {
+ fe = l->data;
+ value = filter_element_xml_encode(fe);
+ xmlAddChild(part, value);
+ l = g_list_next(l);
+ }
+ return part;
+}
+
+int filter_part_xml_decode (FilterPart *fp, xmlNodePtr node)
+{
+ FilterElement *fe;
+ xmlNodePtr n;
+ char *name;
+
+ g_return_val_if_fail(fp != NULL, -1);
+ g_return_val_if_fail(node != NULL, -1);
+
+ n = node->childs;
+ while (n) {
+ if (!strcmp(n->name, "value")) {
+ name = xmlGetProp(n, "name");
+ d(printf("finding element part %p %s = %p\n", name, name, fe));
+ fe = filter_part_find_element(fp, name);
+ d(printf("finding element part %p %s = %p\n", name, name, fe));
+ xmlFree(name);
+ if (fe) {
+ filter_element_xml_decode(fe, n);
+ }
+ }
+ n = n->next;
+ }
+ return 0;
+}
+
+FilterPart *filter_part_clone (FilterPart *fp)
+{
+ FilterPart *new;
+ GList *l;
+ FilterElement *fe, *ne;
+
+ new = (FilterPart *)gtk_type_new( ((GtkObject *)fp)->klass->type );
+ new->name = g_strdup(fp->name);
+ new->title = g_strdup(fp->title);
+ new->code = g_strdup(fp->code);
+ l = fp->elements;
+ while (l) {
+ fe = l->data;
+ ne = filter_element_clone(fe);
+ new->elements = g_list_append(new->elements, ne);
+ l = g_list_next(l);
+ }
+ return new;
+}
+
+FilterElement *filter_part_find_element(FilterPart *ff, const char *name)
+{
+ GList *l = ff->elements;
+ FilterElement *fe;
+
+ if (name == NULL)
+ return NULL;
+
+ while (l) {
+ fe = l->data;
+ if (fe->name && !strcmp(fe->name, name))
+ return fe;
+ l = g_list_next(l);
+ }
+
+ return NULL;
+}
+
+
+GtkWidget *filter_part_get_widget (FilterPart *ff)
+{
+ GtkHBox *hbox;
+ GList *l = ff->elements;
+ FilterElement *fe;
+ GtkWidget *w;
+
+ hbox = (GtkHBox *)gtk_hbox_new(FALSE, 3);
+
+ while (l) {
+ fe = l->data;
+ w = filter_element_get_widget(fe);
+ if (w) {
+ gtk_box_pack_start((GtkBox *)hbox, w, FALSE, FALSE, 3);
+ }
+ l = g_list_next(l);
+ }
+ gtk_widget_show_all((GtkWidget *)hbox);
+ return (GtkWidget *)hbox;
+}
+
+/**
+ * filter_part_build_code:
+ * @ff:
+ * @out:
+ *
+ * Outputs the code of a part.
+ **/
+void filter_part_build_code (FilterPart *ff, GString *out)
+{
+ GList *l = ff->elements;
+ FilterElement *fe;
+
+ if (ff->code) {
+ filter_part_expand_code(ff, ff->code, out);
+ }
+ while (l) {
+ fe = l->data;
+ filter_element_build_code(fe, out, ff);
+ l = g_list_next(l);
+ }
+}
+
+/**
+ * filter_part_build_code_list:
+ * @l:
+ * @out:
+ *
+ * Construct a list of the filter parts code into
+ * a single string.
+ **/
+void
+filter_part_build_code_list(GList *l, GString *out)
+{
+ FilterPart *fp;
+
+ while (l) {
+ fp = l->data;
+ filter_part_build_code(fp, out);
+ g_string_append(out, "\n ");
+ l = g_list_next(l);
+ }
+}
+
+/**
+ * filter_part_find_list:
+ * @l:
+ * @name:
+ *
+ * Find a filter part stored in a list.
+ *
+ * Return value:
+ **/
+FilterPart *filter_part_find_list (GList *l, const char *name)
+{
+ FilterPart *part;
+ d(printf("Find part named %s\n", name));
+
+ while (l) {
+ part = l->data;
+ if (!strcmp(part->name, name)) {
+ d(printf("Found!\n"));
+ return part;
+ }
+ l = g_list_next(l);
+ }
+ return NULL;
+}
+
+/**
+ * filter_part_next_list:
+ * @l:
+ * @last: The last item retrieved, or NULL to start
+ * from the beginning of the list.
+ *
+ * Iterate through a filter part list.
+ *
+ * Return value: The next value in the list, or NULL if the
+ * list is expired.
+ **/
+FilterPart *filter_part_next_list (GList *l, FilterPart *last)
+{
+ GList *node = l;
+
+ if (last != NULL) {
+ node = g_list_find(node, last);
+ if (node == NULL)
+ node = l;
+ else
+ node = g_list_next(node);
+ }
+ if (node)
+ return node->data;
+ return NULL;
+}
+
+/**
+ * filter_part_expand_code:
+ * @ff:
+ * @str:
+ * @out:
+ *
+ * Expands the variables in string @str based on the values of the part.
+ **/
+void filter_part_expand_code (FilterPart *ff, const char *source, GString *out)
+{
+ const char *newstart, *start, *end;
+ char *name=alloca(32);
+ int len, namelen=32;
+ FilterElement *fe;
+
+ 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;
+ fe = filter_part_find_element(ff, name);
+ d(printf("expand code: looking up variab le '%s' = %p\n", name, fe));
+ if (fe) {
+ g_string_sprintfa(out, "%.*s", newstart-start, start);
+ filter_element_format_sexp(fe, out);
+#if 0
+ } else if ( (val = g_hash_table_lookup(ff->globals, name)) ) {
+ g_string_sprintfa(out, "%.*s", newstart-start, start);
+ e_sexp_encode_string(out, val);
+#endif
+ } else {
+ g_string_sprintfa(out, "%.*s", end-start+1, start);
+ }
+ start = end+1;
+ }
+ g_string_append(out, start);
+}
+
+#if 0
+int main(int argc, char **argv)
+{
+ xmlDocPtr system;
+ FilterPart *ff;
+ GtkWidget *w;
+ GnomeDialog *gd;
+ xmlNodePtr node;
+ GString *code;
+
+ gnome_init("test", "0.0", argc, argv);
+
+ system = xmlParseFile("form.xml");
+ if (system==NULL) {
+ printf("i/o error\n");
+ return 1;
+ }
+
+ ff = filter_part_new();
+ filter_part_xml_create(ff, system->root);
+
+ w = filter_part_get_widget(ff);
+
+ gd = (GnomeDialog *)gnome_dialog_new("Test", "Ok", NULL);
+ gtk_box_pack_start((GtkBox *)gd->vbox, w, FALSE, TRUE, 0);
+ gtk_widget_show((GtkWidget *)gd);
+
+ gnome_dialog_run_and_close(gd);
+
+ code = g_string_new("");
+ filter_part_build_code(ff, code);
+ printf("code is:\n%s\n", code->str);
+
+ return 0;
+}
+#endif
diff --git a/filter/filter-part.h b/filter/filter-part.h
new file mode 100644
index 0000000000..2995046b20
--- /dev/null
+++ b/filter/filter-part.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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_PART_H
+#define _FILTER_PART_H
+
+#include <gtk/gtk.h>
+#include "filter-input.h"
+
+#define FILTER_PART(obj) GTK_CHECK_CAST (obj, filter_part_get_type (), FilterPart)
+#define FILTER_PART_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_part_get_type (), FilterPartClass)
+#define IS_FILTER_PART(obj) GTK_CHECK_TYPE (obj, filter_part_get_type ())
+
+typedef struct _FilterPart FilterPart;
+typedef struct _FilterPartClass FilterPartClass;
+
+struct _FilterPart {
+ GtkObject parent;
+ struct _FilterPartPrivate *priv;
+
+ char *name;
+ char *title;
+ char *code;
+ GList *elements;
+};
+
+struct _FilterPartClass {
+ GtkObjectClass parent_class;
+
+ /* virtual methods */
+
+ /* signals */
+};
+
+guint filter_part_get_type (void);
+FilterPart *filter_part_new (void);
+
+/* methods */
+int filter_part_xml_create (FilterPart *ff, xmlNodePtr node);
+
+xmlNodePtr filter_part_xml_encode (FilterPart *fe);
+int filter_part_xml_decode (FilterPart *fe, xmlNodePtr node);
+
+FilterPart *filter_part_clone (FilterPart *fp);
+
+FilterElement *filter_part_find_element(FilterPart *ff, const char *name);
+
+GtkWidget *filter_part_get_widget (FilterPart *ff);
+void filter_part_build_code (FilterPart *ff, GString *out);
+void filter_part_expand_code (FilterPart *ff, const char *str, GString *out);
+
+/* static functions */
+void filter_part_build_code_list (GList *l, GString *out);
+FilterPart *filter_part_find_list (GList *l, const char *name);
+FilterPart *filter_part_next_list (GList *l, FilterPart *last);
+
+#endif /* ! _FILTER_PART_H */
+
diff --git a/filter/filter-rule.c b/filter/filter-rule.c
new file mode 100644
index 0000000000..9e1da43164
--- /dev/null
+++ b/filter/filter-rule.c
@@ -0,0 +1,525 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+#include <gnome-xml/xmlmemory.h>
+
+#include "filter-rule.h"
+#include "filter-context.h"
+
+#define d(x)
+
+static xmlNodePtr xml_encode(FilterRule *);
+static int xml_decode(FilterRule *, xmlNodePtr, RuleContext *);
+static void build_code(FilterRule *, GString *out);
+static GtkWidget *get_widget(FilterRule *fr, struct _RuleContext *f);
+
+static void filter_rule_class_init (FilterRuleClass *class);
+static void filter_rule_init (FilterRule *gspaper);
+static void filter_rule_finalise (GtkObject *obj);
+
+#define _PRIVATE(x) (((FilterRule *)(x))->priv)
+
+struct _FilterRulePrivate {
+ GtkWidget *parts; /* where the parts are stored */
+};
+
+static GtkObjectClass *parent_class;
+
+enum {
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+guint
+filter_rule_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterRule",
+ sizeof(FilterRule),
+ sizeof(FilterRuleClass),
+ (GtkClassInitFunc)filter_rule_class_init,
+ (GtkObjectInitFunc)filter_rule_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(gtk_object_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+filter_rule_class_init (FilterRuleClass *class)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(gtk_object_get_type ());
+
+ object_class->finalize = filter_rule_finalise;
+
+ /* override methods */
+ class->xml_encode = xml_encode;
+ class->xml_decode = xml_decode;
+ class->build_code = build_code;
+ class->get_widget = get_widget;
+
+ /* signals */
+
+ gtk_object_class_add_signals(object_class, signals, LAST_SIGNAL);
+}
+
+static void
+filter_rule_init (FilterRule *o)
+{
+ o->priv = g_malloc0(sizeof(*o->priv));
+}
+
+static void
+unref_list(GList *l)
+{
+ while (l) {
+ gtk_object_unref((GtkObject *)l->data);
+ l = g_list_next(l);
+ }
+}
+
+static void
+filter_rule_finalise(GtkObject *obj)
+{
+ FilterRule *o = (FilterRule *)obj;
+
+ g_free(o->name);
+ unref_list(o->parts);
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * filter_rule_new:
+ *
+ * Create a new FilterRule object.
+ *
+ * Return value: A new #FilterRule object.
+ **/
+FilterRule *
+filter_rule_new(void)
+{
+ FilterRule *o = (FilterRule *)gtk_type_new(filter_rule_get_type ());
+ return o;
+}
+
+xmlNodePtr filter_rule_xml_encode (FilterRule *fr)
+{
+ return ((FilterRuleClass *)((GtkObject *)fr)->klass)->xml_encode(fr);
+}
+
+static xmlNodePtr xml_encode(FilterRule *fr)
+{
+ xmlNodePtr node, set, work;
+ GList *l;
+
+ node = xmlNewNode(NULL, "rule");
+ switch (fr->grouping) {
+ case FILTER_GROUP_ALL:
+ xmlSetProp(node, "grouping", "all");
+ break;
+ case FILTER_GROUP_ANY:
+ xmlSetProp(node, "grouping", "any");
+ break;
+ }
+ if (fr->name) {
+ work = xmlNewNode(NULL, "title");
+ xmlNodeSetContent(work, fr->name);
+ xmlAddChild(node, work);
+ }
+ set = xmlNewNode(NULL, "partset");
+ xmlAddChild(node, set);
+ l = fr->parts;
+ while (l) {
+ work = filter_part_xml_encode((FilterPart *)l->data);
+ xmlAddChild(set, work);
+ l = g_list_next(l);
+ }
+ return node;
+}
+
+static void load_set(xmlNodePtr node, FilterRule *fr, RuleContext *f)
+{
+ xmlNodePtr work;
+ char *rulename;
+ FilterPart *part;
+
+ work = node->childs;
+ while (work) {
+ if (!strcmp(work->name, "part")) {
+ rulename = xmlGetProp(work, "name");
+ part = rule_context_find_part(f, rulename);
+ if (part) {
+ part = filter_part_clone(part);
+ filter_part_xml_decode(part, work);
+ filter_rule_add_part(fr, part);
+ } else {
+ g_warning("cannot find rule part '%s'\n", rulename);
+ }
+ xmlFree(rulename);
+ } else {
+ g_warning("Unknwon xml node in part: %s", work->name);
+ }
+ work = work->next;
+ }
+}
+
+int filter_rule_xml_decode (FilterRule *fr, xmlNodePtr node, RuleContext *f)
+{
+ return ((FilterRuleClass *)((GtkObject *)fr)->klass)->xml_decode(fr, node, f);
+}
+
+static int xml_decode(FilterRule *fr, xmlNodePtr node, RuleContext *f)
+{
+ xmlNodePtr work;
+ char *grouping;
+
+ if (fr->name) {
+ g_free(fr->name);
+ fr->name = NULL;
+ }
+ grouping = xmlGetProp(node, "grouping");
+ if (!strcmp(grouping, "any"))
+ fr->grouping = FILTER_GROUP_ANY;
+ else
+ fr->grouping = FILTER_GROUP_ALL;
+ work = node->childs;
+ while (work) {
+ if (!strcmp(work->name, "partset")) {
+ load_set(work, fr, f);
+ } else if (!strcmp(work->name, "title")) {
+ if (!fr->name)
+ fr->name = xmlNodeGetContent(work);
+ }
+ work = work->next;
+ }
+ return 0;
+}
+
+void filter_rule_add_part (FilterRule *fr, FilterPart *fp)
+{
+ fr->parts = g_list_append(fr->parts, fp);
+}
+
+void filter_rule_remove_part (FilterRule *fr, FilterPart *fp)
+{
+ fr->parts = g_list_remove(fr->parts, fp);
+}
+
+void filter_rule_replace_part(FilterRule *fr, FilterPart *fp, FilterPart *new)
+{
+ GList *l;
+
+ l = g_list_find(fr->parts, fp);
+ if (l) {
+ l->data = new;
+ } else {
+ fr->parts = g_list_append(fr->parts, new);
+ }
+}
+
+void filter_rule_build_code (FilterRule *fr, GString *out)
+{
+ return ((FilterRuleClass *)((GtkObject *)fr)->klass)->build_code(fr, out);
+}
+
+static void build_code(FilterRule *fr, GString *out)
+{
+ switch (fr->grouping) {
+ case FILTER_GROUP_ALL:
+ g_string_append(out, " (and\n ");
+ break;
+ case FILTER_GROUP_ANY:
+ g_string_append(out, " (or\n ");
+ break;
+ default:
+ g_warning("Invalid grouping");
+ }
+
+ filter_part_build_code_list(fr->parts, out);
+ g_string_append(out, ")\n");
+}
+
+
+static void
+match_all(GtkRadioButton *w, FilterRule *fr)
+{
+ if (gtk_toggle_button_get_active((GtkToggleButton *)w))
+ fr->grouping = FILTER_GROUP_ALL;
+}
+
+static void
+match_any(GtkRadioButton *w, FilterRule *fr)
+{
+ if (gtk_toggle_button_get_active((GtkToggleButton *)w))
+ fr->grouping = FILTER_GROUP_ANY;
+}
+
+struct _part_data {
+ FilterRule *fr;
+ RuleContext *f;
+ FilterPart *part;
+ GtkWidget *partwidget, *container;
+};
+
+static void option_activate(GtkMenuItem *item, struct _part_data *data)
+{
+ FilterPart *part = gtk_object_get_data((GtkObject *)item, "part");
+ FilterPart *newpart;
+
+ /* dont update if we haven't changed */
+ if (!strcmp(part->title, data->part->title))
+ return;
+
+ /* here we do a widget shuffle, throw away the old widget/rulepart,
+ and create another */
+ if (data->partwidget)
+ gtk_container_remove((GtkContainer *)data->container, data->partwidget);
+ newpart = filter_part_clone(part);
+ filter_rule_replace_part(data->fr, data->part, newpart);
+ gtk_object_unref((GtkObject *)data->part);
+ data->part = newpart;
+ data->partwidget = filter_part_get_widget(newpart);
+ if (data->partwidget)
+ gtk_box_pack_start((GtkBox *)data->container, data->partwidget, FALSE, FALSE, 0);
+}
+
+static GtkWidget *
+get_rule_part_widget(RuleContext *f, FilterPart *newpart, FilterRule *fr)
+{
+ FilterPart *part = NULL;
+ GtkMenu *menu;
+ GtkMenuItem *item;
+ GtkOptionMenu *omenu;
+ GtkHBox *hbox;
+ GtkWidget *p;
+ int index=0, current=0;
+ struct _part_data *data;
+
+ data = g_malloc0(sizeof(*data));
+ data->fr = fr;
+ data->f = f;
+ data->part = newpart;
+
+ hbox = (GtkHBox *)gtk_hbox_new(FALSE, 0);
+ /* only set to automatically clean up the memory */
+ gtk_object_set_data_full((GtkObject *)hbox, "data", data, g_free);
+
+ p = filter_part_get_widget(newpart);
+
+ data->partwidget = p;
+ data->container = (GtkWidget *)hbox;
+
+ menu = (GtkMenu *)gtk_menu_new();
+ /* sigh, this is a little ugly */
+ while ((part=rule_context_next_part(f, part))) {
+ item = (GtkMenuItem *)gtk_menu_item_new_with_label(part->title);
+ gtk_object_set_data((GtkObject *)item, "part", part);
+ gtk_signal_connect((GtkObject *)item, "activate", option_activate, data);
+ gtk_menu_append(menu, (GtkWidget *)item);
+ gtk_widget_show((GtkWidget *)item);
+ if (!strcmp(newpart->title, part->title)) {
+ current = index;
+ }
+ index++;
+ }
+
+ omenu = (GtkOptionMenu *)gtk_option_menu_new();
+ gtk_option_menu_set_menu(omenu, (GtkWidget *)menu);
+ gtk_option_menu_set_history(omenu, current);
+ gtk_widget_show((GtkWidget *)omenu);
+
+ gtk_box_pack_start((GtkBox *)hbox, (GtkWidget *)omenu, FALSE, FALSE, 0);
+ if (p) {
+ gtk_box_pack_start((GtkBox *)hbox, p, FALSE, FALSE, 0);
+ }
+ gtk_widget_show_all((GtkWidget *)hbox);
+
+ return (GtkWidget *)hbox;
+}
+
+struct _rule_data {
+ FilterRule *fr;
+ RuleContext *f;
+ GtkWidget *parts;
+};
+
+static void
+less_parts(GtkWidget *button, struct _rule_data *data)
+{
+ GList *l;
+ FilterPart *part;
+ GtkWidget *w;
+
+ l = data->fr->parts;
+ if (g_list_length(l) < 2)
+ return;
+
+ /* remove the last one from the list */
+ l = g_list_last(l);
+ part = l->data;
+ filter_rule_remove_part(data->fr, part);
+ gtk_object_unref((GtkObject *)part);
+
+ /* and from the display */
+ l = g_list_last(GTK_BOX(data->parts)->children);
+ w = ((GtkBoxChild *)l->data)->widget;
+ gtk_container_remove((GtkContainer *)data->parts, w);
+}
+
+static void
+more_parts(GtkWidget *button, struct _rule_data *data)
+{
+ FilterPart *new;
+ GtkWidget *w;
+
+ /* create a new rule entry, use the first type of rule */
+ new = rule_context_next_part(data->f, NULL);
+ if (new) {
+ new = filter_part_clone(new);
+ filter_rule_add_part(data->fr, new);
+ w = get_rule_part_widget(data->f, new, data->fr);
+ gtk_box_pack_start((GtkBox *)data->parts, w, FALSE, FALSE, 0);
+ }
+}
+
+static void
+name_changed(GtkEntry *entry, FilterRule *fr)
+{
+ g_free(fr->name);
+ fr->name = g_strdup(gtk_entry_get_text(entry));
+}
+
+GtkWidget *filter_rule_get_widget (FilterRule *fr, struct _RuleContext *f)
+{
+ return ((FilterRuleClass *)((GtkObject *)fr)->klass)->get_widget(fr, f);
+}
+
+static GtkWidget *get_widget(FilterRule *fr, struct _RuleContext *f)
+{
+ GtkVBox *vbox, *parts, *inframe;
+ GtkHBox *hbox;
+ GtkWidget *w;
+ GtkRadioButton *g0, *g1;
+ GtkFrame *frame;
+ GtkEntry *name;
+ GtkLabel *label;
+ GList *l;
+ FilterPart *part;
+ struct _rule_data *data;
+
+ /* this stuff should probably be a table, but the
+ rule parts need to be a vbox */
+ vbox = (GtkVBox *)gtk_vbox_new(FALSE, 3);
+
+ label = (GtkLabel *)gtk_label_new("Name");
+ name = (GtkEntry *)gtk_entry_new();
+ if (fr->name)
+ gtk_entry_set_text(name, fr->name);
+ hbox = (GtkHBox *)gtk_hbox_new(FALSE, 3);
+ gtk_box_pack_start((GtkBox *)hbox, (GtkWidget *)label, FALSE, FALSE, 0);
+ gtk_box_pack_start((GtkBox *)hbox, (GtkWidget *)name, TRUE, TRUE, 0);
+ gtk_box_pack_start((GtkBox *)vbox, (GtkWidget *)hbox, FALSE, FALSE, 3);
+ gtk_signal_connect((GtkObject *)name, "changed", name_changed, fr);
+
+ frame = (GtkFrame *)gtk_frame_new("Messages matching");
+ inframe = (GtkVBox *)gtk_vbox_new(FALSE, 3);
+ gtk_container_add((GtkContainer *)frame, (GtkWidget *)inframe);
+
+ hbox = (GtkHBox *)gtk_hbox_new(FALSE, 3);
+ g0 = (GtkRadioButton *)gtk_radio_button_new_with_label(NULL, "Match all parts");
+ g1 = (GtkRadioButton *)gtk_radio_button_new_with_label(g0->group, "Match any part");
+ if (fr->grouping == FILTER_GROUP_ALL) {
+ gtk_toggle_button_set_active((GtkToggleButton *)g0, TRUE);
+ } else {
+ gtk_toggle_button_set_active((GtkToggleButton *)g1, TRUE);
+ }
+ gtk_box_pack_start((GtkBox *)hbox, (GtkWidget *)g0, FALSE, FALSE, 0);
+ gtk_box_pack_start((GtkBox *)hbox, (GtkWidget *)g1, FALSE, FALSE, 0);
+ gtk_box_pack_start((GtkBox *)inframe, (GtkWidget *)hbox, FALSE, FALSE, 3);
+
+ gtk_signal_connect((GtkObject *)g0, "toggled", match_all, fr);
+ gtk_signal_connect((GtkObject *)g1, "toggled", match_any, fr);
+
+ /* this is the parts list, it should probably be inside a scrolling list */
+ parts = (GtkVBox *)gtk_vbox_new(FALSE, 3);
+
+ /* data for the parts part of the display */
+ data = g_malloc0(sizeof(*data));
+ data->f = f;
+ data->fr = fr;
+ data->parts = (GtkWidget *)parts;
+
+ /* only set to automatically clean up the memory */
+ gtk_object_set_data_full((GtkObject *)vbox, "data", data, g_free);
+
+ l = fr->parts;
+ while (l) {
+ part = l->data;
+ w = get_rule_part_widget(f, part, fr);
+ gtk_box_pack_start((GtkBox *)parts, (GtkWidget *)w, FALSE, FALSE, 3);
+ l = g_list_next(l);
+ }
+
+ gtk_box_pack_start((GtkBox *)inframe, (GtkWidget *)parts, FALSE, FALSE, 3);
+
+ hbox = (GtkHBox *)gtk_hbox_new(FALSE, 3);
+ w = gtk_button_new_with_label("Less");
+ gtk_signal_connect((GtkObject *)w, "clicked", less_parts, data);
+ gtk_box_pack_end((GtkBox *)hbox, (GtkWidget *)w, FALSE, FALSE, 3);
+ w = gtk_button_new_with_label("More");
+ gtk_signal_connect((GtkObject *)w, "clicked", more_parts, data);
+ gtk_box_pack_end((GtkBox *)hbox, (GtkWidget *)w, FALSE, FALSE, 3);
+ gtk_box_pack_start((GtkBox *)inframe, (GtkWidget *)hbox, FALSE, FALSE, 3);
+
+ gtk_box_pack_start((GtkBox *)vbox, (GtkWidget *)frame, FALSE, FALSE, 3);
+
+ gtk_widget_show_all((GtkWidget *)vbox);
+ return (GtkWidget *)vbox;
+}
+
+FilterRule *filter_rule_next_list (GList *l, FilterRule *last)
+{
+ GList *node = l;
+
+ if (last != NULL) {
+ node = g_list_find(node, last);
+ if (node == NULL)
+ node = l;
+ else
+ node = g_list_next(node);
+ }
+ if (node)
+ return node->data;
+ return NULL;
+}
diff --git a/filter/filter-rule.h b/filter/filter-rule.h
new file mode 100644
index 0000000000..ca5b1ddfb7
--- /dev/null
+++ b/filter/filter-rule.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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_RULE_H
+#define _FILTER_RULE_H
+
+#include <gtk/gtk.h>
+
+#include "filter-part.h"
+
+#define FILTER_RULE(obj) GTK_CHECK_CAST (obj, filter_rule_get_type (), FilterRule)
+#define FILTER_RULE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_rule_get_type (), FilterRuleClass)
+#define IS_FILTER_RULE(obj) GTK_CHECK_TYPE (obj, filter_rule_get_type ())
+
+typedef struct _FilterRule FilterRule;
+typedef struct _FilterRuleClass FilterRuleClass;
+
+struct _RuleContext;
+
+enum _filter_grouping_t {
+ FILTER_GROUP_ALL, /* all rules must match */
+ FILTER_GROUP_ANY /* any rule must match */
+};
+
+struct _FilterRule {
+ GtkObject parent;
+ struct _FilterRulePrivate *priv;
+
+ char *name;
+
+ enum _filter_grouping_t grouping;
+ GList *parts;
+};
+
+struct _FilterRuleClass {
+ GtkObjectClass parent_class;
+
+ /* virtual methods */
+ xmlNodePtr (*xml_encode)(FilterRule *);
+ int (*xml_decode)(FilterRule *, xmlNodePtr, struct _RuleContext *);
+
+ void (*build_code)(FilterRule *, GString *out);
+
+ GtkWidget *(*get_widget)(FilterRule *fr, struct _RuleContext *f);
+
+ /* signals */
+};
+
+guint filter_rule_get_type (void);
+FilterRule *filter_rule_new (void);
+
+/* methods */
+xmlNodePtr filter_rule_xml_encode (FilterRule *fr);
+int filter_rule_xml_decode (FilterRule *fr, xmlNodePtr node, struct _RuleContext *f);
+
+void filter_rule_add_part (FilterRule *fr, FilterPart *fp);
+void filter_rule_remove_part (FilterRule *fr, FilterPart *fp);
+void filter_rule_replace_part(FilterRule *fr, FilterPart *fp, FilterPart *new);
+
+GtkWidget *filter_rule_get_widget (FilterRule *fr, struct _RuleContext *f);
+
+void filter_rule_build_code (FilterRule *fr, GString *out);
+/*
+void filter_rule_build_action(FilterRule *fr, GString *out);
+*/
+
+/* static functions */
+FilterRule *filter_rule_next_list (GList *l, FilterRule *last);
+
+#endif /* ! _FILTER_RULE_H */
+
diff --git a/filter/filter-xml.c b/filter/filter-xml.c
deleted file mode 100644
index 61788286bf..0000000000
--- a/filter/filter-xml.c
+++ /dev/null
@@ -1,591 +0,0 @@
-/* -*- Mode: C; c-file-style: "linux"; indent-tabs-mode: t; c-basic-offset: 8; -*- */
-
-/* Load save filter descriptions/options from an xml file */
-
-#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"
-
-#define d(x)
-
-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 },
- { "string", FILTER_XML_STRING },
- { "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 int
-tokenise_xmlfreeprop(char *name)
-{
- int ret = -1;
- ret = tokenise(name);
- free(name);
- return ret;
-}
-
-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>";
-}
-
-
-static xmlNodePtr
-find_node(xmlNodePtr start, char *name)
-{
- d(printf("trying to find node '%s'\n", name));
- while (start && strcmp(start->name, name))
- start = start->next;
- d(printf("node = %p\n", start));
- return start;
-}
-
-static xmlNodePtr
-find_node_attr(xmlNodePtr start, char *name, char *attrname, char *attrvalue)
-{
- char *s;
-
- d(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);
- d(printf(" comparing '%s' to '%s'\n", s, attrvalue));
- if (s && !strcmp(s, attrvalue)) {
- free(s);
- break;
- }
- free(s);
- start = start->next;
- }
- return start;
-}
-
-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 = g_strdup (node->content);
- desc->type = type;
- desc->vartype = vartype;
- desc->varname = g_strdup(varname);
- d(printf(" **** node name = %s var name = %s var type = %s\n", node->name, varname, detokenise(vartype)));
- list = g_list_append(list, desc);
- d(printf("appending '%s'\n", node->content));
- newtype = type;
- newvartype = -1;
- newvarname = NULL;
- } else {
- newtype = tokenise(node->name);
- newvartype = tokenise_xmlfreeprop(xmlGetProp(node, "type"));
- newvarname = xmlGetProp(node, "name");
- }
- n = node->childs;
- while (n) {
- d(printf("adding child '%s'\n", n->name));
- list = g_list_concat(list, load_desc(n, newtype, newvartype, newvarname));
- n = n->next;
- }
- if (newvarname)
- free(newvarname);
- node = node->next;
- }
- return list;
-}
-
-GList *
-filter_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_xmlfreeprop(xmlGetProp(ruleset, "type"));
-
- d(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");
-
- d(printf(" rule, name = %s\n", r->name));
-
- while (n) {
- type = tokenise(n->name);
- d(printf(" n, name = %s\n", n->name));
- d(printf(" ncontent = %s\n", n->content));
- d(printf(" childs = %p\n", n->childs));
- if (n->childs) {
- d(printf(" childs content = %s\n", n->childs->content));
- }
- switch(type) {
- case FILTER_XML_CODE:
- r->code = xmlNodeGetContent(n);
- break;
- case FILTER_XML_DESC:
- d(printf(" ** loading description\n"));
- r->description = load_desc(n->childs, type, -1, NULL);
- d(printf(" ** done loading 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)
-{
- d(printf("finding, is %s = %s?\n", a->name, name));
- return strcmp(a->name, name);
-}
-
-int
-filter_find_arg(FilterArg *a, char *name)
-{
- d(printf("finding, is %s = %s?\n", a->name, name));
- return strcmp(a->name, name);
-}
-
-static FilterArg *
-load_optionvalue(struct filter_desc *desc, xmlNodePtr node)
-{
- FilterArg *arg = NULL;
-
- d(printf("creating arg entry for '%s'\n", desc->varname));
-
- switch(desc->vartype) {
- case FILTER_XML_ADDRESS:
- arg = filter_arg_address_new(desc->varname);
- break;
- case FILTER_XML_FOLDER:
- arg = filter_arg_folder_new(desc->varname);
- break;
- case FILTER_XML_STRING:
- arg = filter_arg_string_new(desc->varname);
- break;
- default:
- d(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;
-}
-
-GList *
-filter_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;
- 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 NULL;
- }
- option = find_node(optionset->childs, "option");
- while (option) {
- o = option->childs;
- op = g_malloc0(sizeof(*op));
- d(printf("option = %s\n", o->name));
- d(printf("option, type=%s\n", xmlGetProp(option, "type")));
- op->type = tokenise_xmlfreeprop(xmlGetProp(option, "type"));
- while (o) {
- char *rulestr;
-
- type = tokenise(o->name);
- switch (type) {
- case FILTER_XML_OPTIONRULE:
- rulestr = xmlGetProp(o, "rule");
- lrule = g_list_find_custom(rules, rulestr, (GCompareFunc) filter_find_rule);
- if (lrule) {
- fr = lrule->data;
- d(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);
- d(printf("Adding arg %s\n", arg->name));
- }
- }
- ldesc = g_list_next(ldesc);
- }
- } else {
- /* FIXME: memleak */
- printf("Cannot find rule: %s\n", rulestr);
- }
- free(rulestr);
- break;
- case FILTER_XML_DESC:
- d(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
-write_description(xmlDocPtr doc, GList *descl)
-{
- xmlNodePtr d;
- struct filter_desc *desc;
-
- desc = descl->data;
- d = xmlNewDocNode(doc, NULL, "description", NULL);
- xmlNodeSetContent(d, desc->data);
- return d;
-}
-
-xmlNodePtr
-filter_write_optionset(xmlDocPtr doc, GList *optionl)
-{
- xmlNodePtr root, 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));
-
- if (op->description) {
- xmlNodePtr desc;
-
- desc = write_description(doc, op->description);
- xmlAddChild(option, desc);
- }
-
- 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;
-}
-
-/* utility functions */
-struct filter_optionrule *
-filter_clone_optionrule(struct filter_optionrule *or)
-{
- GList *arg;
- struct filter_optionrule *rule;
-
- rule = g_malloc0(sizeof(*rule));
-
- rule->rule = or->rule;
- arg = or->args;
- while (arg) {
- FilterArg *new = filter_arg_clone(FILTER_ARG(arg->data));
- gtk_object_set_data((GtkObject *)new, "origin", arg->data);
- rule->args = g_list_append(rule->args, new);
- arg = g_list_next(arg);
- }
- return rule;
-}
-
-void
-filter_clone_optionrule_free(struct filter_optionrule *or)
-{
- GList *argl;
-
- d(printf("---- free optionrule\n"));
-
- argl = or->args;
- while (argl) {
- gtk_object_unref(GTK_OBJECT(argl->data));
- argl = g_list_next(argl);
- }
- g_list_free(or->args);
- g_free(or);
-}
-
-struct filter_optionrule *
-filter_optionrule_new_from_rule(struct filter_rule *rule)
-{
- struct filter_optionrule *or;
- GList *descl;
-
- or = g_malloc0(sizeof(*or));
-
- or->rule = rule;
-
- descl = rule->description;
- while (descl) {
- struct filter_desc *desc = descl->data;
- if (desc->varname && desc->vartype != -1) {
- FilterArg *arg = NULL;
- switch (desc->vartype) {
- case FILTER_XML_ADDRESS:
- arg = filter_arg_address_new(desc->varname);
- break;
- case FILTER_XML_FOLDER:
- arg = filter_arg_folder_new(desc->varname);
- break;
- case FILTER_XML_STRING:
- arg = filter_arg_string_new(desc->varname);
- break;
- }
- if (arg) {
- or->args = g_list_append(or->args, arg);
- }
- }
- descl = g_list_next(descl);
- }
- return or;
-}
-
-void
-filter_description_free(GList *descl)
-{
- GList *node;
-
- node = descl;
- while (node) {
- GList *next = g_list_next(node);
- struct filter_desc *d = node->data;
-
- g_free(d->data);
- g_free(d->varname);
- g_free(d);
-
- node = next;
- }
- g_list_free(descl);
-}
-
-void
-filter_load_ruleset_free(GList *nodel)
-{
- GList *node = nodel;
-
- while (node) {
- GList *next = g_list_next(node);
- struct filter_rule *r = node->data;
-
- filter_description_free(r->description);
-
- /* g_free(r->name); */
- /* g_free(r->code); */
-
- g_free(r);
- node = next;
- }
- g_list_free(nodel);
-}
-
-void
-filter_load_optionset_free(GList *optionl)
-{
- GList *option = optionl;
- while (option) {
- GList *next = g_list_next(option);
- struct filter_option *fo = option->data;
- GList *optionrule = fo->options;
-
- while (optionrule) {
- GList *next = g_list_next(optionrule);
- struct filter_optionrule *or = optionrule->data;
- GList *arg = or->args;
-
- while (arg) {
- gtk_object_unref(arg->data);
- arg = g_list_next(arg);
- }
-
- g_list_free(or->args);
- g_free(or);
- optionrule = next;
- }
- filter_description_free(fo->description);
- g_list_free(fo->options);
- g_free(fo);
- option = next;
- }
-}
-
-GList *filter_load_ruleset_file(const char *name)
-{
- xmlDocPtr doc;
- GList *rules;
-
- doc = xmlParseFile(name);
- rules = filter_load_ruleset(doc);
- xmlFreeDoc(doc);
-
- return rules;
-}
-
-GList *filter_load_optionset_file(const char *name, GList *rules)
-{
- xmlDocPtr doc;
- GList *options;
-
- doc = xmlParseFile(name);
- if( doc == NULL ) {
- g_warning( "Couldn't load option file %s!", name );
- return NULL;
- }
- options = filter_load_optionset(doc, rules);
- xmlFreeDoc(doc);
-
- return options;
-}
-
-int filter_write_optionset_file(const char *name, GList *optionl)
-{
- xmlDocPtr out;
- xmlNodePtr optionset;
- xmlNodePtr filteroptions;
- int ret;
-
- out = xmlNewDoc("1.0");
- optionset = filter_write_optionset(out, optionl);
- filteroptions = xmlNewDocNode(out, NULL, "filteroptions", NULL);
- xmlAddChild(filteroptions, optionset);
- xmlDocSetRootElement(out, filteroptions);
- ret = xmlSaveFile(name, out);
- xmlFreeDoc(out);
-
- return ret;
-}
diff --git a/filter/filter-xml.h b/filter/filter-xml.h
deleted file mode 100644
index 00b4758feb..0000000000
--- a/filter/filter-xml.h
+++ /dev/null
@@ -1,78 +0,0 @@
-
-#ifndef _FILTER_XML_H
-#define _FILTER_XML_H
-
-#include <glib.h>
-#include <gnome-xml/tree.h>
-
-#include "filter-arg.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_STRING,
- 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 */
-};
-
-GList *filter_load_ruleset(xmlDocPtr doc);
-GList *filter_load_optionset(xmlDocPtr doc, GList *rules);
-xmlNodePtr filter_write_optionset(xmlDocPtr doc, GList *optionl);
-
-void filter_description_free(GList *descl);
-void filter_load_ruleset_free(GList *nodel);
-void filter_load_optionset_free(GList *optionl);
-
-GList *filter_load_ruleset_file(const char *name);
-GList *filter_load_optionset_file(const char *name, GList *rules);
-int filter_write_optionset_file(const char *name, GList *optionl);
-
-/* callbacks for searching GLists of various types */
-int filter_find_rule(struct filter_rule *a, char *name);
-int filter_find_arg(FilterArg *a, char *name);
-
-/* utility functions */
-struct filter_optionrule *filter_clone_optionrule(struct filter_optionrule *or);
-void filter_clone_optionrule_free(struct filter_optionrule *or);
-struct filter_optionrule *filter_optionrule_new_from_rule(struct filter_rule *rule);
-
-#endif /* ! _FILTER_XML_H */
diff --git a/filter/filter.glade b/filter/filter.glade
new file mode 100644
index 0000000000..7592bc30fd
--- /dev/null
+++ b/filter/filter.glade
@@ -0,0 +1,383 @@
+<?xml version="1.0"?>
+<GTK-Interface>
+
+<project>
+ <name>Filter</name>
+ <program_name>filter</program_name>
+ <directory></directory>
+ <source_directory>src</source_directory>
+ <pixmaps_directory>pixmaps</pixmaps_directory>
+ <language>C</language>
+ <gnome_support>True</gnome_support>
+ <gettext_support>True</gettext_support>
+</project>
+
+<widget>
+ <class>GnomeDialog</class>
+ <name>edit_filter</name>
+ <type>GTK_WINDOW_TOPLEVEL</type>
+ <position>GTK_WIN_POS_NONE</position>
+ <modal>False</modal>
+ <allow_shrink>False</allow_shrink>
+ <allow_grow>False</allow_grow>
+ <auto_shrink>False</auto_shrink>
+ <auto_close>False</auto_close>
+ <hide_on_close>False</hide_on_close>
+
+ <widget>
+ <class>GtkVBox</class>
+ <child_name>GnomeDialog:vbox</child_name>
+ <name>dialog-vbox1</name>
+ <homogeneous>False</homogeneous>
+ <spacing>8</spacing>
+ <child>
+ <padding>4</padding>
+ <expand>True</expand>
+ <fill>True</fill>
+ </child>
+
+ <widget>
+ <class>GtkHButtonBox</class>
+ <child_name>GnomeDialog:action_area</child_name>
+ <name>dialog-action_area1</name>
+ <layout_style>GTK_BUTTONBOX_END</layout_style>
+ <spacing>8</spacing>
+ <child_min_width>85</child_min_width>
+ <child_min_height>27</child_min_height>
+ <child_ipad_x>7</child_ipad_x>
+ <child_ipad_y>0</child_ipad_y>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>True</fill>
+ <pack>GTK_PACK_END</pack>
+ </child>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>button1</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <stock_button>GNOME_STOCK_BUTTON_OK</stock_button>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>button3</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <stock_button>GNOME_STOCK_BUTTON_CANCEL</stock_button>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>GtkOptionMenu</class>
+ <name>filter_source</name>
+ <sensitive>False</sensitive>
+ <can_focus>True</can_focus>
+ <items>Incoming
+Outgoing
+</items>
+ <initial_choice>0</initial_choice>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
+ </child>
+ </widget>
+
+ <widget>
+ <class>GtkFrame</class>
+ <name>frame1</name>
+ <label>Filter Rules</label>
+ <label_xalign>0</label_xalign>
+ <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
+ <child>
+ <padding>0</padding>
+ <expand>True</expand>
+ <fill>True</fill>
+ </child>
+
+ <widget>
+ <class>GtkHBox</class>
+ <name>hbox1</name>
+ <homogeneous>False</homogeneous>
+ <spacing>0</spacing>
+
+ <widget>
+ <class>GtkScrolledWindow</class>
+ <name>scrolledwindow1</name>
+ <width>256</width>
+ <hscrollbar_policy>GTK_POLICY_ALWAYS</hscrollbar_policy>
+ <vscrollbar_policy>GTK_POLICY_ALWAYS</vscrollbar_policy>
+ <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy>
+ <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy>
+ <child>
+ <padding>0</padding>
+ <expand>True</expand>
+ <fill>True</fill>
+ </child>
+
+ <widget>
+ <class>GtkViewport</class>
+ <name>viewport1</name>
+ <shadow_type>GTK_SHADOW_IN</shadow_type>
+
+ <widget>
+ <class>GtkList</class>
+ <name>rule_list</name>
+ <selection_mode>GTK_SELECTION_SINGLE</selection_mode>
+ </widget>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>GtkVBox</class>
+ <name>vbox1</name>
+ <homogeneous>False</homogeneous>
+ <spacing>0</spacing>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
+ </child>
+
+ <widget>
+ <class>GtkVButtonBox</class>
+ <name>vbuttonbox1</name>
+ <layout_style>GTK_BUTTONBOX_DEFAULT_STYLE</layout_style>
+ <spacing>0</spacing>
+ <child_min_width>85</child_min_width>
+ <child_min_height>27</child_min_height>
+ <child_ipad_x>6</child_ipad_x>
+ <child_ipad_y>0</child_ipad_y>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
+ </child>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>rule_add</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <label>Add</label>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>rule_edit</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <label>Edit</label>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>rule_delete</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <label>Delete</label>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>rule_up</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <stock_button>GNOME_STOCK_BUTTON_UP</stock_button>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>rule_down</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <stock_button>GNOME_STOCK_BUTTON_DOWN</stock_button>
+ </widget>
+ </widget>
+ </widget>
+ </widget>
+ </widget>
+ </widget>
+</widget>
+
+<widget>
+ <class>GnomeDialog</class>
+ <name>edit_vfolder</name>
+ <title>Edit VFolders</title>
+ <type>GTK_WINDOW_TOPLEVEL</type>
+ <position>GTK_WIN_POS_NONE</position>
+ <modal>False</modal>
+ <allow_shrink>False</allow_shrink>
+ <allow_grow>False</allow_grow>
+ <auto_shrink>False</auto_shrink>
+ <auto_close>False</auto_close>
+ <hide_on_close>False</hide_on_close>
+
+ <widget>
+ <class>GtkVBox</class>
+ <child_name>GnomeDialog:vbox</child_name>
+ <name>dialog-vbox2</name>
+ <homogeneous>False</homogeneous>
+ <spacing>8</spacing>
+ <child>
+ <padding>4</padding>
+ <expand>True</expand>
+ <fill>True</fill>
+ </child>
+
+ <widget>
+ <class>GtkHButtonBox</class>
+ <child_name>GnomeDialog:action_area</child_name>
+ <name>dialog-action_area2</name>
+ <layout_style>GTK_BUTTONBOX_END</layout_style>
+ <spacing>8</spacing>
+ <child_min_width>85</child_min_width>
+ <child_min_height>27</child_min_height>
+ <child_ipad_x>7</child_ipad_x>
+ <child_ipad_y>0</child_ipad_y>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>True</fill>
+ <pack>GTK_PACK_END</pack>
+ </child>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>button13</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <stock_button>GNOME_STOCK_BUTTON_OK</stock_button>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>button15</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <stock_button>GNOME_STOCK_BUTTON_CANCEL</stock_button>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>GtkFrame</class>
+ <name>frame2</name>
+ <label>Virtual Folders</label>
+ <label_xalign>0</label_xalign>
+ <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
+ <child>
+ <padding>0</padding>
+ <expand>True</expand>
+ <fill>True</fill>
+ </child>
+
+ <widget>
+ <class>GtkHBox</class>
+ <name>hbox2</name>
+ <homogeneous>False</homogeneous>
+ <spacing>0</spacing>
+
+ <widget>
+ <class>GtkScrolledWindow</class>
+ <name>scrolledwindow2</name>
+ <width>256</width>
+ <height>167</height>
+ <hscrollbar_policy>GTK_POLICY_ALWAYS</hscrollbar_policy>
+ <vscrollbar_policy>GTK_POLICY_ALWAYS</vscrollbar_policy>
+ <hupdate_policy>GTK_UPDATE_CONTINUOUS</hupdate_policy>
+ <vupdate_policy>GTK_UPDATE_CONTINUOUS</vupdate_policy>
+ <child>
+ <padding>0</padding>
+ <expand>True</expand>
+ <fill>True</fill>
+ </child>
+
+ <widget>
+ <class>GtkViewport</class>
+ <name>viewport2</name>
+ <shadow_type>GTK_SHADOW_IN</shadow_type>
+
+ <widget>
+ <class>GtkList</class>
+ <name>rule_list</name>
+ <selection_mode>GTK_SELECTION_SINGLE</selection_mode>
+ </widget>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>GtkVBox</class>
+ <name>vbox2</name>
+ <homogeneous>False</homogeneous>
+ <spacing>0</spacing>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
+ </child>
+
+ <widget>
+ <class>GtkVButtonBox</class>
+ <name>vbuttonbox2</name>
+ <layout_style>GTK_BUTTONBOX_DEFAULT_STYLE</layout_style>
+ <spacing>0</spacing>
+ <child_min_width>85</child_min_width>
+ <child_min_height>27</child_min_height>
+ <child_ipad_x>6</child_ipad_x>
+ <child_ipad_y>0</child_ipad_y>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
+ </child>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>rule_add</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <label>Add</label>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>rule_edit</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <label>Edit</label>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>rule_delete</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <label>Delete</label>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>rule_up</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <stock_button>GNOME_STOCK_BUTTON_UP</stock_button>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>rule_down</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <stock_button>GNOME_STOCK_BUTTON_DOWN</stock_button>
+ </widget>
+ </widget>
+ </widget>
+ </widget>
+ </widget>
+ </widget>
+</widget>
+
+</GTK-Interface>
diff --git a/filter/filtertypes.xml b/filter/filtertypes.xml
index 2a94de574f..db5ceaa3ac 100644
--- a/filter/filtertypes.xml
+++ b/filter/filtertypes.xml
@@ -1,110 +1,105 @@
<?xml version="1.0"?>
<filterdescription>
-<ruleset type="match">
-<rule name="from-address">
- <code>
- (match-all (header-contains "From" ${sender}))
- </code>
- <description lang="en">The From address matches <source type="address" name="sender">sender(s)</source>.</description>
-</rule>
-
-<rule name="to-address">
- <code>
- (match-all (or (header-contains "To" ${recipient})
- (header-contains "Cc" ${recipient})))
- </code>
- <description lang="en">The To or Cc address matches <source type="address" name="recipient">recipients</source>.</description>
-</rule>
-
-<rule name="subject-contains">
- <code>
- (match-all (header-contains "Subject" ${words}))
- </code>
- <description lang="en">The Subject contains <source type="string" name="words">words</source>.</description>
-</rule>
-
-<rule name="body-contains">
- <code>
- (match-all (body-contains ${words}))
- </code>
- <description lang="en">The body contains <source type="string" name="words">words</source>.</description>
-</rule>
-
-<rule name="cc-address">
- <code>
- (match-all (header-contains "CC" ${self-email}))
- </code>
- <description lang="en">I am in the cc list.</description>
-</rule>
-
-<rule name="msg-size">
- <code>
- (&amp; (&gt; message-size (size-lower size-range))
- (&lt; message-size (size-uppwer size-range)))
- </code>
- <description lang="en">The message is a <source type="size-range" name="size">certain size</source>.</description>
-</rule>
-</ruleset>
-
-<ruleset type="action">
-<rule name="copy-me">
- <code>
- (copy-to ${folder})
- </code>
- <description language="en">Send a copy to <source type="folder" name="folder">folder</source>.</description>
-</rule>
-<rule name="forward">
- <code>
- (forward-to ${address})
- </code>
- <description language="en">Forward the message to <source type="address" name="address">people</source>.</description>
-</rule>
-<rule name="delete">
- <code>
- (delete)
- </code>
- <description language="en">Delete message.</description>
-</rule>
-<rule name="stop">
- <code>
- (stop)
- </code>
- <description language="en">Stop processing further rules for this message.</description>
-</rule>
-</ruleset>
-
-<ruleset type="except">
-<rule name="except-me">
- <code>
- (match-all (not (header-contains "To" ${self-email})))
- </code>
- <description language="en">When I am the recipient.</description>
-</rule>
-
-<rule name="not-body-contains">
- <code>
- (match-all (not (body-contains ${words})))
- </code>
- <description lang="en">The body does not contain <source type="string" name="words">words</source>.</description>
-</rule>
-
-</ruleset>
-
-<optionset>
- <option type="receive">
- <description language="en">When a message arrives.</description>
- </option>
- <option type="send">
- <description language="en">When a message is sent.</description>
- </option>
- <option type="receive">
- <description language="en">Copy incoming messages from a certain address to specific folder.</description>
- <optionrule type="match" rule="from-address"/>
- <optionrule type="action" rule="copy-me"/>
- </option>
- <option type="send">
- <description language="en">Copy sent messages to a specific folder.</description>
- <optionrule type="action" rule="copy-me"/>
- </option>
-</optionset>
+<partset>
+ <part name="sender">
+ <title>Sender</title>
+ <input type="optionlist" name="sender-type">
+ <option value="contains">
+ <title>contains</title>
+ <code>(match-all (header-contains "From" ${sender}))</code>
+ </option>
+ <option value="not contains">
+ <title>does not contain</title>
+ <code>(match-all (not (header-contains "From" ${sender})))</code>
+ </option>
+ </input>
+ <input type="string" name="sender"/>
+ </part>
+ <part name="to">
+ <title>Recipients</title>
+ <input type="optionlist" name="recipient-type">
+ <option value="contains">
+ <title>contains</title>
+ <code>
+ (match-all (or (header-contains "To" ${recipient})
+ (header-contains "Cc" ${recipient})))
+ </code>
+ </option>
+ <option value="not contains">
+ <title>does not contain</title>
+ <code>
+ (match-all (not (or
+ (header-contains "To" ${recipient})
+ (header-contains "Cc" ${recipient}))))
+ </code>
+ </option>
+ </input>
+ <input type="address" name="recipient"/>
+ </part>
+ <part name="subject">
+ <title>Subject</title>
+ <input type="optionlist" name="subject-type">
+ <option value="contains">
+ <title>contains</title>
+ <code>
+ (match-all (header-contains "Subject" ${subject}))
+ </code>
+ </option>
+ <option value="not contains">
+ <title>does not contain</title>
+ <code>
+ (match-all (not (header-contains "Subject" ${subject})))
+ </code>
+ </option>
+ </input>
+ <input type="string" name="subject"/>
+ </part>
+ <part name="body">
+ <title>Message Body</title>
+ <input type="optionlist" name="body-type">
+ <option value="contains">
+ <title>contains</title>
+ <code>
+ (body-contains ${word})
+ </code>
+ </option>
+ <option value="not contains">
+ <title>does not contain</title>
+ <code>
+ (not (body-contains "Subject" ${word}))
+ </code>
+ </option>
+ </input>
+ <input type="string" name="word"/>
+ </part>
+ <part name="sexp">
+ <title>Expression</title>
+ <input type="code" name="code"/>
+ </part>
+</partset>
+<actionset>
+ <part name="copy-to-folder">
+ <title>Copy to Folder</title>
+ <code>(copy-to ${folder})</code>
+ <input type="folder" name="folder"/>
+ </part>
+ <part name="forward-to">
+ <title>Forward to address</title>
+ <code>(forward-to ${address})</code>
+ <input type="address" name="address"/>
+ </part>
+ <part name="delete">
+ <title>Delete</title>
+ <code>(delete)</code>
+ </part>
+ <part name="stop">
+ <title>Stop processing</title>
+ <code>(stop)</code>
+ </part>
+ <part name="colour">
+ <title>Assign Colour</title>
+ <code>(set-colour ${colour})</code>
+ <input type="colour" name="colour"/>
+ </part>
+</actionset>
</filterdescription>
diff --git a/filter/rule-context.c b/filter/rule-context.c
new file mode 100644
index 0000000000..e6a18d078a
--- /dev/null
+++ b/filter/rule-context.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <errno.h>
+#include <gtk/gtk.h>
+#include <gnome.h>
+
+#include "rule-context.h"
+
+#define d(x) x
+
+static int load(RuleContext *f, const char *system, const char *user);
+static int save(RuleContext *f, const char *user);
+
+static void rule_context_class_init (RuleContextClass *class);
+static void rule_context_init (RuleContext *gspaper);
+static void rule_context_finalise (GtkObject *obj);
+
+#define _PRIVATE(x) (((RuleContext *)(x))->priv)
+
+struct _RuleContextPrivate {
+};
+
+static GtkObjectClass *parent_class;
+
+enum {
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+guint
+rule_context_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "RuleContext",
+ sizeof(RuleContext),
+ sizeof(RuleContextClass),
+ (GtkClassInitFunc)rule_context_class_init,
+ (GtkObjectInitFunc)rule_context_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(gtk_object_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+rule_context_class_init (RuleContextClass *class)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(gtk_object_get_type ());
+
+ object_class->finalize = rule_context_finalise;
+
+ /* override methods */
+ class->load = load;
+ class->save = save;
+
+ /* signals */
+
+ gtk_object_class_add_signals(object_class, signals, LAST_SIGNAL);
+}
+
+static void
+rule_context_init (RuleContext *o)
+{
+ o->priv = g_malloc0(sizeof(*o->priv));
+
+ o->part_set_map = g_hash_table_new(g_str_hash, g_str_equal);
+ o->rule_set_map = g_hash_table_new(g_str_hash, g_str_equal);
+}
+
+static void
+rule_context_finalise(GtkObject *obj)
+{
+ RuleContext *o = (RuleContext *)obj;
+
+ o = o;
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * rule_context_new:
+ *
+ * Create a new RuleContext object.
+ *
+ * Return value: A new #RuleContext object.
+ **/
+RuleContext *
+rule_context_new(void)
+{
+ RuleContext *o = (RuleContext *)gtk_type_new(rule_context_get_type ());
+ return o;
+}
+
+void rule_context_add_part_set(RuleContext *f, const char *setname, int part_type, RCPartFunc append, RCNextPartFunc next)
+{
+ struct _part_set_map *map;
+
+ map = g_malloc0(sizeof(*map));
+ map->type = part_type;
+ map->append = append;
+ map->next = next;
+ map->name = g_strdup(setname);
+ g_hash_table_insert(f->part_set_map, map->name, map);
+ f->part_set_list = g_list_append(f->part_set_list, map);
+ d(printf("adding part set '%s'\n", setname));
+}
+
+void rule_context_add_rule_set(RuleContext *f, const char *setname, int rule_type, RCRuleFunc append, RCNextRuleFunc next)
+{
+ struct _rule_set_map *map;
+
+ map = g_malloc0(sizeof(*map));
+ map->type = rule_type;
+ map->append = append;
+ map->next = next;
+ map->name = g_strdup(setname);
+ g_hash_table_insert(f->rule_set_map, map->name, map);
+ f->rule_set_list = g_list_append(f->rule_set_list, map);
+ d(printf("adding rule set '%s'\n", setname));
+}
+
+/**
+ * rule_context_set_error:
+ * @f:
+ * @error:
+ *
+ * Set the text error for the context, or NULL to clear it.
+ **/
+void
+rule_context_set_error(RuleContext *f, char *error)
+{
+ g_free(f->error);
+ f->error = error;
+}
+
+/**
+ * rule_context_load:
+ * @f:
+ * @system:
+ * @user:
+ *
+ * Load a rule context from a system and user description file.
+ *
+ * Return value:
+ **/
+int rule_context_load(RuleContext *f, const char *system, const char *user)
+{
+ printf("rule_context: loading %s %s\n", system, user);
+
+ return ((RuleContextClass *)((GtkObject *)f)->klass)->load(f, system, user);
+}
+
+static int load(RuleContext *f, const char *system, const char *user)
+{
+ xmlNodePtr set, rule;
+ struct _part_set_map *part_map;
+ struct _rule_set_map *rule_map;
+
+ rule_context_set_error(f, NULL);
+
+ d(printf("loading rules %s %s\n", system, user));
+
+ f->system = xmlParseFile(system);
+ if (f->system == NULL) {
+ rule_context_set_error(f, g_strdup_printf("Unable to load system rules '%s': %s",
+ system, strerror(errno)));
+ return -1;
+ }
+ if (strcmp(f->system->root->name, "filterdescription")) {
+ rule_context_set_error(f, g_strdup_printf("Unable to load system rules '%s': Invalid format",
+ system));
+ xmlFreeDoc(f->system);
+ f->system = NULL;
+ return -1;
+ }
+ f->user = xmlParseFile(user);
+ if (f->user == NULL) {
+ rule_context_set_error(f, g_strdup_printf("Unable to load user rules '%s': %s",
+ system, strerror(errno)));
+ xmlFreeDoc(f->system);
+ f->system = NULL;
+ return -1;
+ }
+
+ /* now parse structure */
+ /* get rule parts */
+ set = f->system->root->childs;
+ while (set) {
+ d(printf("set name = %s\n", set->name));
+ part_map = g_hash_table_lookup(f->part_set_map, set->name);
+ if (part_map) {
+ d(printf("loading parts ...\n"));
+ rule = set->childs;
+ while (rule) {
+ if (!strcmp(rule->name, "part")) {
+ FilterPart *part = FILTER_PART(gtk_type_new(part_map->type));
+ if (filter_part_xml_create(part, rule) == 0) {
+ part_map->append(f, part);
+ } else {
+ gtk_object_unref((GtkObject *)part);
+ g_warning("Cannot load filter part");
+ }
+ }
+ rule = rule->next;
+ }
+ }
+ set = set->next;
+ }
+
+ /* now load actual rules */
+ set = f->user->root->childs;
+ while (set) {
+ d(printf("set name = %s\n", set->name));
+ rule_map = g_hash_table_lookup(f->rule_set_map, set->name);
+ if (rule_map) {
+ d(printf("loading rules ...\n"));
+ rule = set->childs;
+ while (rule) {
+ printf("checking node: %s\n", rule->name);
+ if (!strcmp(rule->name, "rule")) {
+ FilterRule *part = FILTER_RULE(gtk_type_new(rule_map->type));
+ if (filter_rule_xml_decode(part, rule, f) == 0) {
+ rule_map->append(f, part);
+ } else {
+ gtk_object_unref((GtkObject *)part);
+ g_warning("Cannot load filter part");
+ }
+ }
+ rule = rule->next;
+ }
+ }
+ set = set->next;
+ }
+ return 0;
+}
+
+/**
+ * rule_context_save:
+ * @f:
+ * @user:
+ *
+ * Save a rule context to disk.
+ *
+ * Return value:
+ **/
+int rule_context_save(RuleContext *f, const char *user)
+{
+ return ((RuleContextClass *)((GtkObject *)f)->klass)->save(f, user);
+}
+
+static int save(RuleContext *f, const char *user)
+{
+ xmlDocPtr doc;
+ xmlNodePtr root, rules, work;
+ GList *l;
+ FilterRule *rule;
+ struct _rule_set_map *map;
+
+ doc = xmlNewDoc("1.0");
+ root = xmlNewDocNode(doc, NULL, "filteroptions", NULL);
+ xmlDocSetRootElement(doc, root);
+ l = f->rule_set_list;
+ while (l) {
+ map = l->data;
+ rules = xmlNewDocNode(doc, NULL, map->name, NULL);
+ xmlAddChild(root, rules);
+ rule = NULL;
+ while ( (rule = map->next(f, rule)) ) {
+ d(printf("processing rule %s\n", rule->name));
+ work = filter_rule_xml_encode(rule);
+ xmlAddChild(rules, work);
+ }
+ l = g_list_next(l);
+ }
+ xmlSaveFile(user, doc);
+ xmlFreeDoc(doc);
+ return 0;
+}
+
+FilterPart *rule_context_find_part(RuleContext *f, char *name)
+{
+ d(printf("find part : "));
+ return filter_part_find_list(f->parts, name);
+}
+
+FilterPart *rule_context_next_part(RuleContext *f, FilterPart *last)
+{
+ return filter_part_next_list(f->parts, last);
+}
+
+FilterRule *rule_context_next_rule(RuleContext *f, FilterRule *last)
+{
+ return filter_rule_next_list(f->rules, last);
+}
+
+void rule_context_add_part(RuleContext *f, FilterPart *part)
+{
+ f->parts = g_list_append(f->parts, part);
+}
+
+void rule_context_add_rule(RuleContext *f, FilterRule *new)
+{
+ f->rules = g_list_append(f->rules, new);
+}
+
+void rule_context_remove_rule(RuleContext *f, FilterRule *rule)
+{
+ f->rules = g_list_remove(f->rules, rule);
+}
+
+void rule_context_rank_rule(RuleContext *f, FilterRule *rule, int rank)
+{
+ f->rules = g_list_remove(f->rules, rule);
+ f->rules = g_list_insert(f->rules, rule, rank);
+}
+
+int rule_context_get_rank_rule(RuleContext *f, FilterRule *rule)
+{
+ return g_list_index(f->rules, rule);
+}
diff --git a/filter/rule-context.h b/filter/rule-context.h
new file mode 100644
index 0000000000..f2b59cd3c0
--- /dev/null
+++ b/filter/rule-context.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 _RULE_CONTEXT_H
+#define _RULE_CONTEXT_H
+
+#include <gtk/gtk.h>
+#include <gnome-xml/parser.h>
+
+#include "filter-part.h"
+#include "filter-rule.h"
+
+#define RULE_CONTEXT(obj) GTK_CHECK_CAST (obj, rule_context_get_type (), RuleContext)
+#define RULE_CONTEXT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, rule_context_get_type (), RuleContextClass)
+#define IS_RULE_CONTEXT(obj) GTK_CHECK_TYPE (obj, rule_context_get_type ())
+
+typedef struct _RuleContext RuleContext;
+typedef struct _RuleContextClass RuleContextClass;
+
+struct _RuleContext {
+ GtkObject parent;
+ struct _RuleContextPrivate *priv;
+
+ char *error; /* string version of error */
+
+ xmlDocPtr system; /* system rules source */
+ xmlDocPtr user; /* user defined rules source */
+
+ GList *parts;
+ GList *rules;
+
+ GHashTable *part_set_map;/* map set types to part types */
+ GList *part_set_list;
+ GHashTable *rule_set_map;/* map set types to rule types */
+ GList *rule_set_list;
+};
+
+struct _RuleContextClass {
+ GtkObjectClass parent_class;
+
+ /* virtual methods */
+ int (*load)(RuleContext *f, const char *system, const char *user);
+ int (*save)(RuleContext *f, const char *user);
+
+ /* signals */
+};
+
+typedef void (*RCPartFunc)(RuleContext *f, FilterPart *part);
+typedef void (*RCRuleFunc)(RuleContext *f, FilterRule *part);
+typedef FilterPart * (*RCNextPartFunc)(RuleContext *f, FilterPart *part);
+typedef FilterRule * (*RCNextRuleFunc)(RuleContext *f, FilterRule *rule);
+
+struct _part_set_map {
+ char *name;
+ int type;
+ RCPartFunc append;
+ RCNextPartFunc next;
+};
+
+struct _rule_set_map {
+ char *name;
+ int type;
+ RCRuleFunc append;
+ RCNextRuleFunc next;
+};
+
+guint rule_context_get_type (void);
+RuleContext *rule_context_new (void);
+
+/* methods */
+int rule_context_load(RuleContext *f, const char *system, const char *user);
+int rule_context_save(RuleContext *f, const char *user);
+
+void rule_context_add_part(RuleContext *f, FilterPart *new);
+FilterPart *rule_context_find_part(RuleContext *f, char *name);
+/*FilterPart *rule_context_create_part(RuleContext *f, char *name);*/
+FilterPart *rule_context_next_part(RuleContext *f, FilterPart *last);
+
+FilterRule *rule_context_next_rule(RuleContext *f, FilterRule *last);
+void rule_context_add_rule(RuleContext *f, FilterRule *new);
+void rule_context_remove_rule(RuleContext *f, FilterRule *rule);
+
+/* get/set the rank (position) of a rule */
+void rule_context_rank_rule(RuleContext *f, FilterRule *rule, int rank);
+int rule_context_get_rank_rule(RuleContext *f, FilterRule *rule);
+
+void rule_context_delete_rule(RuleContext *f, FilterRule *rule);
+
+/* setup type for set parts */
+void rule_context_add_part_set(RuleContext *f, const char *setname, int part_type, RCPartFunc append, RCNextPartFunc next);
+void rule_context_add_rule_set(RuleContext *f, const char *setname, int rule_type, RCRuleFunc append, RCNextRuleFunc next);
+
+#endif /* ! _RULE_CONTEXT_H */
+
diff --git a/filter/score-context.c b/filter/score-context.c
new file mode 100644
index 0000000000..a171bd1240
--- /dev/null
+++ b/filter/score-context.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+
+#include "score-context.h"
+#include "score-rule.h"
+
+static void score_context_class_init (ScoreContextClass *class);
+static void score_context_init (ScoreContext *gspaper);
+static void score_context_finalise (GtkObject *obj);
+
+static RuleContextClass *parent_class;
+
+guint
+score_context_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "ScoreContext",
+ sizeof(ScoreContext),
+ sizeof(ScoreContextClass),
+ (GtkClassInitFunc)score_context_class_init,
+ (GtkObjectInitFunc)score_context_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(rule_context_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+score_context_class_init (ScoreContextClass *class)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(rule_context_get_type ());
+
+ object_class->finalize = score_context_finalise;
+ /* override methods */
+
+}
+
+static void
+score_context_init (ScoreContext *o)
+{
+ rule_context_add_part_set((RuleContext *)o, "partset", filter_part_get_type(),
+ rule_context_add_part, rule_context_next_part);
+
+ rule_context_add_rule_set((RuleContext *)o, "ruleset", score_rule_get_type(),
+ rule_context_add_rule, rule_context_next_rule);
+}
+
+static void
+score_context_finalise(GtkObject *obj)
+{
+ ScoreContext *o = (ScoreContext *)obj;
+
+ o = o;
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * score_context_new:
+ *
+ * Create a new ScoreContext object.
+ *
+ * Return value: A new #ScoreContext object.
+ **/
+ScoreContext *
+score_context_new(void)
+{
+ ScoreContext *o = (ScoreContext *)gtk_type_new(score_context_get_type ());
+ return o;
+}
diff --git a/filter/score-context.h b/filter/score-context.h
new file mode 100644
index 0000000000..b89f70c1f8
--- /dev/null
+++ b/filter/score-context.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 _SCORE_CONTEXT_H
+#define _SCORE_CONTEXT_H
+
+#include <gtk/gtk.h>
+
+#include "rule-context.h"
+
+#define SCORE_CONTEXT(obj) GTK_CHECK_CAST (obj, score_context_get_type (), ScoreContext)
+#define SCORE_CONTEXT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, score_context_get_type (), ScoreContextClass)
+#define IS_SCORE_CONTEXT(obj) GTK_CHECK_TYPE (obj, score_context_get_type ())
+
+typedef struct _ScoreContext ScoreContext;
+typedef struct _ScoreContextClass ScoreContextClass;
+
+struct _ScoreContext {
+ RuleContext parent;
+};
+
+struct _ScoreContextClass {
+ RuleContextClass parent_class;
+
+ /* virtual methods */
+
+ /* signals */
+};
+
+guint score_context_get_type (void);
+ScoreContext *score_context_new (void);
+
+/* methods */
+
+#endif /* ! _SCORE_CONTEXT_H */
+
diff --git a/filter/score-editor.c b/filter/score-editor.c
new file mode 100644
index 0000000000..20c5ba78de
--- /dev/null
+++ b/filter/score-editor.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+#include <glade/glade.h>
+
+#include "score-editor.h"
+#include "score-context.h"
+#include "score-rule.h"
+
+#define d(x)
+
+#if 0
+static void score_editor_class_init (ScoreEditorClass *class);
+static void score_editor_init (ScoreEditor *gspaper);
+
+static GnomeDialogClass *parent_class;
+
+guint
+score_editor_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "ScoreEditor",
+ sizeof(ScoreEditor),
+ sizeof(ScoreEditorClass),
+ (GtkClassInitFunc)score_editor_class_init,
+ (GtkObjectInitFunc)score_editor_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(gnome_dialog_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+score_editor_class_init (ScoreEditorClass *class)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(gnome_dialog_get_type ());
+
+ /* override methods */
+
+}
+
+static void
+score_editor_init (ScoreEditor *o)
+{
+}
+
+/**
+ * score_editor_new:
+ *
+ * Create a new ScoreEditor object.
+ *
+ * Return value: A new #ScoreEditor object.
+ **/
+ScoreEditor *
+score_editor_new(void)
+{
+ ScoreEditor *o = (ScoreEditor *)gtk_type_new(score_editor_get_type ());
+ return o;
+}
+#endif
+
+
+enum {
+ BUTTON_ADD,
+ BUTTON_EDIT,
+ BUTTON_DELETE,
+ BUTTON_UP,
+ BUTTON_DOWN,
+ BUTTON_LAST
+};
+
+struct _editor_data {
+ RuleContext *f;
+ FilterRule *current;
+ GtkList *list;
+ GtkButton *buttons[BUTTON_LAST];
+};
+
+static void set_sensitive(struct _editor_data *data);
+
+static void rule_add(GtkWidget *widget, struct _editor_data *data)
+{
+ ScoreRule *rule;
+ int result;
+ GnomeDialog *gd;
+ GtkWidget *w;
+ FilterPart *part;
+
+ d(printf("add rule\n"));
+ /* create a new rule with 1 match and 1 action */
+ rule = score_rule_new();
+
+ part = rule_context_next_part(data->f, NULL);
+ filter_rule_add_part((FilterRule *)rule, filter_part_clone(part));
+
+ w = filter_rule_get_widget((FilterRule *)rule, data->f);
+ gd = (GnomeDialog *)gnome_dialog_new("Add Rule", "Ok", "Cancel", NULL);
+ gtk_box_pack_start((GtkBox *)gd->vbox, w, FALSE, TRUE, 0);
+ gtk_widget_show((GtkWidget *)gd);
+ result = gnome_dialog_run_and_close(gd);
+ if (result == 0) {
+ GtkListItem *item = (GtkListItem *)gtk_list_item_new_with_label(((FilterRule *)rule)->name);
+ GList *l = NULL;
+
+ gtk_object_set_data((GtkObject *)item, "rule", rule);
+ gtk_widget_show((GtkWidget *)item);
+ l = g_list_append(l, item);
+ gtk_list_append_items(data->list, l);
+ gtk_list_select_child(data->list, (GtkWidget *)item);
+ data->current = (FilterRule *)rule;
+ rule_context_add_rule(data->f, (FilterRule *)rule);
+ set_sensitive(data);
+ } else {
+ gtk_object_unref((GtkObject *)rule);
+ }
+}
+
+static void rule_edit(GtkWidget *widget, struct _editor_data *data)
+{
+ GtkWidget *w;
+ int result;
+ GnomeDialog *gd;
+ FilterRule *rule;
+ int pos;
+
+ d(printf("edit rule\n"));
+ rule = data->current;
+ w = filter_rule_get_widget(rule, data->f);
+ gd = (GnomeDialog *)gnome_dialog_new("Edit Score Rule", "Ok", NULL);
+ gtk_box_pack_start((GtkBox *)gd->vbox, w, FALSE, TRUE, 0);
+ gtk_widget_show((GtkWidget *)gd);
+ result = gnome_dialog_run_and_close(gd);
+
+ if (result == 0) {
+ pos = rule_context_get_rank_rule(data->f, data->current);
+ if (pos != -1) {
+ GtkListItem *item = g_list_nth_data(data->list->children, pos);
+ gtk_label_set_text((GtkLabel *)(((GtkBin *)item)->child), data->current->name);
+ }
+ }
+}
+
+static void rule_delete(GtkWidget *widget, struct _editor_data *data)
+{
+ int pos;
+ GList *l;
+ GtkListItem *item;
+
+ d(printf("ddelete rule\n"));
+ pos = rule_context_get_rank_rule(data->f, data->current);
+ if (pos != -1) {
+ rule_context_remove_rule(data->f, data->current);
+
+ item = g_list_nth_data(data->list->children, pos);
+ l = g_list_append(NULL, item);
+ gtk_list_remove_items(data->list, l);
+ g_list_free(l);
+
+ gtk_object_unref((GtkObject *)data->current);
+ data->current = NULL;
+ }
+ set_sensitive(data);
+}
+
+static void rule_move(struct _editor_data *data, int from, int to)
+{
+ GList *l;
+ GtkListItem *item;
+
+ d(printf("moving %d to %d\n", from, to));
+ rule_context_rank_rule(data->f, data->current, to);
+
+ item = g_list_nth_data(data->list->children, from);
+ l = g_list_append(NULL, item);
+ gtk_list_remove_items_no_unref(data->list, l);
+ gtk_list_insert_items(data->list, l, to);
+ gtk_list_select_child(data->list, (GtkWidget *)item);
+ set_sensitive(data);
+}
+
+static void rule_up(GtkWidget *widget, struct _editor_data *data)
+{
+ int pos;
+
+ d(printf("up rule\n"));
+ pos = rule_context_get_rank_rule(data->f, data->current);
+ if (pos>0) {
+ rule_move(data, pos, pos-1);
+ }
+}
+
+static void rule_down(GtkWidget *widget, struct _editor_data *data)
+{
+ int pos;
+
+ d(printf("down rule\n"));
+ pos = rule_context_get_rank_rule(data->f, data->current);
+ rule_move(data, pos, pos+1);
+}
+
+static struct {
+ char *name;
+ GtkSignalFunc func;
+} edit_buttons[] = {
+ { "rule_add", rule_add },
+ { "rule_edit", rule_edit },
+ { "rule_delete", rule_delete },
+ { "rule_up", rule_up },
+ { "rule_down", rule_down },
+};
+
+static void
+set_sensitive(struct _editor_data *data)
+{
+ FilterRule *rule = NULL;
+ int index=-1, count=0;
+
+ while ((rule = rule_context_next_rule(data->f, rule))) {
+ if (rule == data->current)
+ index=count;
+ count++;
+ }
+ d(printf("index = %d count=%d\n", index, count));
+ count--;
+ gtk_widget_set_sensitive((GtkWidget *)data->buttons[BUTTON_EDIT], index != -1);
+ gtk_widget_set_sensitive((GtkWidget *)data->buttons[BUTTON_DELETE], index != -1);
+ gtk_widget_set_sensitive((GtkWidget *)data->buttons[BUTTON_UP], index > 0);
+ gtk_widget_set_sensitive((GtkWidget *)data->buttons[BUTTON_DOWN], index >=0 && index<count);
+}
+
+static void
+select_rule(GtkWidget *w, GtkWidget *child, struct _editor_data *data)
+{
+ data->current = gtk_object_get_data((GtkObject *)child, "rule");
+ if (data->current)
+ d(printf("seledct rule: %s\n", data->current->name));
+ else
+ d(printf("bad data?\n"));
+ set_sensitive(data);
+}
+
+GtkWidget *score_editor_construct (struct _ScoreContext *f)
+{
+ GladeXML *gui;
+ GtkWidget *d, *w;
+ GList *l;
+ FilterRule *rule = NULL;
+ struct _editor_data *data;
+ int i;
+
+ g_assert(IS_SCORE_CONTEXT(f));
+
+ data = g_malloc0(sizeof(*data));
+ data->f = (RuleContext *)f;
+
+ gui = glade_xml_new(FILTER_GLADEDIR "/filter.glade", "edit_vfolder");
+ d = glade_xml_get_widget (gui, "edit_vfolder");
+ gtk_object_set_data_full((GtkObject *)d, "data", data, g_free);
+
+ gtk_window_set_title((GtkWindow *)d, "Edit Score List");
+ for (i=0;i<BUTTON_LAST;i++) {
+ data->buttons[i] = (GtkButton *)w = glade_xml_get_widget (gui, edit_buttons[i].name);
+ gtk_signal_connect((GtkObject *)w, "clicked", edit_buttons[i].func, data);
+ }
+
+ w = glade_xml_get_widget (gui, "rule_list");
+ data->list = (GtkList *)w;
+ l = NULL;
+ while ((rule = rule_context_next_rule((RuleContext *)f, rule))) {
+ GtkListItem *item = (GtkListItem *)gtk_list_item_new_with_label(rule->name);
+ gtk_object_set_data((GtkObject *)item, "rule", rule);
+ gtk_widget_show((GtkWidget *)item);
+ l = g_list_append(l, item);
+ }
+ gtk_list_append_items(data->list, l);
+ gtk_signal_connect((GtkObject *)w, "select_child", select_rule, data);
+
+ set_sensitive(data);
+ gtk_object_unref((GtkObject *)gui);
+
+ return d;
+}
diff --git a/filter/score-editor.h b/filter/score-editor.h
new file mode 100644
index 0000000000..cb78d465f0
--- /dev/null
+++ b/filter/score-editor.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 _SCORE_EDITOR_H
+#define _SCORE_EDITOR_H
+
+#include <gtk/gtk.h>
+#include <libgnomeui/gnome-dialog.h>
+
+#if 0
+/* NOTE: object stuff not used (yet?), this is just a holder file for a static factory */
+
+#define SCORE_EDITOR(obj) GTK_CHECK_CAST (obj, score_editor_get_type (), ScoreEditor)
+#define SCORE_EDITOR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, score_editor_get_type (), ScoreEditorClass)
+#define IS_SCORE_EDITOR(obj) GTK_CHECK_TYPE (obj, score_editor_get_type ())
+
+typedef struct _ScoreEditor ScoreEditor;
+typedef struct _ScoreEditorClass ScoreEditorClass;
+
+struct _ScoreEditor {
+ GnomeDialog parent;
+};
+
+struct _ScoreEditorClass {
+ GnomeDialogClass parent_class;
+
+ /* virtual methods */
+
+ /* signals */
+};
+
+guint score_editor_get_type (void);
+ScoreEditor *score_editor_new (void);
+#endif
+
+struct _ScoreContext;
+
+/* methods */
+GtkWidget *score_editor_construct (struct _ScoreContext *f);
+
+#endif /* ! _SCORE_EDITOR_H */
+
diff --git a/filter/score-rule.c b/filter/score-rule.c
new file mode 100644
index 0000000000..8eb51b6821
--- /dev/null
+++ b/filter/score-rule.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+
+#include "score-rule.h"
+
+static xmlNodePtr xml_encode(FilterRule *);
+static int xml_decode(FilterRule *, xmlNodePtr, struct _RuleContext *f);
+/*static void build_code(FilterRule *, GString *out);*/
+static GtkWidget *get_widget(FilterRule *fr, struct _RuleContext *f);
+
+static void score_rule_class_init (ScoreRuleClass *class);
+static void score_rule_init (ScoreRule *gspaper);
+static void score_rule_finalise (GtkObject *obj);
+
+#define _PRIVATE(x) (((ScoreRule *)(x))->priv)
+
+struct _ScoreRulePrivate {
+};
+
+static FilterRuleClass *parent_class;
+
+enum {
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+guint
+score_rule_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "ScoreRule",
+ sizeof(ScoreRule),
+ sizeof(ScoreRuleClass),
+ (GtkClassInitFunc)score_rule_class_init,
+ (GtkObjectInitFunc)score_rule_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(filter_rule_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+score_rule_class_init (ScoreRuleClass *class)
+{
+ GtkObjectClass *object_class;
+ FilterRuleClass *rule_class = (FilterRuleClass *)class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(filter_rule_get_type ());
+
+ object_class->finalize = score_rule_finalise;
+
+ /* override methods */
+ rule_class->xml_encode = xml_encode;
+ rule_class->xml_decode = xml_decode;
+/* rule_class->build_code = build_code;*/
+ rule_class->get_widget = get_widget;
+
+ /* signals */
+
+ gtk_object_class_add_signals(object_class, signals, LAST_SIGNAL);
+}
+
+static void
+score_rule_init (ScoreRule *o)
+{
+ o->priv = g_malloc0(sizeof(*o->priv));
+}
+
+static void
+score_rule_finalise(GtkObject *obj)
+{
+ ScoreRule *o = (ScoreRule *)obj;
+
+ o = o;
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * score_rule_new:
+ *
+ * Create a new ScoreRule object.
+ *
+ * Return value: A new #ScoreRule object.
+ **/
+ScoreRule *
+score_rule_new(void)
+{
+ ScoreRule *o = (ScoreRule *)gtk_type_new(score_rule_get_type ());
+ return o;
+}
+
+static xmlNodePtr xml_encode(FilterRule *fr)
+{
+ ScoreRule *sr = (ScoreRule *)fr;
+ xmlNodePtr node, value;
+ char number[16];
+
+ node = ((FilterRuleClass *)(parent_class))->xml_encode(fr);
+ sprintf(number, "%d", sr->score);
+ value = xmlNewNode(NULL, "score");
+ xmlSetProp(value, "value", number);
+ xmlAddChild(node, value);
+ return node;
+}
+
+static int xml_decode(FilterRule *fr, xmlNodePtr node, struct _RuleContext *f)
+{
+ ScoreRule *sr = (ScoreRule *)fr;
+ xmlNodePtr value;
+ int result;
+ char *str;
+
+ result = ((FilterRuleClass *)(parent_class))->xml_decode(fr, node, f);
+ if (result != 0)
+ return result;
+ value = node->childs;
+ while (value) {
+ if (!strcmp(value->name, "score")) {
+ str = xmlGetProp(value, "value");
+ sscanf(str, "%d", &sr->score);
+ }
+ value = value->next;
+ }
+ return 0;
+}
+
+/*static void build_code(FilterRule *fr, GString *out)
+{
+}*/
+
+static void spin_changed(GtkAdjustment *adj, ScoreRule *sr)
+{
+ sr->score = adj->value;
+}
+
+static GtkWidget *get_widget(FilterRule *fr, struct _RuleContext *f)
+{
+ GtkWidget *widget;
+ GtkFrame *frame;
+ GtkLabel *label;
+ GtkHBox *hbox;
+ GtkAdjustment *adj;
+ ScoreRule *sr = (ScoreRule *)fr;
+ GtkSpinButton *spin;
+
+ widget = ((FilterRuleClass *)(parent_class))->get_widget(fr, f);
+ frame = (GtkFrame *)gtk_frame_new("Score");
+ hbox = (GtkHBox *)gtk_hbox_new(FALSE, 3);
+ label = (GtkLabel *)gtk_label_new("Score");
+ gtk_box_pack_start((GtkBox *)hbox, (GtkWidget *)label, FALSE, FALSE, 3);
+ adj = (GtkAdjustment *)gtk_adjustment_new((float)sr->score, -100, 100, 1, 10, 10);
+ gtk_signal_connect((GtkObject *)adj, "value_changed", spin_changed, sr);
+ spin = (GtkSpinButton *)gtk_spin_button_new(adj, 1.0, 0);
+ gtk_box_pack_start((GtkBox *)hbox, (GtkWidget *)spin, FALSE, FALSE, 3);
+ gtk_container_add((GtkContainer *)frame, (GtkWidget *)hbox);
+ gtk_widget_show_all((GtkWidget *)frame);
+
+ gtk_box_pack_start((GtkBox *)widget, (GtkWidget *)frame, FALSE, FALSE, 3);
+ return widget;
+}
diff --git a/filter/score-rule.h b/filter/score-rule.h
new file mode 100644
index 0000000000..25607fd7c4
--- /dev/null
+++ b/filter/score-rule.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 _SCORE_RULE_H
+#define _SCORE_RULE_H
+
+#include <gtk/gtk.h>
+
+#include "filter-rule.h"
+
+#define SCORE_RULE(obj) GTK_CHECK_CAST (obj, score_rule_get_type (), ScoreRule)
+#define SCORE_RULE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, score_rule_get_type (), ScoreRuleClass)
+#define IS_SCORE_RULE(obj) GTK_CHECK_TYPE (obj, score_rule_get_type ())
+
+typedef struct _ScoreRule ScoreRule;
+typedef struct _ScoreRuleClass ScoreRuleClass;
+
+struct _ScoreRule {
+ FilterRule parent;
+ struct _ScoreRulePrivate *priv;
+
+ int score;
+};
+
+struct _ScoreRuleClass {
+ FilterRuleClass parent_class;
+
+ /* virtual methods */
+
+ /* signals */
+};
+
+guint score_rule_get_type (void);
+ScoreRule *score_rule_new (void);
+
+/* methods */
+
+#endif /* ! _SCORE_RULE_H */
+
diff --git a/filter/vfolder-context.c b/filter/vfolder-context.c
new file mode 100644
index 0000000000..0202c71847
--- /dev/null
+++ b/filter/vfolder-context.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+
+#include "vfolder-context.h"
+
+static void vfolder_context_class_init (VfolderContextClass *class);
+static void vfolder_context_init (VfolderContext *gspaper);
+static void vfolder_context_finalise (GtkObject *obj);
+
+#define _PRIVATE(x) (((VfolderContext *)(x))->priv)
+
+struct _VfolderContextPrivate {
+};
+
+static RuleContextClass *parent_class;
+
+enum {
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+guint
+vfolder_context_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "VfolderContext",
+ sizeof(VfolderContext),
+ sizeof(VfolderContextClass),
+ (GtkClassInitFunc)vfolder_context_class_init,
+ (GtkObjectInitFunc)vfolder_context_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(rule_context_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+vfolder_context_class_init (VfolderContextClass *class)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(rule_context_get_type ());
+
+ object_class->finalize = vfolder_context_finalise;
+ /* override methods */
+
+ /* signals */
+
+ gtk_object_class_add_signals(object_class, signals, LAST_SIGNAL);
+}
+
+static void
+vfolder_context_init (VfolderContext *o)
+{
+ o->priv = g_malloc0(sizeof(*o->priv));
+
+ rule_context_add_part_set((RuleContext *)o, "partset", filter_part_get_type(),
+ rule_context_add_part, rule_context_next_part);
+
+ rule_context_add_rule_set((RuleContext *)o, "ruleset", filter_rule_get_type(),
+ rule_context_add_rule, rule_context_next_rule);
+}
+
+static void
+vfolder_context_finalise(GtkObject *obj)
+{
+ VfolderContext *o = (VfolderContext *)obj;
+
+ o = o;
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * vfolder_context_new:
+ *
+ * Create a new VfolderContext object.
+ *
+ * Return value: A new #VfolderContext object.
+ **/
+VfolderContext *
+vfolder_context_new(void)
+{
+ VfolderContext *o = (VfolderContext *)gtk_type_new(vfolder_context_get_type ());
+ return o;
+}
diff --git a/filter/vfolder-context.h b/filter/vfolder-context.h
new file mode 100644
index 0000000000..0bf1b5aaf2
--- /dev/null
+++ b/filter/vfolder-context.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 _VFOLDER_CONTEXT_H
+#define _VFOLDER_CONTEXT_H
+
+#include <gtk/gtk.h>
+
+#include "rule-context.h"
+
+#define VFOLDER_CONTEXT(obj) GTK_CHECK_CAST (obj, vfolder_context_get_type (), VfolderContext)
+#define VFOLDER_CONTEXT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, vfolder_context_get_type (), VfolderContextClass)
+#define IS_VFOLDER_CONTEXT(obj) GTK_CHECK_TYPE (obj, vfolder_context_get_type ())
+
+typedef struct _VfolderContext VfolderContext;
+typedef struct _VfolderContextClass VfolderContextClass;
+
+struct _VfolderContext {
+ RuleContext parent;
+ struct _VfolderContextPrivate *priv;
+
+};
+
+struct _VfolderContextClass {
+ RuleContextClass parent_class;
+
+ /* virtual methods */
+
+ /* signals */
+};
+
+guint vfolder_context_get_type (void);
+VfolderContext *vfolder_context_new (void);
+
+/* methods */
+
+#endif /* ! _VFOLDER_CONTEXT_H */
+
diff --git a/filter/vfolder-editor.c b/filter/vfolder-editor.c
new file mode 100644
index 0000000000..90da3c5221
--- /dev/null
+++ b/filter/vfolder-editor.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 <gtk/gtk.h>
+#include <gnome.h>
+#include <glade/glade.h>
+
+#include "vfolder-editor.h"
+#include "vfolder-context.h"
+
+#define d(x)
+
+#if 0
+static void vfolder_editor_class_init (VfolderEditorClass *class);
+static void vfolder_editor_init (VfolderEditor *gspaper);
+static void vfolder_editor_finalise (GtkObject *obj);
+
+#define _PRIVATE(x) (((VfolderEditor *)(x))->priv)
+
+struct _VfolderEditorPrivate {
+};
+
+static GnomeDialogClass *parent_class;
+
+enum {
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+guint
+vfolder_editor_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "VfolderEditor",
+ sizeof(VfolderEditor),
+ sizeof(VfolderEditorClass),
+ (GtkClassInitFunc)vfolder_editor_class_init,
+ (GtkObjectInitFunc)vfolder_editor_init,
+ (GtkArgSetFunc)NULL,
+ (GtkArgGetFunc)NULL
+ };
+
+ type = gtk_type_unique(gnome_dialog_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+vfolder_editor_class_init (VfolderEditorClass *class)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *)class;
+ parent_class = gtk_type_class(gnome_dialog_get_type ());
+
+ object_class->finalize = vfolder_editor_finalise;
+ /* override methods */
+
+ /* signals */
+
+ gtk_object_class_add_signals(object_class, signals, LAST_SIGNAL);
+}
+
+static void
+vfolder_editor_init (VfolderEditor *o)
+{
+ o->priv = g_malloc0(sizeof(*o->priv));
+}
+
+static void
+vfolder_editor_finalise(GtkObject *obj)
+{
+ VfolderEditor *o = (VfolderEditor *)obj;
+
+ ((GtkObjectClass *)(parent_class))->finalize(obj);
+}
+
+/**
+ * vfolder_editor_new:
+ *
+ * Create a new VfolderEditor object.
+ *
+ * Return value: A new #VfolderEditor object.
+ **/
+VfolderEditor *
+vfolder_editor_new(void)
+{
+ VfolderEditor *o = (VfolderEditor *)gtk_type_new(vfolder_editor_get_type ());
+ return o;
+}
+#endif
+
+
+
+enum {
+ BUTTON_ADD,
+ BUTTON_EDIT,
+ BUTTON_DELETE,
+ BUTTON_UP,
+ BUTTON_DOWN,
+ BUTTON_LAST
+};
+
+struct _editor_data {
+ RuleContext *f;
+ FilterRule *current;
+ GtkList *list;
+ GtkButton *buttons[BUTTON_LAST];
+};
+
+static void set_sensitive(struct _editor_data *data);
+
+static void rule_add(GtkWidget *widget, struct _editor_data *data)
+{
+ FilterRule *rule;
+ int result;
+ GnomeDialog *gd;
+ GtkWidget *w;
+ FilterPart *part;
+
+ d(printf("add rule\n"));
+ /* create a new rule with 1 match and 1 action */
+ rule = filter_rule_new();
+
+ part = rule_context_next_part(data->f, NULL);
+ filter_rule_add_part(rule, filter_part_clone(part));
+
+ w = filter_rule_get_widget(rule, data->f);
+ gd = (GnomeDialog *)gnome_dialog_new("Add Rule", "Ok", "Cancel", NULL);
+ gtk_box_pack_start((GtkBox *)gd->vbox, w, FALSE, TRUE, 0);
+ gtk_widget_show((GtkWidget *)gd);
+ result = gnome_dialog_run_and_close(gd);
+ if (result == 0) {
+ GtkListItem *item = (GtkListItem *)gtk_list_item_new_with_label(rule->name);
+ GList *l = NULL;
+
+ gtk_object_set_data((GtkObject *)item, "rule", rule);
+ gtk_widget_show((GtkWidget *)item);
+ l = g_list_append(l, item);
+ gtk_list_append_items(data->list, l);
+ gtk_list_select_child(data->list, (GtkWidget *)item);
+ data->current = rule;
+ rule_context_add_rule(data->f, rule);
+ set_sensitive(data);
+ } else {
+ gtk_object_unref((GtkObject *)rule);
+ }
+}
+
+static void rule_edit(GtkWidget *widget, struct _editor_data *data)
+{
+ GtkWidget *w;
+ int result;
+ GnomeDialog *gd;
+ FilterRule *rule;
+ int pos;
+
+ d(printf("edit rule\n"));
+ rule = data->current;
+ w = filter_rule_get_widget(rule, data->f);
+ gd = (GnomeDialog *)gnome_dialog_new("Edit VFolder Rule", "Ok", NULL);
+ gtk_box_pack_start((GtkBox *)gd->vbox, w, FALSE, TRUE, 0);
+ gtk_widget_show((GtkWidget *)gd);
+ result = gnome_dialog_run_and_close(gd);
+
+ if (result == 0) {
+ pos = rule_context_get_rank_rule(data->f, data->current);
+ if (pos != -1) {
+ GtkListItem *item = g_list_nth_data(data->list->children, pos);
+ gtk_label_set_text((GtkLabel *)(((GtkBin *)item)->child), data->current->name);
+ }
+ }
+}
+
+static void rule_delete(GtkWidget *widget, struct _editor_data *data)
+{
+ int pos;
+ GList *l;
+ GtkListItem *item;
+
+ d(printf("ddelete rule\n"));
+ pos = rule_context_get_rank_rule(data->f, data->current);
+ if (pos != -1) {
+ rule_context_remove_rule(data->f, data->current);
+
+ item = g_list_nth_data(data->list->children, pos);
+ l = g_list_append(NULL, item);
+ gtk_list_remove_items(data->list, l);
+ g_list_free(l);
+
+ gtk_object_unref((GtkObject *)data->current);
+ data->current = NULL;
+ }
+ set_sensitive(data);
+}
+
+static void rule_move(struct _editor_data *data, int from, int to)
+{
+ GList *l;
+ GtkListItem *item;
+
+ d(printf("moving %d to %d\n", from, to));
+ rule_context_rank_rule(data->f, data->current, to);
+
+ item = g_list_nth_data(data->list->children, from);
+ l = g_list_append(NULL, item);
+ gtk_list_remove_items_no_unref(data->list, l);
+ gtk_list_insert_items(data->list, l, to);
+ gtk_list_select_child(data->list, (GtkWidget *)item);
+ set_sensitive(data);
+}
+
+static void rule_up(GtkWidget *widget, struct _editor_data *data)
+{
+ int pos;
+
+ d(printf("up rule\n"));
+ pos = rule_context_get_rank_rule(data->f, data->current);
+ if (pos>0) {
+ rule_move(data, pos, pos-1);
+ }
+}
+
+static void rule_down(GtkWidget *widget, struct _editor_data *data)
+{
+ int pos;
+
+ d(printf("down rule\n"));
+ pos = rule_context_get_rank_rule(data->f, data->current);
+ rule_move(data, pos, pos+1);
+}
+
+static struct {
+ char *name;
+ GtkSignalFunc func;
+} edit_buttons[] = {
+ { "rule_add", rule_add },
+ { "rule_edit", rule_edit },
+ { "rule_delete", rule_delete },
+ { "rule_up", rule_up },
+ { "rule_down", rule_down },
+};
+
+static void
+set_sensitive(struct _editor_data *data)
+{
+ FilterRule *rule = NULL;
+ int index=-1, count=0;
+
+ while ((rule = rule_context_next_rule(data->f, rule))) {
+ if (rule == data->current)
+ index=count;
+ count++;
+ }
+ d(printf("index = %d count=%d\n", index, count));
+ count--;
+ gtk_widget_set_sensitive((GtkWidget *)data->buttons[BUTTON_EDIT], index != -1);
+ gtk_widget_set_sensitive((GtkWidget *)data->buttons[BUTTON_DELETE], index != -1);
+ gtk_widget_set_sensitive((GtkWidget *)data->buttons[BUTTON_UP], index > 0);
+ gtk_widget_set_sensitive((GtkWidget *)data->buttons[BUTTON_DOWN], index >=0 && index<count);
+}
+
+static void
+select_rule(GtkWidget *w, GtkWidget *child, struct _editor_data *data)
+{
+ data->current = gtk_object_get_data((GtkObject *)child, "rule");
+ if (data->current)
+ d(printf("seledct rule: %s\n", data->current->name));
+ else
+ d(printf("bad data?\n"));
+ set_sensitive(data);
+}
+
+GtkWidget *vfolder_editor_construct (struct _VfolderContext *f)
+{
+ GladeXML *gui;
+ GtkWidget *d, *w;
+ GList *l;
+ FilterRule *rule = NULL;
+ struct _editor_data *data;
+ int i;
+
+ g_assert(IS_VFOLDER_CONTEXT(f));
+
+ data = g_malloc0(sizeof(*data));
+ data->f = (RuleContext *)f;
+
+ gui = glade_xml_new(FILTER_GLADEDIR "/filter.glade", "edit_vfolder");
+ d = glade_xml_get_widget (gui, "edit_vfolder");
+ gtk_object_set_data_full((GtkObject *)d, "data", data, g_free);
+
+ gtk_window_set_title((GtkWindow *)d, "Edit VFolders");
+ for (i=0;i<BUTTON_LAST;i++) {
+ data->buttons[i] = (GtkButton *)w = glade_xml_get_widget (gui, edit_buttons[i].name);
+ gtk_signal_connect((GtkObject *)w, "clicked", edit_buttons[i].func, data);
+ }
+
+ w = glade_xml_get_widget (gui, "rule_list");
+ data->list = (GtkList *)w;
+ l = NULL;
+ while ((rule = rule_context_next_rule((RuleContext *)f, rule))) {
+ GtkListItem *item = (GtkListItem *)gtk_list_item_new_with_label(rule->name);
+ gtk_object_set_data((GtkObject *)item, "rule", rule);
+ gtk_widget_show((GtkWidget *)item);
+ l = g_list_append(l, item);
+ }
+ gtk_list_append_items(data->list, l);
+ gtk_signal_connect((GtkObject *)w, "select_child", select_rule, data);
+
+ set_sensitive(data);
+ gtk_object_unref((GtkObject *)gui);
+
+ return d;
+}
diff --git a/filter/vfolder-editor.h b/filter/vfolder-editor.h
new file mode 100644
index 0000000000..2ff2b261dc
--- /dev/null
+++ b/filter/vfolder-editor.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2000 Helix Code Inc.
+ *
+ * Authors: Not Zed <notzed@lostzed.mmc.com.au>
+ *
+ * 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 _VFOLDER_EDITOR_H
+#define _VFOLDER_EDITOR_H
+
+#include <gtk/gtk.h>
+#include <libgnomeui/gnome-dialog.h>
+
+#if 0
+/* NOTE: object stuff not used (yet?), this is just a holder file for a static factory */
+
+#define VFOLDER_EDITOR(obj) GTK_CHECK_CAST (obj, vfolder_editor_get_type (), VfolderEditor)
+#define VFOLDER_EDITOR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, vfolder_editor_get_type (), VfolderEditorClass)
+#define IS_VFOLDER_EDITOR(obj) GTK_CHECK_TYPE (obj, vfolder_editor_get_type ())
+
+typedef struct _VfolderEditor VfolderEditor;
+typedef struct _VfolderEditorClass VfolderEditorClass;
+
+struct _VfolderEditor {
+ GnomeDialog parent;
+ struct _VfolderEditorPrivate *priv;
+
+};
+
+struct _VfolderEditorClass {
+ GnomeDialogClass parent_class;
+
+ /* virtual methods */
+
+ /* signals */
+};
+
+guint vfolder_editor_get_type (void);
+VfolderEditor *vfolder_editor_new (void);
+#endif
+
+struct _VfolderContext;
+
+/* methods */
+GtkWidget *vfolder_editor_construct (struct _VfolderContext *f);
+
+#endif /* ! _VFOLDER_EDITOR_H */
+
diff --git a/filter/vfoldertypes.xml b/filter/vfoldertypes.xml
index 5363d6bfc4..af763aed2f 100644
--- a/filter/vfoldertypes.xml
+++ b/filter/vfoldertypes.xml
@@ -1,74 +1,80 @@
<?xml version="1.0"?>
<filterdescription>
-<ruleset type="match">
-<rule name="from-address">
- <code>
- (match-all (header-contains "From" ${sender}))
- </code>
- <description lang="en">The From address matches <source type="address" name="sender">sender(s)</source>.</description>
-</rule>
-
-<rule name="to-address">
- <code>
- (match-all (or (header-contains "To" ${recipient})
- (header-contains "Cc" ${recipient})))
- </code>
- <description lang="en">The To or Cc address matches <source type="address" name="recipient">recipients</source>.</description>
-</rule>
-
-<rule name="subject-contains">
- <code>
- (match-all (header-contains "Subject" ${words}))
- </code>
- <description lang="en">The Subject contains <source type="string" name="words">words</source>.</description>
-</rule>
-
-<rule name="body-contains">
- <code>
- (match-all (body-contains ${words}))
- </code>
- <description lang="en">The body contains <source type="string" name="words">words</source>.</description>
-</rule>
-
-<rule name="cc-address">
- <code>
- (match-all (header-contains "CC" ${self-email}))
- </code>
- <description lang="en">I am in the cc list.</description>
-</rule>
-
-</ruleset>
-
-<ruleset type="except">
-<rule name="except-me">
- <code>
- (match-all (not (header-contains "To" ${self-email})))
- </code>
- <description language="en">I am the recipient.</description>
-</rule>
-<rule name="not-body-contains">
- <code>
- (match-all (not (body-contains ${words})))
- </code>
- <description lang="en">The body does not contain <source type="string" name="words">words</source>.</description>
-</rule>
-</ruleset>
-
-<optionset>
- <option type="match">
- <description language="en">For matching messages.</description>
- </option>
- <option type="match">
- <description language="en">Messages from a certain person.</description>
- <optionrule type="match" rule="from-address"/>
- </option>
- <option type="match">
- <description language="en">Messages to a certain address.</description>
- <optionrule type="match" rule="to-address"/>
- </option>
- <option type="match">
- <description language="en">Messages with a given subject.</description>
- <optionrule type="match" rule="subject-contains"/>
- </option>
-</optionset>
+<partset>
+ <part name="sender">
+ <title>Sender</title>
+ <input type="optionlist" name="sender-type">
+ <option value="contains">
+ <title>contains</title>
+ <code>(match-all (header-contains "From" ${sender}))</code>
+ </option>
+ <option value="not contains">
+ <title>does not contain</title>
+ <code>(match-all (not (header-contains "From" ${sender})))</code>
+ </option>
+ </input>
+ <input type="string" name="sender"/>
+ </part>
+ <part name="to">
+ <title>Recipients</title>
+ <input type="optionlist" name="recipient-type">
+ <option value="contains">
+ <title>contains</title>
+ <code>
+ (match-all (or (header-contains "To" ${recipient})
+ (header-contains "Cc" ${recipient})))
+ </code>
+ </option>
+ <option value="not contains">
+ <title>does not contain</title>
+ <code>
+ (match-all (not (or
+ (header-contains "To" ${recipient})
+ (header-contains "Cc" ${recipient}))))
+ </code>
+ </option>
+ </input>
+ <input type="address" name="recipient"/>
+ </part>
+ <part name="subject">
+ <title>Subject</title>
+ <input type="optionlist" name="subject-type">
+ <option value="contains">
+ <title>contains</title>
+ <code>
+ (match-all (header-contains "Subject" ${subject}))
+ </code>
+ </option>
+ <option value="not contains">
+ <title>does not contain</title>
+ <code>
+ (match-all (not (header-contains "Subject" ${subject})))
+ </code>
+ </option>
+ </input>
+ <input type="string" name="subject"/>
+ </part>
+ <part name="body">
+ <title>Message Body</title>
+ <input type="optionlist" name="body-type">
+ <option value="contains">
+ <title>contains</title>
+ <code>
+ (body-contains ${word})
+ </code>
+ </option>
+ <option value="not contains">
+ <title>does not contain</title>
+ <code>
+ (not (body-contains "Subject" ${word}))
+ </code>
+ </option>
+ </input>
+ <input type="string" name="word"/>
+ </part>
+ <part name="sexp">
+ <title>Expression</title>
+ <input type="code" name="code"/>
+ </part>
+</partset>
</filterdescription>