[339] in BarnOwl Developers
[D-O-H] r484 - in trunk: . owl owl/perl/modules
daemon@ATHENA.MIT.EDU (nelhage@MIT.EDU)
Thu Oct 29 18:05:05 2009
Resent-From: nelhage@mit.edu
Resent-To: barnowl-dev-mtg@charon.mit.edu
To: dirty-owl-hackers@mit.edu
From: nelhage@MIT.EDU
Reply-to: dirty-owl-hackers@MIT.EDU
Date: Tue, 26 Dec 2006 01:05:26 -0500 (EST)
Author: nelhage
Date: 2006-12-26 01:05:26 -0500 (Tue, 26 Dec 2006)
New Revision: 484
Modified:
trunk/
trunk/owl/filter.c
trunk/owl/filterelement.c
trunk/owl/global.c
trunk/owl/owl.c
trunk/owl/owl.h
trunk/owl/perl/modules/jabber.pl
trunk/owl/regex.c
trunk/owl/tester.c
Log:
r15874@phanatique: nelhage | 2006-12-24 18:25:33 -0500
Don't quit if we can't contact the hostmaster.
r15884@phanatique: nelhage | 2006-12-24 18:56:03 -0500
Respect the displayoutgoing variable
r15885@phanatique: nelhage | 2006-12-24 20:10:44 -0500
You can now write filters based off arbitrary message attributes
r15887@phanatique: nelhage | 2006-12-24 22:59:39 -0500
r15886@phanatique (orig r476): nelhage | 2006-12-24 22:59:10 -0500
r24493@heretique: nelhage | 2006-12-24 22:59:02 -0500
Moving zephyr initialization later, so that zephyr works again
r15891@phanatique: nelhage | 2006-12-25 14:40:08 -0500
* perl messages hashes use `private', not `isprivate'
* get rid of a perl warning if login fails
r15900@phanatique: nelhage | 2006-12-25 21:04:15 -0500
Merging in filter regression tests from my local branch.
r15926@phanatique: nelhage | 2006-12-26 00:57:07 -0500
r15901@phanatique: nelhage | 2006-12-25 21:08:47 -0500
Base framework for the filter rewrite system. Only understands regexes and true/false so far.
r15927@phanatique: nelhage | 2006-12-26 00:57:08 -0500
r15902@phanatique: nelhage | 2006-12-25 23:03:33 -0500
support for negation and parentheses
r15928@phanatique: nelhage | 2006-12-26 00:57:08 -0500
r15924@phanatique: nelhage | 2006-12-26 00:16:30 -0500
Now passing all tests except for recursion detection
r15929@phanatique: nelhage | 2006-12-26 00:57:08 -0500
r15925@phanatique: nelhage | 2006-12-26 00:52:09 -0500
Checking for filter recursion loops
Property changes on: trunk
___________________________________________________________________
Name: svk:merge
- bb873fd7-8e23-0410-944a-99ec44c633eb:/local/d-o-h/trunk:15872
+ bb873fd7-8e23-0410-944a-99ec44c633eb:/branches/owl/filter-rewrite:15925
bb873fd7-8e23-0410-944a-99ec44c633eb:/local/d-o-h/trunk:15935
Modified: trunk/owl/filter.c
===================================================================
--- trunk/owl/filter.c 2006-12-26 06:00:43 UTC (rev 483)
+++ trunk/owl/filter.c 2006-12-26 06:05:26 UTC (rev 484)
@@ -18,17 +18,11 @@
int owl_filter_init(owl_filter *f, char *name, int argc, char **argv)
{
- int i, j, error;
- owl_filterelement *fe;
- char *regexstr;
- owl_list list;
-
f->name=owl_strdup(name);
f->polarity=0;
f->color=OWL_COLOR_DEFAULT;
f->cachedmsgid=-1;
- owl_list_create(&(f->fes));
-
+
/* first take arguments that have to come first */
/* set the color */
if (argc>=2 && !strcmp(argv[0], "-c")) {
@@ -40,78 +34,115 @@
argc-=2;
argv+=2;
}
-
- /* then deal with the expression */
- for (i=0; i<argc; i++) {
- error=0;
- fe=owl_malloc(sizeof(owl_filterelement));
-
- /* all the 0 argument possibilities */
- if (!strcmp(argv[i], "(")) {
- owl_filterelement_create_openbrace(fe);
- } else if (!strcmp(argv[i], ")")) {
- owl_filterelement_create_closebrace(fe);
- } else if (!strcasecmp(argv[i], "and")) {
- owl_filterelement_create_and(fe);
- } else if (!strcasecmp(argv[i], "or")) {
- owl_filterelement_create_or(fe);
- } else if (!strcasecmp(argv[i], "not")) {
- owl_filterelement_create_not(fe);
- } else if (!strcasecmp(argv[i], "true")) {
- owl_filterelement_create_true(fe);
- } else if (!strcasecmp(argv[i], "false")) {
- owl_filterelement_create_false(fe);
-
- } else if (i==argc-1) { /* we need more than one arg at this point */
- error=1;
- } else {
- if (!strcasecmp(argv[i], "filter")) {
- owl_filterelement_create_filter(fe, argv[i+1]);
- i++;
- } else if (!strcasecmp(argv[i], "perl")) {
- owl_filterelement_create_perl(fe, argv[i+1]);
- i++;
- } else {
- regexstr=owl_text_substitute(argv[i+1], "%me%", owl_zephyr_get_sender());
- owl_filterelement_create_re(fe, argv[i], regexstr);
- owl_free(regexstr);
- i++;
- }
- }
- if (!error) {
- owl_list_append_element(&(f->fes), fe);
- } else {
- owl_free(fe);
- owl_filter_free(f);
- return(-1);
- }
- }
-
- /* Are we trying to use the filter we're creating? Bad. */
- owl_list_create(&list);
- _owl_filter_get_subfilter_names(f, &list);
- j=owl_list_get_size(&list);
- for (i=0; i<j; i++) {
- if (!strcasecmp(name, owl_list_get_element(&list, i))) {
- owl_function_error("Filter loop.");
- owl_filter_free(f);
- owl_list_free_all(&list, owl_free);
- return(-1);
- }
- }
- owl_list_free_all(&list, owl_free);
+ if(!(f->root = owl_filter_parse_expression(argc, argv, NULL)))
+ return(-1);
- /* Now check for more subtle recursion. */
+ /* Now check for recursion. */
if (owl_filter_is_toodeep(f)) {
owl_function_error("Filter loop or exceeds recursion depth");
owl_filter_free(f);
return(-1);
}
-
+
return(0);
}
+
+/* A primitive expression is one without any toplevel ``and'' or ``or''s*/
+
+static owl_filterelement * owl_filter_parse_primitive_expression(int argc, char **argv, int *next)
+{
+ if(!argc) return NULL;
+
+ owl_filterelement * fe = owl_malloc(sizeof(owl_filterelement));
+ owl_filterelement *op;
+
+ owl_filterelement_create(fe);
+ int i = 0, skip;
+
+ if(!strcasecmp(argv[i], "(")) {
+ i++;
+ op = owl_filter_parse_expression(argc-i, argv+i, &skip);
+ if(!op) goto err;
+ i += skip;
+ if(strcasecmp(argv[i++], ")")) goto err;
+ owl_filterelement_create_group(fe, op);
+ } else if(!strcasecmp(argv[i], "not")) {
+ i++;
+ op = owl_filter_parse_primitive_expression(argc-i, argv+i, &skip);
+ if(!op) goto err;
+ i += skip;
+ owl_filterelement_create_not(fe, op);
+ } else if(!strcasecmp(argv[i], "true")) {
+ i++;
+ owl_filterelement_create_true(fe);
+ } else if(!strcasecmp(argv[i], "false")) {
+ i++;
+ owl_filterelement_create_false(fe);
+ } else {
+ if(argc == 1) goto err;
+ if(!strcasecmp(*argv, "filter")) {
+ owl_filterelement_create_filter(fe, *(argv+1));
+ } else if(!strcasecmp(*argv, "perl")) {
+ owl_filterelement_create_perl(fe, *(argv+1));
+ } else {
+ owl_filterelement_create_re(fe, *argv, *(argv+1));
+ }
+ i += 2;
+ }
+
+ if(next) {
+ *next = i;
+ } else if(i != argc) {
+ goto err;
+ }
+ return fe;
+err:
+ owl_filterelement_free(fe);
+ owl_free(fe);
+ return NULL;
+}
+
+owl_filterelement * owl_filter_parse_expression(int argc, char **argv, int *next)
+{
+ int i = 0, skip;
+ owl_filterelement * op1 = NULL, * op2 = NULL;
+
+ op1 = owl_filter_parse_primitive_expression(argc-i, argv+i, &skip);
+ i += skip;
+ if(!op1) goto err;
+
+ while(i < argc) {
+ if(strcasecmp(argv[i], "and") &&
+ strcasecmp(argv[i], "or")) break;
+ op2 = owl_filter_parse_primitive_expression(argc-i-1, argv+i+1, &skip);
+ if(!op2) goto err;
+ owl_filterelement * tmp = owl_malloc(sizeof(owl_filterelement));
+ if(!strcasecmp(argv[i], "and")) {
+ owl_filterelement_create_and(tmp, op1, op2);
+ } else {
+ owl_filterelement_create_or(tmp, op1, op2);
+ }
+ op1 = tmp;
+ op2 = NULL;
+ i += skip+1;
+ }
+
+ if(next) {
+ *next = i;
+ } else if(i != argc) {
+ goto err;
+ }
+ return op1;
+err:
+ if(op1) {
+ owl_filterelement_free(op1);
+ owl_free(op1);
+ }
+ return NULL;
+}
+
char *owl_filter_get_name(owl_filter *f)
{
return(f->name);
@@ -152,318 +183,18 @@
*/
int owl_filter_message_match(owl_filter *f, owl_message *m)
{
- int i, j, tmp;
- owl_list work_fes, *fes;
- owl_filterelement *fe;
- char *field, *match;
-
- /* create the working list of expression elements */
- fes=&(f->fes);
- owl_list_create(&work_fes);
- j=owl_list_get_size(fes);
- for (i=0; i<j; i++) {
- owl_list_append_element(&work_fes, owl_list_get_element(fes, i));
- }
-
- /* first go thru and evaluate all RE elements to true or false */
- match="";
- for (i=0; i<j; i++) {
- fe=owl_list_get_element(&work_fes, i);
- if (!owl_filterelement_is_re(fe)) continue;
- field=owl_filterelement_get_field(fe);
- if (!strcasecmp(field, "class")) {
- match=owl_message_get_class(m);
- } else if (!strcasecmp(field, "instance")) {
- match=owl_message_get_instance(m);
- } else if (!strcasecmp(field, "sender")) {
- match=owl_message_get_sender(m);
- } else if (!strcasecmp(field, "recipient")) {
- match=owl_message_get_recipient(m);
- } else if (!strcasecmp(field, "body")) {
- match=owl_message_get_body(m);
- } else if (!strcasecmp(field, "opcode")) {
- match=owl_message_get_opcode(m);
- } else if (!strcasecmp(field, "realm")) {
- match=owl_message_get_realm(m);
- } else if (!strcasecmp(field, "type")) {
- match=owl_message_get_type(m);
- } else if (!strcasecmp(field, "hostname")) {
- match=owl_message_get_hostname(m);
- } else if (!strcasecmp(field, "direction")) {
- if (owl_message_is_direction_out(m)) {
- match="out";
- } else if (owl_message_is_direction_in(m)) {
- match="in";
- } else if (owl_message_is_direction_none(m)) {
- match="none";
- } else {
- match="";
- }
- } else if (!strcasecmp(field, "login")) {
- if (owl_message_is_login(m)) {
- match="login";
- } else if (owl_message_is_logout(m)) {
- match="logout";
- } else {
- match="none";
- }
- } else {
- match = owl_message_get_attribute_value(m,field);
- if(match == NULL) match = "";
- }
-
- tmp=owl_regex_compare(owl_filterelement_get_re(fe), match);
- if (!tmp) {
- owl_list_replace_element(&work_fes, i, owl_global_get_filterelement_true(&g));
- } else {
- owl_list_replace_element(&work_fes, i, owl_global_get_filterelement_false(&g));
- }
- }
-
- /* now subfilters and perl functions */
- for (i=0; i<j; i++) {
- owl_filter *subfilter;
-
- fe=owl_list_get_element(&work_fes, i);
-
- if (owl_filterelement_is_filter(fe)) {
-
- subfilter=owl_global_get_filter(&g, owl_filterelement_get_filtername(fe));
- if (!subfilter) {
- /* the filter does not exist, maybe because it was deleted.
- * Default to not matching
- */
- owl_list_replace_element(&work_fes, i, owl_global_get_filterelement_false(&g));
- } else if (owl_filter_message_match(subfilter, m)) {
- owl_list_replace_element(&work_fes, i, owl_global_get_filterelement_true(&g));
- } else {
- owl_list_replace_element(&work_fes, i, owl_global_get_filterelement_false(&g));
- }
-
- } else if (owl_filterelement_is_perl(fe)) {
- char *subname, *perlrv;
- int tf=0;
-
- subname = owl_filterelement_get_filtername(fe);
- if (!owl_perlconfig_is_function(subname)) {
- owl_list_replace_element(&work_fes, i, owl_global_get_filterelement_false(&g));
- continue;
- }
- perlrv = owl_perlconfig_call_with_message(subname, m);
- if (perlrv) {
- if (0 == strcmp(perlrv, "1")) {
- tf=1;
- }
- owl_free(perlrv);
- }
- if (tf) {
- owl_list_replace_element(&work_fes, i, owl_global_get_filterelement_true(&g));
- } else {
- owl_list_replace_element(&work_fes, i, owl_global_get_filterelement_false(&g));
- }
- }
- }
-
- /* call the recrsive helper */
- i=_owl_filter_message_match_recurse(f, m, &work_fes, 0, owl_list_get_size(&(f->fes))-1);
-
- /* now there will be only one TRUE / FALSE, find it among the NULL's */
- tmp=0;
- for (i=0; i<j; i++) {
- fe=owl_list_get_element(&work_fes, i);
- if (owl_filterelement_is_null(fe)) continue;
- if (owl_filterelement_is_true(fe)) {
- tmp=1;
- break;
- }
- if (owl_filterelement_is_false(fe)) {
- tmp=0;
- break;
- }
- }
-
- /* reverse the answer if negative polarity is in use */
- if (f->polarity) tmp=!tmp;
-
- owl_list_free_simple(&work_fes);
- return(tmp);
+ if(!f->root) return 0;
+ int ret = owl_filterelement_match(f->root, m);
+ if(f->polarity) ret = !ret;
+ return ret;
}
-int _owl_filter_message_match_recurse(owl_filter *f, owl_message *m, owl_list *fes, int start, int end)
-{
- int a=0, b=0, i, x, y, z, score, ret, type;
- owl_filterelement *fe, *tmpfe=NULL;
- /* Deal with parens first. */
- for (i=0; i<OWL_FILTER_MAX_DEPTH; i++) {
- /* Find first open paren and matching close paren, store in x, y */
- score=x=y=0;
- for (i=start; i<=end; i++) {
- fe=owl_list_get_element(fes, i);
- if (owl_filterelement_is_openbrace(fe)) {
- if (score==0) x=i;
- score++;
- } else if (owl_filterelement_is_closebrace(fe)) {
- score--;
- if (score<0) {
- /* unblanaced parens */
- return(-1);
- } else if (score==0) {
- y=i; /* this is the matching close paren */
- break;
- }
- }
- }
- if (score>0) {
- /* unblanaced parens */
- return(-1);
- }
-
- /* Simply the parens by removing them and evaluating what was in between */
- if (y>0) {
- /* null out the parens */
- owl_list_replace_element(fes, x, owl_global_get_filterelement_null(&g));
- owl_list_replace_element(fes, y, owl_global_get_filterelement_null(&g));
-
- /* evaluate expression in between */
- ret=_owl_filter_message_match_recurse(f, m, fes, x+1, y-1);
- if (ret<0) return(-1);
-
- /* there may be more, so we continue */
- continue;
- } else {
- /* otherwise we're done with this part */
- break;
- }
- }
- if (i==OWL_FILTER_MAX_DEPTH) {
- /* hit the saftey limit, consider it invalid */
- return(-1);
- }
-
- /* Find AND / OR / NOT.
- * For binary expressions (AND/OR):
- * "type" is 1
- * "x" will index first val, "y" the operator and "z" the second val
- * For unary expressions (NOT):
- * "type" is 2
- * "x" will index the operator, "y" the value
- * "score" tallys how many expression elements have been found so far
- */
- for (i=0; i<OWL_FILTER_MAX_DEPTH; i++) {
- type=score=x=y=z=0;
- for (i=start; i<=end; i++) {
- fe=owl_list_get_element(fes, i);
- if (owl_filterelement_is_null(fe)) continue;
- if (score==0) {
- if (owl_filterelement_is_value(fe)) {
- x=i;
- score=1;
- type=1;
- } else if (owl_filterelement_is_not(fe)) {
- x=i;
- score=1;
- type=2;
- }
- } else if (score==1) {
- if (type==1) {
- if (owl_filterelement_is_and(fe) || owl_filterelement_is_or(fe)) {
- score=2;
- y=i;
- } else {
- /* it's not a valid binary expression */
- x=y=z=score=0;
- }
- } else if (type==2) {
- if (owl_filterelement_is_value(fe)) {
- /* valid unary expression, we're done */
- y=i;
- break;
- }
- }
- } else if (score==2) {
- if (owl_filterelement_is_value(fe)) {
- /* valid binary expression, we're done */
- z=i;
- break;
- } else {
- x=y=z=score=0;
- }
- }
- }
-
- /* simplify AND / OR */
- if ((type==1) && (z>0)) {
- fe=owl_list_get_element(fes, x);
- if (owl_filterelement_is_true(fe)) {
- a=1;
- } else if (owl_filterelement_is_false(fe)) {
- a=0;
- }
-
- fe=owl_list_get_element(fes, z);
- if (owl_filterelement_is_true(fe)) {
- b=1;
- } else if (owl_filterelement_is_false(fe)) {
- b=0;
- }
-
- fe=owl_list_get_element(fes, y);
- if (owl_filterelement_is_and(fe)) {
- if (a && b) {
- tmpfe=owl_global_get_filterelement_true(&g);
- } else {
- tmpfe=owl_global_get_filterelement_false(&g);
- }
- } else if (owl_filterelement_is_or(fe)) {
- if (a || b) {
- tmpfe=owl_global_get_filterelement_true(&g);
- } else {
- tmpfe=owl_global_get_filterelement_false(&g);
- }
- }
- owl_list_replace_element(fes, x, owl_global_get_filterelement_null(&g));
- owl_list_replace_element(fes, y, tmpfe);
- owl_list_replace_element(fes, z, owl_global_get_filterelement_null(&g));
- } else if ((type==2) && (y>0)) {
- /* simplify NOT */
- fe=owl_list_get_element(fes, y);
- owl_list_replace_element(fes, x, owl_global_get_filterelement_null(&g));
- if (owl_filterelement_is_false(fe)) {
- owl_list_replace_element(fes, y, owl_global_get_filterelement_true(&g));
- } else {
- owl_list_replace_element(fes, y, owl_global_get_filterelement_false(&g));
- }
- } else {
- break;
- }
- }
- return(0);
-
-}
-
void owl_filter_print(owl_filter *f, char *out)
{
- int i, j;
- owl_filterelement *fe;
- char *tmp;
-
- strcpy(out, owl_filter_get_name(f));
- strcat(out, ": ");
-
- if (f->color!=OWL_COLOR_DEFAULT) {
- strcat(out, "-c ");
- strcat(out, owl_util_color_to_string(f->color));
- strcat(out, " ");
- }
-
- j=owl_list_get_size(&(f->fes));
- for (i=0; i<j; i++) {
- fe=owl_list_get_element(&(f->fes), i);
- tmp=owl_filterelement_to_string(fe);
- strcat(out, tmp);
- owl_free(tmp);
- }
+ strcpy(out, "");
+ if(!f->root) return;
+ owl_filterelement_print(f->root, out);
strcat(out, "\n");
}
@@ -479,108 +210,110 @@
return(0);
}
-/* Private
- * 'list' should already be allocated and initialized
- * This function places into list the string names of all filters
- * used in the filter expression for 'f'.
- * Caller must do a full free on 'list', including elements.
- */
-void _owl_filter_get_subfilter_names(owl_filter *f, owl_list *list)
+
+int owl_filter_is_toodeep(owl_filter *f)
{
- int i, j;
- owl_filterelement *fe;
+ return owl_filterelement_is_toodeep(f, f->root);
+}
- j=owl_list_get_size(&(f->fes));
- for (i=0; i<j; i++) {
- fe=owl_list_get_element(&(f->fes), i);
- if (owl_filterelement_is_filter(fe)) {
- owl_list_append_element(list, owl_strdup(owl_filterelement_get_filtername(fe)));
- }
+void owl_filter_free(owl_filter *f)
+{
+ if(f->root) {
+ owl_filterelement_free(f->root);
+ owl_free(f->root);
}
+ if (f->name) owl_free(f->name);
}
-int owl_filter_is_toodeep(owl_filter *f)
-{
- owl_list seen, tocheck, tmp;
- int i, j, x, y;
- owl_filter *subfilter;
+/**************************************************************************/
+/************************* REGRESSION TESTS *******************************/
+/**************************************************************************/
- owl_list_create(&seen);
- owl_list_create(&tocheck);
- owl_list_create(&tmp);
+#ifdef OWL_INCLUDE_REG_TESTS
- /* seed 'tocheck' with the first set of filters */
- _owl_filter_get_subfilter_names(f, &tmp);
- j=owl_list_get_size(&tmp);
- for (i=0; i<j; i++) {
- owl_util_list_add_unique_string(&tocheck, owl_list_get_element(&tmp, i));
+int owl_filter_test_string(char * filt, owl_message *m, int shouldmatch) /* noproto */ {
+ owl_filter f;
+ int ok;
+ int failed = 0;
+ if(owl_filter_init_fromstring(&f, "test-filter", filt)) {
+ printf("\tFAIL: parse %s\n", filt);
+ failed = 1;
+ goto out;
}
- owl_list_free_all(&tmp, owl_free);
- owl_list_create(&tmp);
+ ok = owl_filter_message_match(&f, m);
+ if((shouldmatch && !ok) || (!shouldmatch && ok)) {
+ printf("\tFAIL: match %s (got %d, expected %d)\n", filt, ok, shouldmatch);
+ failed = 1;
+ }
+ out:
+ owl_filter_free(&f);
+ if(!failed) {
+ printf("\tok : %s %s\n", shouldmatch ? "matches" : "doesn't match", filt);
+ }
+ return failed;
+}
- /* add this list to the 'seen' list */
- owl_list_append_element(&seen, owl_strdup(owl_filter_get_name(f)));
- for (i=0; i<OWL_FILTER_MAXRECURSE; i++) {
- /* if anything in 'tocheck' is in 'seen' we have a loop */
- if (owl_util_common_strings_in_lists(&tocheck, &seen)) {
- owl_list_free_all(&tmp, owl_free);
- owl_list_free_all(&tocheck, owl_free);
- owl_list_free_all(&seen, owl_free);
- return(1);
- }
+#include "test.h"
- /* if there's nothing to check, we're done */
- y=owl_list_get_size(&tocheck);
- if (y==0) {
- owl_list_free_all(&tmp, owl_free);
- owl_list_free_all(&tocheck, owl_free);
- owl_list_free_all(&seen, owl_free);
- return(0);
- }
- /* add everything in 'tocheck' to the 'seen' list */
- /* y=owl_list_get_size(&tocheck); */
- for (x=0; x<y; x++) {
- owl_list_append_element(&seen, owl_strdup(owl_list_get_element(&tocheck, x)));
- }
+int owl_filter_regtest(void) {
+ owl_list_create(&(g.filterlist));
+ int numfailed=0;
+ owl_message m;
+ owl_message_init(&m);
+ owl_message_set_type_zephyr(&m);
+ owl_message_set_direction_in(&m);
+ owl_message_set_class(&m, "owl");
+ owl_message_set_instance(&m, "tester");
+ owl_message_set_sender(&m, "owl-user");
+ owl_message_set_recipient(&m, "joe");
+ owl_message_set_attribute(&m, "foo", "bar");
- /* make a new list into 'tmp' with the children of 'tocheck' */
- /* y=owl_list_get_size(&tocheck); */
- for (x=0; x<y; x++) {
- subfilter=owl_global_get_filter(&g, owl_list_get_element(&tocheck, x));
- if (!subfilter) return(0);
- _owl_filter_get_subfilter_names(subfilter, &tmp);
- }
+#define TEST_FILTER(f, e) numfailed += owl_filter_test_string(f, &m, e)
- /* clean out 'tocheck' */
- owl_list_free_all(&tocheck, owl_free);
- owl_list_create(&tocheck);
- /* put 'tmp' into 'tocheck' */
- y=owl_list_get_size(&tmp);
- for (x=0; x<y; x++) {
- owl_util_list_add_unique_string(&tocheck, owl_list_get_element(&tmp, x));
- }
+ TEST_FILTER("true", 1);
+ TEST_FILTER("false", 0);
+ TEST_FILTER("( true )", 1);
+ TEST_FILTER("not false", 1);
+ TEST_FILTER("( true ) or ( false )", 1);
+ TEST_FILTER("true and false", 0);
+ TEST_FILTER("( true or true ) or ( ( false ) )", 1);
- /* clean out 'tmp' */
- owl_list_free_all(&tmp, owl_free);
- owl_list_create(&tmp);
- }
+ TEST_FILTER("class owl", 1);
+ TEST_FILTER("class ^owl$", 1);
+ TEST_FILTER("instance test", 1);
+ TEST_FILTER("instance ^test$", 0);
+ TEST_FILTER("instance ^tester$", 1);
- owl_list_free_all(&tmp, owl_free);
- owl_list_free_all(&tocheck, owl_free);
- owl_list_free_all(&seen, owl_free);
+ TEST_FILTER("foo bar", 1);
+ TEST_FILTER("class owl and instance tester", 1);
+ TEST_FILTER("type ^zephyr$ and direction ^in$ and ( class ^owl$ or instance ^owl$ )", 1);
- return(1);
-}
+ // Order of operations and precedence
+ TEST_FILTER("not true or false", 0);
+ TEST_FILTER("true or true and false", 0);
+ TEST_FILTER("true and true and false or true", 1);
+ TEST_FILTER("false and false or true", 1);
+ TEST_FILTER("true and false or false", 0);
-void owl_filter_free(owl_filter *f)
-{
- void (*func)();
+ owl_filter f1, f2, f3, f4;
- func=&owl_filterelement_free;
-
- if (f->name) owl_free(f->name);
- owl_list_free_all(&(f->fes), func);
+ owl_filter_init_fromstring(&f1, "f1", "class owl");
+ owl_global_add_filter(&g, &f1);
+ TEST_FILTER("filter f1", 1);
+
+ // Test recursion prevention
+ FAIL_UNLESS("self reference", owl_filter_init_fromstring(&f2, "test", "filter test"));
+
+ // mutual recursion
+ owl_filter_init_fromstring(&f3, "f3", "filter f4");
+ owl_global_add_filter(&g, &f3);
+ FAIL_UNLESS("mutual recursion", owl_filter_init_fromstring(&f4, "f4", "filter f3"));
+
+ return 0;
}
+
+
+#endif /* OWL_INCLUDE_REG_TESTS */
Modified: trunk/owl/filterelement.c
===================================================================
--- trunk/owl/filterelement.c 2006-12-26 06:00:43 UTC (rev 483)
+++ trunk/owl/filterelement.c 2006-12-26 06:05:26 UTC (rev 484)
@@ -2,214 +2,320 @@
static const char fileIdent[] = "$Id$";
-#define OWL_FILTERELEMENT_NULL 0
-#define OWL_FILTERELEMENT_TRUE 1
-#define OWL_FILTERELEMENT_FALSE 2
-#define OWL_FILTERELEMENT_OPENBRACE 3
-#define OWL_FILTERELEMENT_CLOSEBRACE 4
-#define OWL_FILTERELEMENT_AND 5
-#define OWL_FILTERELEMENT_OR 6
-#define OWL_FILTERELEMENT_NOT 7
-#define OWL_FILTERELEMENT_RE 8
-#define OWL_FILTERELEMENT_FILTER 9
-#define OWL_FILTERELEMENT_PERL 10
+static char * owl_filterelement_get_field(owl_message *m, char * field)
+{
+ char *match;
+ if (!strcasecmp(field, "class")) {
+ match=owl_message_get_class(m);
+ } else if (!strcasecmp(field, "instance")) {
+ match=owl_message_get_instance(m);
+ } else if (!strcasecmp(field, "sender")) {
+ match=owl_message_get_sender(m);
+ } else if (!strcasecmp(field, "recipient")) {
+ match=owl_message_get_recipient(m);
+ } else if (!strcasecmp(field, "body")) {
+ match=owl_message_get_body(m);
+ } else if (!strcasecmp(field, "opcode")) {
+ match=owl_message_get_opcode(m);
+ } else if (!strcasecmp(field, "realm")) {
+ match=owl_message_get_realm(m);
+ } else if (!strcasecmp(field, "type")) {
+ match=owl_message_get_type(m);
+ } else if (!strcasecmp(field, "hostname")) {
+ match=owl_message_get_hostname(m);
+ } else if (!strcasecmp(field, "direction")) {
+ if (owl_message_is_direction_out(m)) {
+ match="out";
+ } else if (owl_message_is_direction_in(m)) {
+ match="in";
+ } else if (owl_message_is_direction_none(m)) {
+ match="none";
+ } else {
+ match="";
+ }
+ } else if (!strcasecmp(field, "login")) {
+ if (owl_message_is_login(m)) {
+ match="login";
+ } else if (owl_message_is_logout(m)) {
+ match="logout";
+ } else {
+ match="none";
+ }
+ } else {
+ match = owl_message_get_attribute_value(m,field);
+ if(match == NULL) match = "";
+ }
-void owl_filterelement_create_null(owl_filterelement *fe)
+ return match;
+}
+
+static int owl_filterelement_match_false(owl_filterelement *fe, owl_message *m)
{
- fe->type=OWL_FILTERELEMENT_NULL;
- fe->field=NULL;
- fe->filtername=NULL;
+ return 0;
}
-void owl_filterelement_create_openbrace(owl_filterelement *fe)
+static int owl_filterelement_match_true(owl_filterelement *fe, owl_message *m)
{
- owl_filterelement_create_null(fe);
- fe->type=OWL_FILTERELEMENT_OPENBRACE;
+ return 1;
}
-void owl_filterelement_create_closebrace(owl_filterelement *fe)
+static int owl_filterelement_match_re(owl_filterelement *fe, owl_message *m)
{
- owl_filterelement_create_null(fe);
- fe->type=OWL_FILTERELEMENT_CLOSEBRACE;
+ char * val = owl_filterelement_get_field(m, fe->field);
+ return !owl_regex_compare(&(fe->re), val);
}
-void owl_filterelement_create_and(owl_filterelement *fe)
+static int owl_filterelement_match_filter(owl_filterelement *fe, owl_message *m)
{
- owl_filterelement_create_null(fe);
- fe->type=OWL_FILTERELEMENT_AND;
+ owl_filter *subfilter;
+ subfilter=owl_global_get_filter(&g, fe->field);
+ if (!subfilter) {
+ /* the filter does not exist, maybe because it was deleted.
+ * Default to not matching
+ */
+ return 0;
+ }
+ return owl_filter_message_match(subfilter, m);
}
-void owl_filterelement_create_or(owl_filterelement *fe)
+static int owl_filterelement_match_perl(owl_filterelement *fe, owl_message *m)
{
- owl_filterelement_create_null(fe);
- fe->type=OWL_FILTERELEMENT_OR;
+ char *subname, *perlrv;
+ int tf=0;
+
+ subname = fe->field;
+ if (!owl_perlconfig_is_function(subname)) {
+ return 0;
+ }
+ perlrv = owl_perlconfig_call_with_message(subname, m);
+ if (perlrv) {
+ if (0 == strcmp(perlrv, "1")) {
+ tf=1;
+ }
+ owl_free(perlrv);
+ }
+ return tf;
}
-void owl_filterelement_create_not(owl_filterelement *fe)
+static int owl_filterelement_match_group(owl_filterelement *fe, owl_message *m)
{
- owl_filterelement_create_null(fe);
- fe->type=OWL_FILTERELEMENT_NOT;
+ return owl_filterelement_match(fe->left, m);
}
-void owl_filterelement_create_true(owl_filterelement *fe)
+/* XXX: Our boolea operators short-circuit here. The original owl did
+ not. Do we care?
+*/
+
+static int owl_filterelement_match_and(owl_filterelement *fe, owl_message *m)
{
- owl_filterelement_create_null(fe);
- fe->type=OWL_FILTERELEMENT_TRUE;
+ return owl_filterelement_match(fe->left, m) &&
+ owl_filterelement_match(fe->right, m);
}
-void owl_filterelement_create_false(owl_filterelement *fe)
+static int owl_filterelement_match_or(owl_filterelement *fe, owl_message *m)
{
- owl_filterelement_create_null(fe);
- fe->type=OWL_FILTERELEMENT_FALSE;
+ return owl_filterelement_match(fe->left, m) ||
+ owl_filterelement_match(fe->right, m);
}
-void owl_filterelement_create_re(owl_filterelement *fe, char *field, char *re)
+static int owl_filterelement_match_not(owl_filterelement *fe, owl_message *m)
{
- owl_filterelement_create_null(fe);
- fe->type=OWL_FILTERELEMENT_RE;
- fe->field=owl_strdup(field);
- owl_regex_create(&(fe->re), re);
+ return !owl_filterelement_match(fe->left, m);
}
-void owl_filterelement_create_filter(owl_filterelement *fe, char *name)
+// Print methods
+
+static void owl_filterelement_print_true(owl_filterelement *fe, char *buf)
{
- owl_filterelement_create_null(fe);
- fe->type=OWL_FILTERELEMENT_FILTER;
- fe->filtername=owl_strdup(name);
+ strcat(buf, "true");
}
-void owl_filterelement_create_perl(owl_filterelement *fe, char *name)
+static void owl_filterelement_print_false(owl_filterelement *fe, char *buf)
{
- owl_filterelement_create_null(fe);
- fe->type=OWL_FILTERELEMENT_PERL;
- fe->filtername=owl_strdup(name);
+ strcat(buf, "false");
}
-void owl_filterelement_free(owl_filterelement *fe)
+static void owl_filterelement_print_re(owl_filterelement *fe, char *buf)
{
- if (fe->field) owl_free(fe->field);
- if (fe->filtername) owl_free(fe->filtername);
+ strcat(buf, fe->field);
+ strcat(buf, " ");
+ strcat(buf, owl_regex_get_string(&(fe->re)));
}
-int owl_filterelement_is_null(owl_filterelement *fe)
+static void owl_filterelement_print_filter(owl_filterelement *fe, char *buf)
{
- if (fe->type==OWL_FILTERELEMENT_NULL) return(1);
- return(0);
+ strcat(buf, "filter ");
+ strcat(buf, fe->field);
}
-int owl_filterelement_is_openbrace(owl_filterelement *fe)
+static void owl_filterelement_print_perl(owl_filterelement *fe, char *buf)
{
- if (fe->type==OWL_FILTERELEMENT_OPENBRACE) return(1);
- return(0);
+ strcat(buf, "perl ");
+ strcat(buf, fe->field);
}
-int owl_filterelement_is_closebrace(owl_filterelement *fe)
+static void owl_filterelement_print_group(owl_filterelement *fe, char *buf)
{
- if (fe->type==OWL_FILTERELEMENT_CLOSEBRACE) return(1);
- return(0);
+ strcat(buf, "( ");
+ owl_filterelement_print(fe->left, buf) ;
+ strcat(buf, " )");
}
-int owl_filterelement_is_and(owl_filterelement *fe)
+static void owl_filterelement_print_or(owl_filterelement *fe, char *buf)
{
- if (fe->type==OWL_FILTERELEMENT_AND) return(1);
- return(0);
+ owl_filterelement_print(fe->left, buf);
+ strcat(buf, " or ");
+ owl_filterelement_print(fe->right, buf);
}
-int owl_filterelement_is_or(owl_filterelement *fe)
+static void owl_filterelement_print_and(owl_filterelement *fe, char *buf)
{
- if (fe->type==OWL_FILTERELEMENT_OR) return(1);
- return(0);
+ owl_filterelement_print(fe->left, buf);
+ strcat(buf, " and ");
+ owl_filterelement_print(fe->right, buf);
}
-int owl_filterelement_is_not(owl_filterelement *fe)
+static void owl_filterelement_print_not(owl_filterelement *fe, char *buf)
{
- if (fe->type==OWL_FILTERELEMENT_NOT) return(1);
- return(0);
+ strcat(buf, " not ");
+ owl_filterelement_print(fe->left, buf);
}
-int owl_filterelement_is_true(owl_filterelement *fe)
+// Constructors
+
+void owl_filterelement_create(owl_filterelement *fe) {
+ fe->field = NULL;
+ fe->left = fe->right = NULL;
+ fe->match_message = NULL;
+ fe->print_elt = NULL;
+ owl_regex_init(&(fe->re));
+}
+
+
+void owl_filterelement_create_true(owl_filterelement *fe)
{
- if (fe->type==OWL_FILTERELEMENT_TRUE) return(1);
- return(0);
+ owl_filterelement_create(fe);
+ fe->match_message = owl_filterelement_match_true;
+ fe->print_elt = owl_filterelement_print_true;
}
-int owl_filterelement_is_false(owl_filterelement *fe)
+void owl_filterelement_create_false(owl_filterelement *fe)
{
- if (fe->type==OWL_FILTERELEMENT_FALSE) return(1);
- return(0);
+ owl_filterelement_create(fe);
+ fe->match_message = owl_filterelement_match_false;
+ fe->print_elt = owl_filterelement_print_false;
}
-int owl_filterelement_is_re(owl_filterelement *fe)
+void owl_filterelement_create_re(owl_filterelement *fe, char *field, char *re)
{
- if (fe->type==OWL_FILTERELEMENT_RE) return(1);
- return(0);
+ owl_filterelement_create(fe);
+ fe->field=owl_strdup(field);
+ owl_regex_create(&(fe->re), re);
+ fe->match_message = owl_filterelement_match_re;
+ fe->print_elt = owl_filterelement_print_re;
}
-int owl_filterelement_is_perl(owl_filterelement *fe)
+void owl_filterelement_create_filter(owl_filterelement *fe, char *name)
{
- if (fe->type==OWL_FILTERELEMENT_PERL) return(1);
- return(0);
+ owl_filterelement_create(fe);
+ fe->field=owl_strdup(name);
+ fe->match_message = owl_filterelement_match_filter;
+ fe->print_elt = owl_filterelement_print_filter;
}
-owl_regex *owl_filterelement_get_re(owl_filterelement *fe)
+void owl_filterelement_create_perl(owl_filterelement *fe, char *name)
{
- return(&(fe->re));
+ owl_filterelement_create(fe);
+ fe->field=owl_strdup(name);
+ fe->match_message = owl_filterelement_match_perl;
+ fe->print_elt = owl_filterelement_print_perl;
}
-int owl_filterelement_is_filter(owl_filterelement *fe)
+void owl_filterelement_create_group(owl_filterelement *fe, owl_filterelement *in)
{
- if (fe->type==OWL_FILTERELEMENT_FILTER) return(1);
- return(0);
+ owl_filterelement_create(fe);
+ fe->left = in;
+ fe->match_message = owl_filterelement_match_group;
+ fe->print_elt = owl_filterelement_print_group;
}
-char *owl_filterelement_get_field(owl_filterelement *fe)
+void owl_filterelement_create_not(owl_filterelement *fe, owl_filterelement *in)
{
- if (fe->field) return(fe->field);
- return("unknown-field");
+ owl_filterelement_create(fe);
+ fe->left = in;
+ fe->match_message = owl_filterelement_match_not;
+ fe->print_elt = owl_filterelement_print_not;
}
-char *owl_filterelement_get_filtername(owl_filterelement *fe)
+void owl_filterelement_create_and(owl_filterelement *fe, owl_filterelement *lhs, owl_filterelement *rhs)
{
- if (fe->filtername) return(fe->filtername);
- return("unknown-filter");
+ owl_filterelement_create(fe);
+ fe->left = lhs;
+ fe->right = rhs;
+ fe->match_message = owl_filterelement_match_and;
+ fe->print_elt = owl_filterelement_print_and;
}
-int owl_filterelement_is_value(owl_filterelement *fe)
+void owl_filterelement_create_or(owl_filterelement *fe, owl_filterelement *lhs, owl_filterelement *rhs)
{
- if ( (fe->type==OWL_FILTERELEMENT_TRUE) ||
- (fe->type==OWL_FILTERELEMENT_FALSE) ||
- (fe->type==OWL_FILTERELEMENT_RE) ||
- (fe->type==OWL_FILTERELEMENT_PERL) ||
- (fe->type==OWL_FILTERELEMENT_FILTER)) {
- return(1);
+ owl_filterelement_create(fe);
+ fe->left = lhs;
+ fe->right = rhs;
+ fe->match_message = owl_filterelement_match_or;
+ fe->print_elt = owl_filterelement_print_or;
+}
+
+int owl_filterelement_match(owl_filterelement *fe, owl_message *m)
+{
+ if(!fe) return 0;
+ if(!fe->match_message) return 0;
+ return fe->match_message(fe, m);
+}
+
+int owl_filterelement_is_toodeep(owl_filter *f, owl_filterelement *fe)
+{
+ int one = 1;
+ owl_list nodes;
+ owl_dict filters;
+ owl_list_create(&nodes);
+ owl_dict_create(&filters);
+
+ owl_list_append_element(&nodes, fe);
+ owl_dict_insert_element(&filters, f->name, &one, NULL);
+ while(owl_list_get_size(&nodes)) {
+ fe = owl_list_get_element(&nodes, 0);
+ owl_list_remove_element(&nodes, 0);
+ if(fe->left) owl_list_append_element(&nodes, fe->left);
+ if(fe->right) owl_list_append_element(&nodes, fe->right);
+ if(fe->match_message == owl_filterelement_match_filter) {
+ if(owl_dict_find_element(&filters, fe->field)) return 1;
+ owl_dict_insert_element(&filters, fe->field, &one, NULL);
+ f = owl_global_get_filter(&g, fe->field);
+ if(f) owl_list_append_element(&nodes, f->root);
+ }
}
- return(0);
+
+ owl_list_free_simple(&nodes);
+ owl_dict_free_simple(&filters);
+ return 0;
}
-/* caller must free the return */
-char *owl_filterelement_to_string(owl_filterelement *fe)
+void owl_filterelement_free(owl_filterelement *fe)
{
- if (owl_filterelement_is_openbrace(fe)) {
- return(owl_strdup("( "));
- } else if (owl_filterelement_is_closebrace(fe)) {
- return(owl_strdup(") "));
- } else if (owl_filterelement_is_and(fe)) {
- return(owl_strdup("and "));
- } else if (owl_filterelement_is_or(fe)) {
- return(owl_strdup("or "));
- } else if (owl_filterelement_is_not(fe)) {
- return(owl_strdup("not "));
- } else if (owl_filterelement_is_true(fe)) {
- return(owl_strdup("true "));
- } else if (owl_filterelement_is_false(fe)) {
- return(owl_strdup("false "));
- } else if (owl_filterelement_is_re(fe)) {
- return(owl_sprintf("%s %s ", fe->field, owl_regex_get_string(&(fe->re))));
- } else if (owl_filterelement_is_filter(fe)) {
- return(owl_sprintf("filter %s ", fe->filtername));
- } else if (owl_filterelement_is_perl(fe)) {
- return(owl_sprintf("perl %s ", fe->filtername));
+ if (fe->field) owl_free(fe->field);
+ if (fe->left) {
+ owl_filterelement_free(fe->left);
+ owl_free(fe->left);
}
+ if (fe->right) {
+ owl_filterelement_free(fe->right);
+ owl_free(fe->right);
+ }
+ owl_regex_free(&(fe->re));
+}
- return(owl_strdup("?"));
+void owl_filterelement_print(owl_filterelement *fe, char *buf)
+{
+ if(!fe || !fe->print_elt) return;
+ fe->print_elt(fe, buf);
}
Modified: trunk/owl/global.c
===================================================================
--- trunk/owl/global.c 2006-12-26 06:00:43 UTC (rev 483)
+++ trunk/owl/global.c 2006-12-26 06:05:26 UTC (rev 484)
@@ -77,10 +77,6 @@
owl_history_set_norepeats(&(g->cmdhist));
g->nextmsgid=0;
- owl_filterelement_create_true(&(g->fe_true));
- owl_filterelement_create_false(&(g->fe_false));
- owl_filterelement_create_null(&(g->fe_null));
-
_owl_global_setup_windows(g);
/* Fill in some variables which don't have constant defaults */
@@ -582,18 +578,6 @@
return(&(g->current_view));
}
-owl_filterelement *owl_global_get_filterelement_true(owl_global *g) {
- return(&(g->fe_true));
-}
-
-owl_filterelement *owl_global_get_filterelement_false(owl_global *g) {
- return(&(g->fe_false));
-}
-
-owl_filterelement *owl_global_get_filterelement_null(owl_global *g) {
- return(&(g->fe_null));
-}
-
/* has colors */
int owl_global_get_hascolors(owl_global *g) {
Modified: trunk/owl/owl.c
===================================================================
--- trunk/owl/owl.c 2006-12-26 06:00:43 UTC (rev 483)
+++ trunk/owl/owl.c 2006-12-26 06:05:26 UTC (rev 484)
@@ -189,7 +189,7 @@
/* owl global init */
owl_global_init(&g);
- if (debug) owl_global_set_debug_on(&g);
+ if (debug) owl_global_set_debug_on(&g);
owl_function_debugmsg("startup: first available debugging message");
owl_global_set_startupargs(&g, argcsave, argvsave);
owl_global_set_haveaim(&g);
Modified: trunk/owl/owl.h
===================================================================
--- trunk/owl/owl.h 2006-12-26 06:00:43 UTC (rev 483)
+++ trunk/owl/owl.h 2006-12-26 06:05:26 UTC (rev 484)
@@ -399,16 +399,21 @@
} owl_regex;
typedef struct _owl_filterelement {
- int type;
+ int (*match_message)(struct _owl_filterelement *fe, owl_message *m);
+ /* Append a string representation of the filterelement onto buf*/
+ void (*print_elt)(struct _owl_filterelement *fe, char * buf);
+ /* Operands for and,or,not*/
+ struct _owl_filterelement *left, *right;
+ /* For regex filters*/
+ owl_regex re;
+ /* Used by regexes, filter references, and perl */
char *field;
- owl_regex re;
- char *filtername; /* for maching on another filter */
} owl_filterelement;
typedef struct _owl_filter {
char *name;
int polarity;
- owl_list fes; /* filterelements */
+ owl_filterelement * root;
int color;
int cachedmsgid; /* cached msgid: should move into view eventually */
} owl_filter;
@@ -554,9 +559,6 @@
int newmsgproc_pid;
int malloced, freed;
char *searchstring;
- owl_filterelement fe_true;
- owl_filterelement fe_false;
- owl_filterelement fe_null;
aim_session_t aimsess;
aim_conn_t bosconn;
owl_timer aim_noop_timer;
Modified: trunk/owl/perl/modules/jabber.pl
===================================================================
--- trunk/owl/perl/modules/jabber.pl 2006-12-26 06:00:43 UTC (rev 483)
+++ trunk/owl/perl/modules/jabber.pl 2006-12-26 06:05:26 UTC (rev 484)
@@ -351,7 +351,7 @@
my @result = $client->AuthSend( %{ $vars{jlogin_authhash} } );
if ( $result[0] ne 'ok' ) {
- if ( !$vars{jlogin_havepass} && $result[0] == 401 ) {
+ if ( !$vars{jlogin_havepass} && $result[0] eq '401' ) {
$vars{jlogin_havepass} = 1;
$conn->removeConnection($jidStr);
owl::start_password( "Password for $jidStr: ", \&do_login );
@@ -808,9 +808,7 @@
$j->SetSubject( $vars{jwrite}{subject} ) if ( $vars{jwrite}{subject} );
my $m = j2o( $j, { direction => 'out' } );
- if ( $vars{jwrite}{type} ne 'groupchat' ) {
-
- #XXX TODO: Check for displayoutgoing.
+ if ( $vars{jwrite}{type} ne 'groupchat' && owl::getvar('displayoutgoing') eq 'on') {
owl::queue_message($m);
}
@@ -1012,7 +1010,7 @@
"jwrite " . ( ( $dir eq 'in' ) ? $props{from} : $props{to} );
$props{replycmd} .=
" -a " . ( ( $dir eq 'out' ) ? $props{from} : $props{to} );
- $props{isprivate} = 1;
+ $props{private} = 1;
}
elsif ( $jtype eq 'groupchat' ) {
my $nick = $props{nick} = $from->GetResource();
@@ -1031,7 +1029,7 @@
}
elsif ( $jtype eq 'normal' ) {
$props{replycmd} = undef;
- $props{isprivate} = 1;
+ $props{private} = 1;
}
elsif ( $jtype eq 'headline' ) {
$props{replycmd} = undef;
Modified: trunk/owl/regex.c
===================================================================
--- trunk/owl/regex.c 2006-12-26 06:00:43 UTC (rev 483)
+++ trunk/owl/regex.c 2006-12-26 06:05:26 UTC (rev 484)
@@ -85,7 +85,10 @@
void owl_regex_free(owl_regex *re)
{
- if (re->string) owl_free(re->string);
+ if (re->string) {
+ owl_free(re->string);
+ regfree(&(re->re));
+ }
/* do we need to free the regular expression? */
}
Modified: trunk/owl/tester.c
===================================================================
--- trunk/owl/tester.c 2006-12-26 06:00:43 UTC (rev 483)
+++ trunk/owl/tester.c 2006-12-26 06:05:26 UTC (rev 484)
@@ -149,6 +149,7 @@
numfailures += owl_util_regtest();
numfailures += owl_dict_regtest();
numfailures += owl_variable_regtest();
+ numfailures += owl_filter_regtest();
if (numfailures) {
fprintf(stderr, "*** WARNING: %d failures total\n", numfailures);
}