diff options
Diffstat (limited to 'filter/filter-driver.c')
-rw-r--r-- | filter/filter-driver.c | 498 |
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; } |