aboutsummaryrefslogtreecommitdiffstats
path: root/filter/filter-driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'filter/filter-driver.c')
-rw-r--r--filter/filter-driver.c498
1 files changed, 348 insertions, 150 deletions
diff --git a/filter/filter-driver.c b/filter/filter-driver.c
index ff8b0a6fda..94c69c93b0 100644
--- a/filter/filter-driver.c
+++ b/filter/filter-driver.c
@@ -1,3 +1,25 @@
+/*
+ * 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 General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "filter-driver.h"
#include <glib.h>
#include <gtk/gtk.h>
@@ -14,23 +36,190 @@
#include <camel/camel.h>
-extern int filter_find_arg(FilterArg *a, char *name);
-
-struct exec_context {
+struct _FilterDriverPrivate {
+ GList *rules, *options;
GHashTable *globals; /* global variables */
+ /* run-time data */
+ GHashTable *folders; /* currently open folders */
GList *matches; /* all messages which match current rule */
-
- GList *deleted; /* messages to be deleted */
GHashTable *terminated; /* messages for which processing is terminated */
GHashTable *processed; /* all messages that were processed in some way */
- CamelSession *session;
- CamelStore *store;
- CamelFolder *folder; /* temporary input folder */
+ CamelFolder *source; /* temporary input folder */
+
CamelException *ex;
+
+ /* evaluator */
+ ESExp *eval;
};
+#define _PRIVATE(o) (((FilterDriver *)(o))->priv)
+
+static void filter_driver_class_init (FilterDriverClass *klass);
+static void filter_driver_init (FilterDriver *obj);
+static void filter_driver_finalise (GtkObject *obj);
+
+static CamelFolder *open_folder(FilterDriver *d, const char *folder_url);
+static int close_folders(FilterDriver *d);
+
+static ESExpResult *do_delete(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *);
+static ESExpResult *do_forward(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *);
+static ESExpResult *do_copy(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *);
+static ESExpResult *do_stop(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *);
+
+static struct {
+ char *name;
+ ESExpFunc *func;
+ int type; /* set to 1 if a function can perform shortcut evaluation, or
+ doesn't execute everything, 0 otherwise */
+} symbols[] = {
+ { "delete", (ESExpFunc *)do_delete, 0 },
+ { "forward-to", (ESExpFunc *)do_forward, 0 },
+ { "copy-to", (ESExpFunc *)do_copy, 0 },
+ { "stop", (ESExpFunc *)do_stop, 0 },
+};
+
+static GtkObjectClass *filter_driver_parent;
+
+enum SIGNALS {
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+guint
+filter_driver_get_type (void)
+{
+ static guint type = 0;
+
+ if (!type) {
+ GtkTypeInfo type_info = {
+ "FilterDriver",
+ sizeof (FilterDriver),
+ sizeof (FilterDriverClass),
+ (GtkClassInitFunc) filter_driver_class_init,
+ (GtkObjectInitFunc) filter_driver_init,
+ (GtkArgSetFunc) NULL,
+ (GtkArgGetFunc) NULL
+ };
+
+ type = gtk_type_unique (gtk_object_get_type (), &type_info);
+ }
+
+ return type;
+}
+
+static void
+filter_driver_class_init (FilterDriverClass *klass)
+{
+ GtkObjectClass *object_class = (GtkObjectClass *) klass;
+
+ filter_driver_parent = gtk_type_class (gtk_object_get_type ());
+
+ object_class->finalize = filter_driver_finalise;
+
+ gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
+}
+
+static void
+filter_driver_init (FilterDriver *obj)
+{
+ struct _FilterDriverPrivate *p;
+ int i;
+
+ p = _PRIVATE(obj) = g_malloc0(sizeof(*p));
+
+ p->eval = e_sexp_new();
+ /* Load in builtin symbols */
+ for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++) {
+ if (symbols[i].type == 1) {
+ e_sexp_add_ifunction(p->eval, 0, symbols[i].name, (ESExpIFunc *)symbols[i].func, obj);
+ } else {
+ e_sexp_add_function(p->eval, 0, symbols[i].name, symbols[i].func, obj);
+ }
+ }
+
+ p->globals = g_hash_table_new(g_str_hash, g_str_equal);
+
+ p->ex = camel_exception_new ();
+}
+
+static void
+free_hash_strings(void *key, void *value, void *data)
+{
+ g_free(key);
+ g_free(value);
+}
+
+static void
+filter_driver_finalise (GtkObject *obj)
+{
+ FilterDriver *d = (FilterDriver *)obj;
+ struct _FilterDriverPrivate *p = _PRIVATE(d);
+
+ g_hash_table_foreach(p->globals, free_hash_strings, d);
+ g_hash_table_destroy(p->globals);
+
+ gtk_object_unref((GtkObject *)p->eval);
+
+ ((GtkObjectClass *)(filter_driver_parent))->finalize((GtkObject *)obj);
+}
+
+/**
+ * filter_driver_new:
+ *
+ * Create a new FilterDriver object.
+ *
+ * Return value: A new FilterDriver widget.
+ **/
+FilterDriver *
+filter_driver_new (void)
+{
+ FilterDriver *new = FILTER_DRIVER ( gtk_type_new (filter_driver_get_type ()));
+ return new;
+}
+
+
+void filter_driver_set_session(FilterDriver *d, CamelSession *s)
+{
+ if (d->session)
+ gtk_object_unref((GtkObject *)s);
+ d->session = s;
+ if (s)
+ gtk_object_ref((GtkObject *)s);
+}
+
+int filter_driver_set_rules(FilterDriver *d, const char *description, const char *filter)
+{
+ struct _FilterDriverPrivate *p = _PRIVATE(d);
+ xmlDocPtr desc, filt;
+
+#warning "fix leaks, free xml docs here"
+ desc = xmlParseFile(description);
+ p->rules = filter_load_ruleset(desc);
+
+ filt = xmlParseFile(filter);
+ p->options = filter_load_optionset(filt, p->rules);
+
+ return 0;
+}
+
+void filter_driver_set_global(FilterDriver *d, const char *name, const char *value)
+{
+ struct _FilterDriverPrivate *p = _PRIVATE(d);
+ char *oldkey, *oldvalue;
+
+ if (g_hash_table_lookup_extended(p->globals, name, (void *)&oldkey, (void *)&oldvalue)) {
+ g_free(oldvalue);
+ g_hash_table_insert(p->globals, oldkey, g_strdup(value));
+ } else {
+ g_hash_table_insert(p->globals, g_strdup(name), g_strdup(value));
+ }
+}
+
+extern int filter_find_arg(FilterArg *a, char *name);
+
/*
foreach rule
@@ -44,7 +233,7 @@ struct exec_context {
/*
splices ${cc} lines into a single string
*/
-int
+static int
expand_variables(GString *out, char *source, GList *args, GHashTable *globals)
{
GList *argl;
@@ -111,15 +300,11 @@ expand_variables(GString *out, char *source, GList *args, GHashTable *globals)
build an expression for the filter
*/
static void
-expand_filter_option(GString *s, GString *action, struct filter_option *op)
+expand_filter_option(FilterDriver *d, GString *s, GString *action, struct filter_option *op)
{
GList *optionl;
FilterArg *arg;
- GHashTable *globals;
-
- globals = g_hash_table_new(g_str_hash, g_str_equal);
-
- g_hash_table_insert(globals, "self-email", "mzucchi@dehaa.sa.gov.au");
+ struct _FilterDriverPrivate *p = _PRIVATE(d);
g_string_append(s, "(and ");
optionl = op->options;
@@ -133,7 +318,7 @@ expand_filter_option(GString *s, GString *action, struct filter_option *op)
printf("arg = %s\n", arg->name);
}
}
- expand_variables(s, or->rule->code, or->args, globals);
+ expand_variables(s, or->rule->code, or->args, p->globals);
}
optionl = g_list_next(optionl);
}
@@ -145,7 +330,7 @@ expand_filter_option(GString *s, GString *action, struct filter_option *op)
while (optionl) {
struct filter_optionrule *or = optionl->data;
if (or->rule->type == FILTER_XML_ACTION) {
- expand_variables(action, or->rule->code, or->args, globals);
+ expand_variables(action, or->rule->code, or->args, p->globals);
g_string_append(action, " ");
}
optionl = g_list_next(optionl);
@@ -156,57 +341,51 @@ expand_filter_option(GString *s, GString *action, struct filter_option *op)
printf("combined action '%s'\n", action->str);
}
-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 ESExpResult *
-do_delete(struct _ESExp *f, int argc, struct _ESExpResult **argv, struct exec_context *x)
+do_delete(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *d)
{
+ struct _FilterDriverPrivate *p = _PRIVATE(d);
GList *m;
printf("doing delete\n");
- m = x->matches;
+ m = p->matches;
while (m) {
- printf(" %s\n", m->data);
- x->deleted = g_list_append(x->deleted, g_strdup(m->data));
+ CamelMimeMessage *mm;
+
+ printf(" %s\n", (char *)m->data);
+
+ mm = camel_folder_get_message_by_uid(p->source, m->data, p->ex);
+ if (mm) {
+ camel_mime_message_set_flags(mm, CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_DELETED);
+ gtk_object_unref((GtkObject *)mm);
+ }
+
m = m->next;
}
return NULL;
}
static ESExpResult *
-do_forward(struct _ESExp *f, int argc, struct _ESExpResult **argv, struct exec_context *x)
+do_forward(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *d)
{
+ struct _FilterDriverPrivate *p = _PRIVATE(d);
GList *m;
printf("doing forward on the following messages:\n");
- m = x->matches;
+ m = p->matches;
while (m) {
- printf(" %s\n", m->data);
+ printf(" %s\n", (char *)m->data);
m = m->next;
}
return NULL;
}
static ESExpResult *
-do_copy(struct _ESExp *f, int argc, struct _ESExpResult **argv, struct exec_context *x)
+do_copy(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *d)
{
GList *m;
int i;
+ struct _FilterDriverPrivate *p = _PRIVATE(d);
printf("doing copy on the following messages to:");
for (i=0;i<argc;i++) {
@@ -217,27 +396,25 @@ do_copy(struct _ESExp *f, int argc, struct _ESExpResult **argv, struct exec_cont
/* FIXME: this might have to find another store, based on
the folder as a url??? */
printf("opening outpbox %s\n", folder);
- outbox = camel_store_get_folder (x->store, folder, x->ex);
- if (!camel_folder_exists(outbox, x->ex)) {
- camel_folder_create(outbox, x->ex);
+ outbox = open_folder(d, folder);
+ if (outbox == NULL) {
+ g_warning("Cannot open folder: %s", folder);
+ continue;
}
-
- camel_folder_open (outbox, FOLDER_OPEN_WRITE, x->ex);
- m = x->matches;
+ m = p->matches;
while (m) {
CamelMimeMessage *mm;
- printf("appending message %s\n", m->data);
+ printf("appending message %s\n", (char *)m->data);
- mm = camel_folder_get_message_by_uid(x->folder, m->data, x->ex);
- camel_folder_append_message(outbox, mm, x->ex);
+ mm = camel_folder_get_message_by_uid(p->source, m->data, p->ex);
+ camel_folder_append_message(outbox, mm, p->ex);
gtk_object_unref((GtkObject *)mm);
- printf(" %s\n", m->data);
+ printf(" %s\n", (char *)m->data);
m = m->next;
}
- camel_folder_close (outbox, FALSE, x->ex);
}
}
@@ -245,159 +422,180 @@ do_copy(struct _ESExp *f, int argc, struct _ESExpResult **argv, struct exec_cont
}
static ESExpResult *
-do_stop(struct _ESExp *f, int argc, struct _ESExpResult **argv, struct exec_context *x)
+do_stop(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *d)
{
GList *m;
+ struct _FilterDriverPrivate *p = _PRIVATE(d);
printf("doing stop on the following messages:\n");
- m = x->matches;
+ m = p->matches;
while (m) {
- printf(" %s\n", m->data);
- g_hash_table_insert(x->terminated, g_strdup(m->data), (void *)1);
+ printf(" %s\n", (char *)m->data);
+ g_hash_table_insert(p->terminated, g_strdup(m->data), (void *)1);
m = m->next;
}
return NULL;
}
-static struct {
- char *name;
- ESExpFunc *func;
- int type; /* set to 1 if a function can perform shortcut evaluation, or
- doesn't execute everything, 0 otherwise */
-} symbols[] = {
- { "delete", (ESExpFunc *)do_delete, 0 },
- { "forward-to", (ESExpFunc *)do_forward, 0 },
- { "copy-to", (ESExpFunc *)do_copy, 0 },
- { "stop", (ESExpFunc *)do_stop, 0 },
-};
-
-static char *
-auth_callback(char *prompt, gboolean secret,
- CamelService *service, char *item,
- CamelException *ex)
+static CamelFolder *
+open_folder(FilterDriver *d, const char *folder_url)
{
- printf ("auth_callback called: %s\n", prompt);
+ char *folder, *store;
+ CamelStore *camelstore;
+ CamelFolder *camelfolder;
+ struct _FilterDriverPrivate *p = _PRIVATE(d);
+
+ /* we have a lookup table of currently open folders */
+ camelfolder = g_hash_table_lookup(p->folders, folder_url);
+ if (camelfolder)
+ return camelfolder;
+
+ store = g_strdup(folder_url);
+ folder = strrchr(store, '/');
+ if (folder == NULL || folder == store || folder[1]==0)
+ goto fail;
+
+ *folder++ = 0;
+ camelstore = camel_session_get_store (d->session, store, p->ex);
+ if (camel_exception_get_id (p->ex)) {
+ printf ("Could not open store: %s: %s", store, camel_exception_get_description (p->ex));
+ goto fail;
+ }
+
+ camelfolder = camel_store_get_folder (camelstore, folder, p->ex);
+ if (camel_exception_get_id (p->ex)) {
+ printf ("Could not open folder: %s: %s", folder, camel_exception_get_description (p->ex));
+ goto fail;
+ }
+
+ g_free(store);
+
+ if (!camel_folder_exists(camelfolder, p->ex)) {
+ camel_folder_create(camelfolder, p->ex);
+ }
+
+ g_hash_table_insert(p->folders, g_strdup(folder_url), camelfolder);
+
+ return camelfolder;
+
+fail:
+ g_free(store);
return NULL;
}
-static struct exec_context *
-start(void)
+static void
+close_folder(void *key, void *value, void *data)
{
- struct exec_context *x;
- char *store_url = "mbox:///tmp/evmail";
-
- x = g_malloc0(sizeof(*x));
-
- /* just hack up this for now */
- x->ex = camel_exception_new ();
- x->session = camel_session_new (auth_callback);
- printf("session = %p\n", x->session);
- x->store = camel_session_get_store (x->session, store_url, x->ex);
- printf("store = %p\n", x->store);
- if (camel_exception_get_id (x->ex)) {
- printf ("Exception caught in camel_store_get_folder\n"
- "Full description : %s\n", camel_exception_get_description (x->ex));
- return NULL;
- }
- x->folder = camel_store_get_folder (x->store, "Inbox", x->ex);
- if (camel_exception_get_id (x->ex)) {
- printf ("Exception caught in camel_store_get_folder\n"
- "Full description : %s\n", camel_exception_get_description (x->ex));
- return NULL;
- }
- camel_folder_open (x->folder, FOLDER_OPEN_READ, x->ex);
- x->terminated = g_hash_table_new(g_str_hash, g_str_equal);
- x->processed = g_hash_table_new(g_str_hash, g_str_equal);
- return x;
+ CamelFolder *f = value;
+ FilterDriver *d = data;
+ struct _FilterDriverPrivate *p = _PRIVATE(d);
+
+ g_free(key);
+ camel_folder_close(f, TRUE, p->ex);
+ gtk_object_unref((GtkObject *)f);
+}
+
+/* flush/close all folders */
+static int
+close_folders(FilterDriver *d)
+{
+ struct _FilterDriverPrivate *p = _PRIVATE(d);
+
+ g_hash_table_foreach(p->folders, close_folder, d);
+ g_hash_table_destroy(p->folders);
+ p->folders = g_hash_table_new(g_str_hash, g_str_equal);
+
+ /* FIXME: status from d */
+ return 0;
}
-int main(int argc, char **argv)
+int
+filter_driver_run(FilterDriver *d, CamelFolder *source, CamelFolder *inbox)
{
- ESExp *f;
+ struct _FilterDriverPrivate *p = _PRIVATE(d);
ESExpResult *r;
- GList *rules, *options, *options2;
- xmlDocPtr doc, out;
+ GList *options;
GString *s, *a;
GList *all, *m;
- struct exec_context *x;
- int i;
- ESExp *eval;
- gnome_init("Test", "0.0", argc, argv);
- camel_init();
+ p->source = source;
- doc = xmlParseFile("filterdescription.xml");
- rules = filter_load_ruleset(doc);
- options2 = filter_load_optionset(doc, rules);
+ /* setup runtime data */
+ p->folders = g_hash_table_new(g_str_hash, g_str_equal);
+ p->terminated = g_hash_table_new(g_str_hash, g_str_equal);
+ p->processed = g_hash_table_new(g_str_hash, g_str_equal);
- out = xmlParseFile("saveoptions.xml");
- options = filter_load_optionset(out, rules);
-
- x = start();
-
- eval = e_sexp_new();
- /* Load in builtin symbols? */
- for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++) {
- if (symbols[i].type == 1) {
- e_sexp_add_ifunction(eval, 0, symbols[i].name, (ESExpIFunc *)symbols[i].func, x);
- } else {
- e_sexp_add_function(eval, 0, symbols[i].name, symbols[i].func, x);
- }
- }
+ camel_exception_init(p->ex);
+ options = p->options;
while (options) {
struct filter_option *fo = options->data;
- int id;
s = g_string_new("");
a = g_string_new("");
- expand_filter_option(s, a, fo);
+ expand_filter_option(d, s, a, fo);
printf("searching expression %s\n", s->str);
- x->matches = camel_folder_search_by_expression (x->folder, s->str, x->ex);
+ p->matches = camel_folder_search_by_expression (p->source, s->str, p->ex);
/* remove uid's for which processing is complete ... */
- m = x->matches;
+ m = p->matches;
while (m) {
GList *n = m->next;
/* for all matching id's, so we can work out what to default */
- if (g_hash_table_lookup(x->processed, m->data) == NULL) {
- g_hash_table_insert(x->processed, g_strdup(m->data), (void *)1);
+ if (g_hash_table_lookup(p->processed, m->data) == NULL) {
+ g_hash_table_insert(p->processed, g_strdup(m->data), (void *)1);
}
- if (g_hash_table_lookup(x->terminated, m->data)) {
- printf("removing terminated message %s\n", m->data);
- x->matches = g_list_remove_link(x->matches, m);
+ if (g_hash_table_lookup(p->terminated, m->data)) {
+ printf("removing terminated message %s\n", (char *)m->data);
+ p->matches = g_list_remove_link(p->matches, m);
}
m = n;
}
printf("applying actions ... '%s'\n", a->str);
- e_sexp_input_text(eval, a->str, strlen(a->str));
- e_sexp_parse(eval);
- r = e_sexp_eval(eval);
+ 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_list_free(x->matches);
+ g_list_free(p->matches);
options = g_list_next(options);
}
- /* now apply 'default' rule */
- all = camel_folder_get_uid_list(x->folder, x->ex);
- m = all;
- while (m) {
- char *uid = m->data;
- if (g_hash_table_lookup(x->processed, uid) == NULL) {
- printf("Applying default rule to message %s\n", uid);
+ /* apply the default of copying to an inbox, if we are given one */
+ if (inbox) {
+ all = camel_folder_get_uid_list(p->source, p->ex);
+ m = all;
+ while (m) {
+ char *uid = m->data;
+
+ if (g_hash_table_lookup(p->processed, uid) == NULL) {
+ CamelMimeMessage *mm;
+
+ printf("Applying default rule to message %s\n", uid);
+
+ mm = camel_folder_get_message_by_uid(p->source, m->data, p->ex);
+ camel_folder_append_message(inbox, mm, p->ex);
+ gtk_object_unref((GtkObject *)mm);
+
+ }
+ m = m->next;
}
- m = m->next;
+ g_list_free(all);
}
- g_list_free(all);
+
+ g_hash_table_destroy(p->processed);
+ g_hash_table_destroy(p->terminated);
+ g_hash_table_destroy(p->folders);
+
+ close_folders(d);
return 0;
}