diff options
-rw-r--r-- | filter/ChangeLog | 11 | ||||
-rw-r--r-- | filter/filter-message-search.c | 122 | ||||
-rw-r--r-- | filter/filtertypes.xml | 79 | ||||
-rw-r--r-- | filter/libfilter-i18n.h | 3 |
4 files changed, 183 insertions, 32 deletions
diff --git a/filter/ChangeLog b/filter/ChangeLog index 5a0052a97d..b35fc305f2 100644 --- a/filter/ChangeLog +++ b/filter/ChangeLog @@ -1,3 +1,14 @@ +2000-10-25 Jeffrey Stedfast <fejj@helixcode.com> + + * filtertypes.xml: Added option menu items to allow searching + based on regular expressions. + + * filter-message-search.c (body_regex): New callback to match text + in the body using regex. + (body_contains): Modified to only match using strstr. + (header_regex): New callback to match headers using regex. + (header_contains): Modified to only match using strstr. + 2000-10-24 Jeffrey Stedfast <fejj@helixcode.com> * filtertypes.xml: Take out the reference to "Source". diff --git a/filter/filter-message-search.c b/filter/filter-message-search.c index 8b90e273e6..a227af41c0 100644 --- a/filter/filter-message-search.c +++ b/filter/filter-message-search.c @@ -23,6 +23,7 @@ #include "filter-message-search.h" #include <e-util/e-sexp.h> #include <regex.h> +#include <string.h> typedef struct { CamelMimeMessage *message; @@ -33,8 +34,10 @@ typedef struct { /* ESExp callbacks */ static ESExpResult *header_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms); +static ESExpResult *header_regex (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 *body_regex (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); @@ -52,7 +55,9 @@ static struct { } symbols[] = { { "match-all", (ESExpFunc *) match_all, 0 }, { "body-contains", (ESExpFunc *) body_contains, 0 }, + { "body-regex", (ESExpFunc *) body_regex, 0 }, { "header-contains", (ESExpFunc *) header_contains, 0 }, + { "header-regex", (ESExpFunc *) header_regex, 0 }, { "user-tag", (ESExpFunc *) user_tag, 0 }, { "user-flag", (ESExpFunc *) user_flag, 0 }, { "get-sent-date", (ESExpFunc *) get_sent_date, 0 }, @@ -71,6 +76,31 @@ header_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterM 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) { + if (strstr (contents, match)) + matched = TRUE; + } + } + + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = matched; + + return r; +} + +static ESExpResult * +header_regex (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; regex_t regexpat; /* regex patern */ regmatch_t *fltmatch; gint regerr = 0; @@ -127,7 +157,7 @@ match_all (struct _ESExp *f, int argc, struct _ESExpTerm **argv, FilterMessageSe } static gboolean -mime_part_matches (CamelMimePart *mime_part, const char *match, CamelException *ex) +mime_part_matches (CamelMimePart *mime_part, const char *match, gboolean regex, CamelException *ex) { CamelStream *stream; GByteArray *array; @@ -142,38 +172,46 @@ mime_part_matches (CamelMimePart *mime_part, const char *match, CamelException * array = g_byte_array_new (); stream = camel_stream_mem_new_with_byte_array (array); camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (mime_part), stream); - camel_stream_reset (stream); + camel_object_unref (CAMEL_OBJECT (stream)); + g_byte_array_append (array, "", 1); text = 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 (ex, CAMEL_EXCEPTION_SYSTEM, - "Failed to perform regex search on message body: %s", - regmsg); - g_free (regmsg); - regfree (®expat); + if (regex) { + 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 (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, text, regexpat.re_nsub, fltmatch, 0)) + matched = TRUE; + + g_free (fltmatch); + regfree (®expat); + } } else { - fltmatch = g_new0 (regmatch_t, regexpat.re_nsub); - - if (!regexec (®expat, text, regexpat.re_nsub, fltmatch, 0)) + if (strstr (text, match)) matched = TRUE; - - g_free (fltmatch); - regfree (®expat); } + g_byte_array_free (array, TRUE); + return matched; } static gboolean -handle_multipart (CamelMultipart *multipart, const char *match, CamelException *ex) +handle_multipart (CamelMultipart *multipart, const char *match, gboolean regex, CamelException *ex) { gboolean matched = FALSE; int i, nparts; @@ -189,7 +227,7 @@ handle_multipart (CamelMultipart *multipart, const char *match, CamelException * if (gmime_content_field_is_type (content, "text", "*")) { /* we only want to match text parts */ - matched = mime_part_matches (mime_part, match, ex); + matched = mime_part_matches (mime_part, match, regex, ex); if (camel_exception_is_set (ex)) break; @@ -200,7 +238,7 @@ handle_multipart (CamelMultipart *multipart, const char *match, CamelException * wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part)); mpart = CAMEL_MULTIPART (wrapper); - matched = handle_multipart (mpart, match, ex); + matched = handle_multipart (mpart, match, regex, ex); if (camel_exception_is_set (ex)) break; @@ -231,10 +269,44 @@ body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMes wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (CAMEL_MIME_PART (fms->message))); multipart = CAMEL_MULTIPART (wrapper); - matched = handle_multipart (multipart, match, fms->ex); + matched = handle_multipart (multipart, match, FALSE, fms->ex); + } else { + /* single-part message so just search the entire message */ + matched = mime_part_matches (CAMEL_MIME_PART (fms->message), match, FALSE, fms->ex); + } + } + + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = matched; + + return r; +} + +static ESExpResult * +body_regex (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) +{ + gboolean matched = FALSE; + ESExpResult *r; + + if (argc > 0) { + GMimeContentField *content; + char *match; + + match = (*argv)->value.string; + + content = camel_mime_part_get_content_type (CAMEL_MIME_PART (fms->message)); + + if (gmime_content_field_is_type (content, "multipart", "*")) { + CamelDataWrapper *wrapper; + CamelMultipart *multipart; + + wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (CAMEL_MIME_PART (fms->message))); + multipart = CAMEL_MULTIPART (wrapper); + + matched = handle_multipart (multipart, match, TRUE, fms->ex); } else { /* single-part message so just search the entire message */ - matched = mime_part_matches (CAMEL_MIME_PART (fms->message), match, fms->ex); + matched = mime_part_matches (CAMEL_MIME_PART (fms->message), match, TRUE, fms->ex); } } diff --git a/filter/filtertypes.xml b/filter/filtertypes.xml index 930db4fc2a..6417ef261c 100644 --- a/filter/filtertypes.xml +++ b/filter/filtertypes.xml @@ -2,15 +2,31 @@ <filterdescription> <partset> <part name="sender"> - <title>Sender</title> + <title>Sender</title> <input type="optionlist" name="sender-type"> <option value="contains"> - <title>contains</title> - <code>(match-all (header-contains "From" ${sender}))</code> + <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> + <title>does not contain</title> + <code> + (match-all (not (header-contains "From" ${sender}))) + </code> + </option> + <option value="matches regex"> + <title>matches regex</title> + <code> + (match-all (header-regex "From" ${sender})) + </code> + </option> + <option value="not match regex"> + <title>does not match regex</title> + <code> + (match-all (not (header-regex "From" ${sender}))) + </code> </option> </input> <input type="string" name="sender"/> @@ -34,6 +50,21 @@ (header-contains "Cc" ${recipient})))) </code> </option> + <option value="matches regex"> + <title>matches regex</title> + <code> + (match-all (or (header-regex "To" ${recipient}) + (header-regex "Cc" ${recipient}))) + </code> + </option> + <option value="not match regex"> + <title>does not match regex</title> + <code> + (match-all (not (or + (header-regex "To" ${recipient}) + (header-regex "Cc" ${recipient})))) + </code> + </option> </input> <input type="address" name="recipient"/> </part> @@ -53,6 +84,18 @@ (match-all (not (header-contains "Subject" ${subject}))) </code> </option> + <option value="matches regex"> + <title>matches regex</title> + <code> + (match-all (header-regex "Subject" ${subject})) + </code> + </option> + <option value="not match regex"> + <title>does not match regex</title> + <code> + (match-all (not (header-regex "Subject" ${subject})) + </code> + </option> </input> <input type="string" name="subject"/> </part> @@ -73,6 +116,18 @@ (match-all (not (header-contains ${header-field} ${word}))) </code> </option> + <option value="matches regex"> + <title>matches regex</title> + <code> + (match-all (header-regex ${header-field} ${word})) + </code> + </option> + <option value="not match regex"> + <title>does not match regex</title> + <code> + (match-all (not (header-regex ${header-field} ${word})) + </code> + </option> </input> <input type="string" name="word"/> </part> @@ -89,7 +144,19 @@ <option value="not contains"> <title>does not contain</title> <code> - (not (body-contains "Subject" ${word})) + (not (body-contains ${word})) + </code> + </option> + <option value="matches regex"> + <title>matches regex</title> + <code> + (body-regex ${word}) + </code> + </option> + <option value="not match regex"> + <title>does not match regex</title> + <code> + (not (body-regex ${word})) </code> </option> </input> diff --git a/filter/libfilter-i18n.h b/filter/libfilter-i18n.h index 25391215ad..c998d4ba0e 100644 --- a/filter/libfilter-i18n.h +++ b/filter/libfilter-i18n.h @@ -14,7 +14,6 @@ char *s = N_("Move to Folder"); char *s = N_("Priority"); char *s = N_("Recipients"); char *s = N_("Sender"); -char *s = N_("Source"); char *s = N_("Specific header"); char *s = N_("Stop Processing"); char *s = N_("Subject"); @@ -22,10 +21,12 @@ char *s = N_("after"); char *s = N_("before"); char *s = N_("contains"); char *s = N_("does not contain"); +char *s = N_("does not match regex"); char *s = N_("is greater than"); char *s = N_("is less than"); char *s = N_("is not"); char *s = N_("is"); +char *s = N_("matches regex"); char *s = N_("on or after"); char *s = N_("on or before"); char *s = N_("was after"); |