diff options
-rw-r--r-- | filter/ChangeLog | 8 | ||||
-rw-r--r-- | filter/Makefile.am | 2 | ||||
-rw-r--r-- | filter/filter-driver.c | 458 | ||||
-rw-r--r-- | filter/filter-driver.h | 16 | ||||
-rw-r--r-- | filter/filter-message-search.c | 275 | ||||
-rw-r--r-- | filter/filter-message-search.h | 43 | ||||
-rw-r--r-- | filter/filter-rule.h | 12 |
7 files changed, 525 insertions, 289 deletions
diff --git a/filter/ChangeLog b/filter/ChangeLog index b1d0466194..0796572667 100644 --- a/filter/ChangeLog +++ b/filter/ChangeLog @@ -1,3 +1,11 @@ +2000-09-06 Jeffrey Stedfast <fejj@helixcode.com> + + * filter-driver.c (filter_driver_run): Totally rewritten to filter + a single message at a time instead of filtering a folder. + + * filter-message-search.c (filter_message_search): New convenience + function for searching a message. + 2000-08-24 Lauris Kaplinski <lauris@helixcode.com> * filter-folder.c: Use e_utf8 wrappers diff --git a/filter/Makefile.am b/filter/Makefile.am index 65927b827a..477666f4b7 100644 --- a/filter/Makefile.am +++ b/filter/Makefile.am @@ -42,6 +42,8 @@ libfilter_la_SOURCES = \ filter-folder.h \ filter-input.c \ filter-input.h \ + filter-message-search.c \ + filter-message-search.h \ filter-option.c \ filter-option.h \ filter-part.c \ diff --git a/filter/filter-driver.c b/filter/filter-driver.c index 5cedee6e85..bc8dbd8ca2 100644 --- a/filter/filter-driver.c +++ b/filter/filter-driver.c @@ -22,6 +22,7 @@ */ #include "filter-driver.h" +#include "filter-message-search.h" #include <glib.h> #include <gtk/gtk.h> @@ -32,23 +33,22 @@ #include <gnome-xml/parser.h> #include <camel/camel.h> -#include "mail/mail-tools.h" /*mail_tool_camel_lock_up*/ +#include "mail/mail-tools.h" /*mail_tool_camel_lock_up/down*/ #include "filter-context.h" #include "filter-filter.h" #include "e-util/e-sexp.h" -#define d(x) +#define d(x) x /* mail-thread filter input data type */ typedef struct { FilterDriver *driver; - CamelFolder *source; + CamelMimeMessage *message; CamelFolder *inbox; enum _filter_source_t sourcetype; gboolean self_destruct; gpointer unhook_func; gpointer unhook_data; - gchar *path_to_unlink; } filter_mail_input_t; /* mail-thread filter functions */ @@ -59,27 +59,26 @@ static void cleanup_filter_mail (gpointer in_data, gpointer op_data, CamelExcept struct _FilterDriverPrivate { - GHashTable *globals; /* global variables */ - + GHashTable *globals; /* global variables */ + FilterContext *context; - + /* for callback */ FilterGetFolderFunc get_folder; void *data; - + /* run-time data */ - GHashTable *folders; /* currently open folders */ - GPtrArray *matches; /* all messages which match current rule */ - GHashTable *terminated; /* messages for which processing is terminated */ - GHashTable *processed; /* all messages that were processed in some way */ - GHashTable *copies; /* lists of folders to copy messages to */ - - CamelFolder *source; /* temporary input folder */ - - GList *searches; /* search results */ - + GHashTable *folders; /* folders that message has been copied to */ + GHashTable *forwards; /* addresses that have been forwarded the message */ + + gboolean terminated; /* message processing was terminated */ + gboolean deleted; /* message was marked for deletion */ + + CamelMimeMessage *message; /* input message */ + CamelMessageInfo *info; /* message summary info */ + CamelException *ex; - + /* evaluator */ ESExp *eval; }; @@ -93,23 +92,24 @@ 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 *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 ESExpResult *do_delete (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *); +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 *); +/* these are our filter actions - each must have a callback */ 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 *)mark_forward, 0 }, - { "copy-to", (ESExpFunc *)mark_copy, 0 }, - { "stop", (ESExpFunc *)do_stop, 0 }, - { "set-colour", (ESExpFunc *)do_colour, 0 }, + { "delete", (ESExpFunc *) do_delete, 0 }, + { "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; @@ -148,9 +148,9 @@ 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); } @@ -159,9 +159,9 @@ 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++) { @@ -171,9 +171,9 @@ filter_driver_init (FilterDriver *obj) 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); - + /* Will get set in filter_driver_run */ p->ex = NULL; } @@ -190,18 +190,14 @@ 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 (GTK_OBJECT (p->eval)); - - /*Was set to the mail_operation_queue exception, - * not our responsibility to free it.*/ - /*camel_exception_free (p->ex);*/ g_free (p); - + ((GtkObjectClass *)(filter_driver_parent))->finalize (GTK_OBJECT (obj)); } @@ -220,25 +216,26 @@ filter_driver_new (FilterContext *context, FilterGetFolderFunc get_folder, void { FilterDriver *new; struct _FilterDriverPrivate *p; - + new = FILTER_DRIVER (gtk_type_new (filter_driver_get_type ())); - p = _PRIVATE(new); - + p = _PRIVATE (new); + p->get_folder = get_folder; p->data = data; p->context = context; - gtk_object_ref((GtkObject *)context); - + gtk_object_ref (GTK_OBJECT (context)); + return new; } #if 0 -void filter_driver_set_global(FilterDriver *d, const char *name, const char *value) +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)); @@ -252,18 +249,12 @@ static ESExpResult * do_delete (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *driver) { struct _FilterDriverPrivate *p = _PRIVATE (driver); - char *uid; - int i; - - printf ("doing delete\n"); - for (i = 0; i < p->matches->len; i++) { - uid = p->matches->pdata[i]; - printf (" %s\n", uid); - - mail_tool_camel_lock_up (); - camel_folder_delete_message (p->source, uid); - mail_tool_camel_lock_down (); + + if (!p->terminated) { + d(fprintf (stderr, "doing delete\n")); + p->deleted = TRUE; } + return NULL; } @@ -271,12 +262,12 @@ static ESExpResult * mark_forward (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *driver) { struct _FilterDriverPrivate *p = _PRIVATE (driver); - int i; - - printf ("marking the following messages for forwarding:\n"); - for (i = 0; i < p->matches->len; i++) { - printf (" %s\n", (char *)p->matches->pdata[i]); + + if (!p->terminated) { + d(fprintf (stderr, "marking message for forwarding\n")); + /* FIXME: do stuff here */ } + return NULL; } @@ -284,33 +275,30 @@ static ESExpResult * mark_copy (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *driver) { struct _FilterDriverPrivate *p = _PRIVATE (driver); - int i, m; - char *uid; - - printf ("marking for copy\n"); - for (i = 0; i < argc; i++) { - if (argv[i]->type == ESEXP_RES_STRING) { - char *folder = argv[i]->value.string; - CamelFolder *outbox; - - outbox = open_folder (driver, folder); - if (outbox == NULL) - continue; - - for (m = 0; m < p->matches->len; m++) { - gpointer old_key, old_value; - - uid = p->matches->pdata[m]; - printf (" %s\n", uid); - - if (g_hash_table_lookup_extended (p->copies, uid, &old_key, &old_value)) - g_hash_table_insert (p->copies, old_key, g_list_prepend (old_value, outbox)); - else - g_hash_table_insert (p->copies, uid, g_list_append (NULL, outbox)); + int i; + + if (!p->terminated) { + d(fprintf (stderr, "copying message...\n")); + for (i = 0; i < argc; i++) { + if (argv[i]->type == ESEXP_RES_STRING) { + /* open folders we intent to copy to */ + char *folder = argv[i]->value.string; + CamelFolder *outbox; + + outbox = g_hash_table_lookup (p->folders, folder); + if (!outbox) { + outbox = open_folder (driver, folder); + if (!outbox) + continue; + + mail_tool_camel_lock_up (); + camel_folder_append_message (outbox, p->message, p->info, p->ex); + mail_tool_camel_lock_down (); + } } } } - + return NULL; } @@ -318,65 +306,61 @@ static ESExpResult * do_stop (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *driver) { struct _FilterDriverPrivate *p = _PRIVATE (driver); - char *uid; - int i; - - printf ("doing stop on the following messages:\n"); - for (i = 0; i < p->matches->len; i++) { - uid = p->matches->pdata[i]; - printf (" %s\n", uid); - g_hash_table_insert (p->terminated, uid, GINT_TO_POINTER (1)); + + if (!p->terminated) { + d(fprintf (stderr, "terminating message processing\n")); + p->terminated = TRUE; } + return NULL; } static ESExpResult * -do_colour(struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *d) +do_colour (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterDriver *driver) { - int i; - char *uid; - struct _FilterDriverPrivate *p = _PRIVATE(d); - - if (argc>0 && argv[0]->type == ESEXP_RES_STRING) { - for (i=0 ; i<p->matches->len; i++) { - uid = p->matches->pdata[i]; - camel_folder_set_message_user_tag(p->source, uid, "colour", argv[0]->value.string); + struct _FilterDriverPrivate *p = _PRIVATE (driver); + + if (!p->terminated) { + d(fprintf (stderr, "setting colour flag\n")); + if (argc > 0 && argv[0]->type == ESEXP_RES_STRING) { + camel_tag_set (&p->info->user_tags, "colour", argv[0]->value.string); } } - + return NULL; } static CamelFolder * open_folder (FilterDriver *driver, const char *folder_url) { - CamelFolder *camelfolder; struct _FilterDriverPrivate *p = _PRIVATE (driver); - + CamelFolder *camelfolder; + /* we have a lookup table of currently open folders */ camelfolder = g_hash_table_lookup (p->folders, folder_url); if (camelfolder) return camelfolder; - - camelfolder = p->get_folder(driver, folder_url, p->data); - + + camelfolder = p->get_folder (driver, folder_url, p->data); + if (camelfolder) { g_hash_table_insert (p->folders, g_strdup (folder_url), camelfolder); mail_tool_camel_lock_up (); camel_folder_freeze (camelfolder); mail_tool_camel_lock_down (); } - + return camelfolder; } static void close_folder (void *key, void *value, void *data) { + CamelFolder *folder = value; FilterDriver *driver = data; struct _FilterDriverPrivate *p = _PRIVATE (driver); - + g_free (key); mail_tool_camel_lock_up (); camel_folder_sync (folder, FALSE, p->ex); @@ -390,11 +374,11 @@ static int close_folders (FilterDriver *driver) { struct _FilterDriverPrivate *p = _PRIVATE (driver); - + g_hash_table_foreach (p->folders, close_folder, driver); g_hash_table_destroy (p->folders); p->folders = g_hash_table_new (g_str_hash, g_str_equal); - + /* FIXME: status from driver */ return 0; } @@ -417,27 +401,26 @@ static const mail_operation_spec op_filter_mail = }; void -filter_driver_run (FilterDriver *d, CamelFolder *source, CamelFolder *inbox, - enum _filter_source_t sourcetype, - gboolean self_destruct, gpointer unhook_func, gpointer unhook_data, - const char *path_to_unlink) +filter_driver_run (FilterDriver *driver, CamelMimeMessage *message, CamelFolder *inbox, + enum _filter_source_t sourcetype, gboolean self_destruct, + gpointer unhook_func, gpointer unhook_data) { filter_mail_input_t *input; - + input = g_new (filter_mail_input_t, 1); - input->driver = d; - input->source = source; + input->driver = driver; + input->message = message; input->inbox = inbox; input->sourcetype = sourcetype; input->self_destruct = self_destruct; input->unhook_func = unhook_func; input->unhook_data = unhook_data; - input->path_to_unlink = g_strdup (path_to_unlink); - + mail_operation_queue (&op_filter_mail, input, TRUE); } -static gchar *describe_filter_mail (gpointer in_data, gboolean gerund) +static gchar * +describe_filter_mail (gpointer in_data, gboolean gerund) { filter_mail_input_t *input = (filter_mail_input_t *) in_data; @@ -453,26 +436,26 @@ static void setup_filter_mail (gpointer in_data, gpointer op_data, CamelException *ex) { filter_mail_input_t *input = (filter_mail_input_t *) in_data; - + if (!input->driver) { camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, "Bad filter driver passed to filter_mail"); return; } - - if (!CAMEL_IS_FOLDER (input->source)) { + + if (!CAMEL_IS_MIME_MESSAGE (input->message)) { camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, - "Bad source folder passed to filter_mail"); + "Bad mime message passed to filter_mail"); return; } - + if (!CAMEL_IS_FOLDER (input->inbox)) { camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, "Bad Inbox passed to filter_mail"); return; } - - camel_object_ref (CAMEL_OBJECT (input->source)); + + camel_object_ref (CAMEL_OBJECT (input->message)); camel_object_ref (CAMEL_OBJECT (input->inbox)); } @@ -480,166 +463,96 @@ static void do_filter_mail (gpointer in_data, gpointer op_data, CamelException *ex) { filter_mail_input_t *input = (filter_mail_input_t *) in_data; - FilterDriver *d = input->driver; - CamelFolder *source = input->source; + FilterDriver *driver = input->driver; + CamelMimeMessage *message = input->message; CamelFolder *inbox = input->inbox; - struct _FilterDriverPrivate *p = _PRIVATE (d); + struct _FilterDriverPrivate *p = _PRIVATE (driver); ESExpResult *r; - GString *s, *a; - GPtrArray *all; - char *uid; - int i; + GString *fsearch, *faction; FilterFilter *rule; - GList *l; - - /* FIXME: needs to check all failure cases */ - p->source = source; - + + p->ex = camel_exception_new (); + p->terminated = FALSE; + p->deleted = FALSE; + p->message = message; + p->info = g_new0 (CamelMessageInfo, 1); + /* 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); - p->copies = g_hash_table_new(g_str_hash, g_str_equal); - + p->folders = g_hash_table_new (g_str_hash, g_str_equal); + mail_tool_camel_lock_up (); - camel_folder_freeze(inbox); + camel_folder_freeze (inbox); mail_tool_camel_lock_down (); - - s = g_string_new(""); - a = g_string_new(""); - + + fsearch = g_string_new (""); + faction = g_string_new (""); + rule = NULL; - while ( (rule = (FilterFilter *)rule_context_next_rule((RuleContext *)p->context, (FilterRule *)rule)) ) { - + while ((rule = (FilterFilter *)rule_context_next_rule ((RuleContext *)p->context, (FilterRule *)rule))) { + gboolean matched; + if (((FilterRule *)rule)->source != input->sourcetype) { - d(printf("skipping rule %s - wrong source type (%d %d)\n", ((FilterRule *)rule)->name, - ((FilterRule *)rule)->source, input->sourcetype)); + d(fprintf (stderr, "skipping rule %s - wrong source type (%d %d)\n", ((FilterRule *)rule)->name, + ((FilterRule *)rule)->source, input->sourcetype)); continue; } - - g_string_truncate(s, 0); - g_string_truncate(a, 0); - - filter_rule_build_code((FilterRule *)rule, s); - filter_filter_build_action(rule, a); - - d(printf("applying rule %s\n action %s\n", s->str, a->str)); - + + g_string_truncate (fsearch, 0); + g_string_truncate (faction, 0); + + filter_rule_build_code (FILTER_RULE (rule), fsearch); + filter_filter_build_action (rule, faction); + + d(fprintf (stderr, "applying rule %s\n action %s\n", fsearch->str, faction->str)); + mail_tool_camel_lock_up (); - p->matches = camel_folder_search_by_expression (p->source, s->str, p->ex); + matched = filter_message_search (p->message, p->info, fsearch->str, p->ex); mail_tool_camel_lock_down (); - - /* remove uid's for which processing is complete ... */ - for (i = 0; i < p->matches->len; i++) { - uid = p->matches->pdata[i]; - - /* for all matching id's, so we can work out what to default */ - if (g_hash_table_lookup (p->processed, uid) == NULL) { - g_hash_table_insert (p->processed, uid, GINT_TO_POINTER (1)); - } - - if (g_hash_table_lookup (p->terminated, uid)) { - g_ptr_array_remove_index_fast (p->matches, i); - i--; - } - } - + + if (!matched) + continue; + #ifndef NO_WARNINGS #warning "Must check expression parsed and executed properly?" #endif - 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); - - p->searches = g_list_append(p->searches, p->matches); + e_sexp_input_text (p->eval, faction->str, strlen (faction->str)); + e_sexp_parse (p->eval); + r = e_sexp_eval (p->eval); + e_sexp_result_free (r); + + if (p->terminated) + break; } - - 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. - */ - mail_tool_camel_lock_up (); - all = camel_folder_get_uids (p->source); - mail_tool_camel_lock_down (); - for (i = 0; i < all->len; i++) { - char *uid = all->pdata[i], *procuid; - GList *copies, *tmp; - CamelMimeMessage *mm; - const CamelMessageInfo *info; - - copies = g_hash_table_lookup (p->copies, uid); - procuid = g_hash_table_lookup (p->processed, uid); - + + g_string_free (fsearch, TRUE); + g_string_free (faction, TRUE); + + if (!p->deleted && g_hash_table_size (p->folders) == 0) { + /* copy it to the default inbox */ mail_tool_camel_lock_up (); - info = camel_folder_get_message_info (p->source, uid); - - if (copies || !procuid) { - mm = camel_folder_get_message (p->source, uid, p->ex); - - while (copies) { - camel_folder_append_message(copies->data, mm, info, p->ex); - tmp = copies->next; - g_list_free_1 (copies); - copies = tmp; - } - - if (!procuid && inbox != source) { - printf("Applying default rule to message %s\n", uid); - camel_folder_append_message(inbox, mm, info, p->ex); - } - - camel_object_unref (CAMEL_OBJECT (mm)); - } - - if (inbox != source) - camel_folder_delete_message (p->source, uid); + camel_folder_append_message (input->inbox, p->message, p->info, p->ex); + + /* warn that inbox was changed */ + if (input->unhook_func) + camel_object_unhook_event (CAMEL_OBJECT (input->inbox), "folder_changed", + input->unhook_func, input->unhook_data); mail_tool_camel_lock_down (); - } - mail_tool_camel_lock_up (); - camel_folder_free_uids (p->source, all); - if (input->unhook_func) - camel_object_unhook_event (CAMEL_OBJECT (input->inbox), "folder_changed", - input->unhook_func, input->unhook_data); - mail_tool_camel_lock_down (); - - /* now we no longer need our keys */ - l = p->searches; - while (l) { - camel_folder_search_free (p->source, l->data); - l = l->next; - } - g_list_free (p->searches); - g_hash_table_destroy (p->copies); - g_hash_table_destroy (p->processed); - g_hash_table_destroy (p->terminated); - close_folders (d); + /* close all folders that were opened for appending */ + close_folders (driver); g_hash_table_destroy (p->folders); + + /* thaw the inbox folder */ mail_tool_camel_lock_up (); - camel_folder_sync (source, TRUE, ex); - if (inbox != source) - camel_folder_sync (inbox, FALSE, ex); camel_folder_thaw (inbox); mail_tool_camel_lock_down (); - - if (input->path_to_unlink) { - struct stat sb; - - if (stat (input->path_to_unlink, &sb) < 0) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Couldn't stat(2) movemail folder %s"), - input->path_to_unlink); - return; - } - - if (sb.st_size == 0) - unlink (input->path_to_unlink); - } + + /* transfer any exceptions over to our async exception */ + if (camel_exception_is_set (p->ex)) + camel_exception_xfer (ex, p->ex); + + camel_exception_free (p->ex); } static void @@ -647,12 +560,9 @@ cleanup_filter_mail (gpointer in_data, gpointer op_data, CamelException *ex) { filter_mail_input_t *input = (filter_mail_input_t *) in_data; - camel_object_unref (CAMEL_OBJECT (input->source)); + camel_object_unref (CAMEL_OBJECT (input->message)); camel_object_unref (CAMEL_OBJECT (input->inbox)); - - if (input->path_to_unlink) - g_free (input->path_to_unlink); - + if (input->self_destruct) gtk_object_unref (GTK_OBJECT (input->driver)); } diff --git a/filter/filter-driver.h b/filter/filter-driver.h index 984780b927..5ab4d8a8a9 100644 --- a/filter/filter-driver.h +++ b/filter/filter-driver.h @@ -48,21 +48,19 @@ struct _FilterDriverClass { typedef CamelFolder * (*FilterGetFolderFunc) (FilterDriver *, const char *uri, void *data); -guint filter_driver_get_type (void); -FilterDriver *filter_driver_new (FilterContext *ctx, FilterGetFolderFunc fetcher, void *data); +guint filter_driver_get_type (void); +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 */ -void filter_driver_run(FilterDriver *d, CamelFolder *source, CamelFolder *inbox, - enum _filter_source_t sourcetype, - gboolean self_destruct, gpointer unhook_func, gpointer unhook_data, - const char *path_to_unlink); +void filter_driver_run (FilterDriver *driver, CamelMimeMessage *message, CamelFolder *inbox, + enum _filter_source_t sourcetype, + gboolean self_destruct, gpointer unhook_func, gpointer unhook_data); #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); +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); diff --git a/filter/filter-message-search.c b/filter/filter-message-search.c new file mode 100644 index 0000000000..a55a7f5c4d --- /dev/null +++ b/filter/filter-message-search.c @@ -0,0 +1,275 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@helixcode.com> + * + * Copyright 2000 Helix Code, Inc. (www.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 Street #330, Boston, MA 02111-1307, USA. + * + */ + +#include "filter-message-search.h" +#include <e-util/e-sexp.h> +#include <e-util/e-util.h> +#include <regex.h> + +typedef struct { + CamelMimeMessage *message; + CamelMessageInfo *info; + CamelException *ex; +} FilterMessageSearch; + +/* ESExp callbacks */ +static ESExpResult *header_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms); +static ESExpResult *match_all (struct _ESExp *f, int argc, struct _ESExpTerm **argv, FilterMessageSearch *fms); +static ESExpResult *body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms); +static ESExpResult *user_flag (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms); +static ESExpResult *user_tag (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms); +static ESExpResult *get_sent_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms); +static ESExpResult *get_received_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms); +static ESExpResult *get_current_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms); + + +/* builtin functions */ +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[] = { + { "match-all", (ESExpFunc *) match_all, 0 }, + { "body-contains", (ESExpFunc *) body_contains, 0 }, + { "header-contains", (ESExpFunc *) header_contains, 0 }, + { "user-tag", (ESExpFunc *) user_tag, 1 }, + { "user-flag", (ESExpFunc *) user_flag, 1 }, + { "get-sent-date", (ESExpFunc *) get_sent_date, 1 }, + { "get-received-date", (ESExpFunc *) get_received_date, 1 }, + { "get-current-date", (ESExpFunc *) get_current_date, 1 } +}; + +static ESExpResult * +header_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) +{ + gboolean matched = FALSE; + ESExpResult *r; + + if (argc == 2) { + char *header = (argv[0])->value.string; + char *match = (argv[1])->value.string; + const char *contents; + + contents = camel_medium_get_header (CAMEL_MEDIUM (fms->message), header); + if (contents && e_strstrcase (contents, match)) + matched = TRUE; + } + + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = matched; + + return r; +} + +static ESExpResult * +match_all (struct _ESExp *f, int argc, struct _ESExpTerm **argv, FilterMessageSearch *fms) +{ + /* match-all: when dealing with single messages is a no-op */ + ESExpResult *r; + + /* FIXME: is this right?? */ + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = TRUE; + + return r; +} + +static ESExpResult * +body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) +{ + gboolean matched = FALSE; + ESExpResult *r; + + if (argc > 0) { + CamelStream *stream; + GByteArray *array; + char *match, *body; + regex_t regexpat; /* regex patern */ + regmatch_t *fltmatch; + gint regerr = 0; + size_t reglen = 0; + gchar *regmsg; + + match = (*argv)->value.string; + + array = g_byte_array_new (); + stream = camel_stream_mem_new_with_byte_array (array); + camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (fms->message), stream); + camel_stream_reset (stream); + g_byte_array_append (array, "", 1); + + body = array->data; + + regerr = regcomp (®expat, match, REG_EXTENDED | REG_NEWLINE | REG_ICASE); + if (regerr) { + /* regerror gets called twice to get the full error string + length to do proper posix error reporting */ + reglen = regerror (regerr, ®expat, 0, 0); + regmsg = g_malloc0 (reglen + 1); + regerror (regerr, ®expat, regmsg, reglen); + camel_exception_setv (fms->ex, CAMEL_EXCEPTION_SYSTEM, + "Failed to perform regex search on message body: %s", + regmsg); + g_free (regmsg); + regfree (®expat); + } else { + fltmatch = g_new0 (regmatch_t, regexpat.re_nsub); + + if (!regexec (®expat, body, regexpat.re_nsub, fltmatch, 0)) + matched = TRUE; + + g_free (fltmatch); + regfree (®expat); + } + } + + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = matched; + + return r; +} + +static ESExpResult * +user_flag (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) +{ + ESExpResult *r; + gboolean truth = FALSE; + int i; + + /* performs an OR of all words */ + for (i = 0; i < argc && !truth; i++) { + if (argv[i]->type == ESEXP_RES_STRING + && camel_flag_get (&fms->info->user_flags, argv[i]->value.string)) { + truth = TRUE; + break; + } + } + + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = truth; + + return r; +} + +static ESExpResult * +user_tag (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) +{ + ESExpResult *r; + const char *tag; + + tag = camel_tag_get (&fms->info->user_tags, argv[0]->value.string); + + r = e_sexp_result_new (ESEXP_RES_STRING); + r->value.string = g_strdup (tag ? tag : ""); + + return r; +} + +static ESExpResult * +get_sent_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) +{ + ESExpResult *r; + const char *sent_date; + time_t date; + + sent_date = camel_mime_message_get_sent_date (fms->message); + date = header_decode_date (sent_date, NULL); + + r = e_sexp_result_new (ESEXP_RES_INT); + r->value.number = date; + + return r; +} + +static ESExpResult * +get_received_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) +{ + ESExpResult *r; + const char *received_date; + time_t date; + + received_date = camel_mime_message_get_received_date (fms->message); + date = header_decode_date (received_date, NULL); + + r = e_sexp_result_new (ESEXP_RES_INT); + r->value.number = date; + + return r; +} + +static ESExpResult * +get_current_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) +{ + ESExpResult *r; + time_t date; + + date = time (NULL); + + r = e_sexp_result_new (ESEXP_RES_INT); + r->value.number = date; + + return r; +} + +gboolean +filter_message_search (CamelMimeMessage *message, CamelMessageInfo *info, const char *expression, CamelException *ex) +{ + FilterMessageSearch *fms; + ESExp *sexp; + ESExpResult *result; + gboolean retval; + int i; + + fms = g_new (FilterMessageSearch, 1); + fms->message = message; + fms->info = info; + fms->ex = ex; + + sexp = e_sexp_new (); + + for (i = 0; i < sizeof (symbols) / sizeof (symbols[0]); i++) { + if (symbols[i].type == 1) { + e_sexp_add_ifunction (sexp, 0, symbols[i].name, + (ESExpIFunc *)symbols[i].func, fms); + } else { + e_sexp_add_function (sexp, 0, symbols[i].name, + symbols[i].func, fms); + } + } + + e_sexp_input_text (sexp, expression, strlen (expression)); + e_sexp_parse (sexp); + result = e_sexp_eval (sexp); + + g_free (fms); + + if (result->type == ESEXP_RES_BOOL) + retval = result->value.bool; + else + retval = FALSE; + + gtk_object_unref (GTK_OBJECT (sexp)); + e_sexp_result_free (result); + + return retval; +} diff --git a/filter/filter-message-search.h b/filter/filter-message-search.h new file mode 100644 index 0000000000..ce9cc57c52 --- /dev/null +++ b/filter/filter-message-search.h @@ -0,0 +1,43 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Jeffrey Stedfast <fejj@helixcode.com> + * + * Copyright 2000 Helix Code, Inc. (www.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 Street #330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef FILTER_MESSAGE_SEARCH_H +#define FILTER_MESSAGE_SEARCH_H + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +#include <glib.h> +#include <camel.h> +#include <camel-mime-message.h> +#include <camel-folder-summary.h> + +gboolean filter_message_search (CamelMimeMessage *message, CamelMessageInfo *info, + const char *expression, CamelException *ex); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! FILTER_MESSAGE_SEARCH_H */ diff --git a/filter/filter-rule.h b/filter/filter-rule.h index 425d0ac350..e1d5655050 100644 --- a/filter/filter-rule.h +++ b/filter/filter-rule.h @@ -49,9 +49,9 @@ enum _filter_source_t { struct _FilterRule { GtkObject parent; struct _FilterRulePrivate *priv; - + char *name; - + enum _filter_grouping_t grouping; enum _filter_source_t source; GList *parts; @@ -59,15 +59,15 @@ struct _FilterRule { 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 */ }; |