source: filter.c @ 446aa2b

barnowl_perlaimdebianrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 446aa2b was 446aa2b, checked in by Nelson Elhage <nelhage@mit.edu>, 14 years ago
make owl_filter_print include the filter name and color, like the old one did
  • Property mode set to 100644
File size: 7.7 KB
Line 
1#include <string.h>
2#include "owl.h"
3
4static const char fileIdent[] = "$Id$";
5
6#define OWL_FILTER_MAXRECURSE 20
7
8int owl_filter_init_fromstring(owl_filter *f, char *name, char *string)
9{
10  char **argv;
11  int argc, out;
12
13  argv=owl_parseline(string, &argc);
14  out=owl_filter_init(f, name, argc, argv);
15  /* owl_parsefree(argv, argc); */
16  return(out);
17}
18
19int owl_filter_init(owl_filter *f, char *name, int argc, char **argv)
20{
21  f->name=owl_strdup(name);
22  f->polarity=0;
23  f->color=OWL_COLOR_DEFAULT;
24  f->cachedmsgid=-1;
25
26  /* first take arguments that have to come first */
27  /* set the color */
28  if (argc>=2 && !strcmp(argv[0], "-c")) {
29    if (owl_util_string_to_color(argv[1])==-1) {
30      owl_function_error("The color '%s' is not available, using default.", argv[1]);
31    } else {
32      f->color=owl_util_string_to_color(argv[1]);
33    }
34    argc-=2;
35    argv+=2;
36  }
37
38  if(!(f->root = owl_filter_parse_expression(argc, argv, NULL)))
39    return(-1);
40
41  /* Now check for recursion. */
42  if (owl_filter_is_toodeep(f)) {
43    owl_function_error("Filter loop or exceeds recursion depth");
44    owl_filter_free(f);
45    return(-1);
46  }
47
48  return(0);
49}
50
51
52/* A primitive expression is one without any toplevel ``and'' or ``or''s*/
53
54static owl_filterelement * owl_filter_parse_primitive_expression(int argc, char **argv, int *next)
55{
56  if(!argc) return NULL;
57
58  owl_filterelement * fe = owl_malloc(sizeof(owl_filterelement));
59  owl_filterelement *op;
60
61  owl_filterelement_create(fe);
62  int i = 0, skip;
63
64  if(!strcasecmp(argv[i], "(")) {
65    i++;
66    op = owl_filter_parse_expression(argc-i, argv+i, &skip);
67    if(!op) goto err;
68    i += skip;
69    if(strcasecmp(argv[i++], ")")) goto err;
70    owl_filterelement_create_group(fe, op);
71  } else if(!strcasecmp(argv[i], "not")) {
72    i++;
73    op = owl_filter_parse_primitive_expression(argc-i, argv+i, &skip);
74    if(!op) goto err;
75    i += skip;
76    owl_filterelement_create_not(fe, op);
77  } else if(!strcasecmp(argv[i], "true")) {
78    i++;
79    owl_filterelement_create_true(fe);
80  } else if(!strcasecmp(argv[i], "false")) {
81    i++;
82    owl_filterelement_create_false(fe);
83  } else {
84    if(argc == 1) goto err;
85    if(!strcasecmp(*argv, "filter")) {
86      owl_filterelement_create_filter(fe, *(argv+1));
87    } else if(!strcasecmp(*argv, "perl")) {
88      owl_filterelement_create_perl(fe, *(argv+1));
89    } else {
90      owl_filterelement_create_re(fe, *argv, *(argv+1));
91    }
92    i += 2;
93  }
94
95  if(next) {
96    *next = i;
97  } else if(i != argc) {
98    goto err;
99  }
100  return fe;
101err:
102  owl_filterelement_free(fe);
103  owl_free(fe);
104  return NULL;
105}
106
107owl_filterelement * owl_filter_parse_expression(int argc, char **argv, int *next)
108{
109  int i = 0, skip;
110  owl_filterelement * op1 = NULL, * op2 = NULL;
111
112  op1 = owl_filter_parse_primitive_expression(argc-i, argv+i, &skip);
113  i += skip;
114  if(!op1) goto err;
115
116  while(i < argc) {
117    if(strcasecmp(argv[i], "and") &&
118       strcasecmp(argv[i], "or")) break;
119    op2 = owl_filter_parse_primitive_expression(argc-i-1, argv+i+1, &skip);
120    if(!op2) goto err;
121    owl_filterelement * tmp = owl_malloc(sizeof(owl_filterelement));
122    if(!strcasecmp(argv[i], "and")) {
123      owl_filterelement_create_and(tmp, op1, op2);
124    } else {
125      owl_filterelement_create_or(tmp, op1, op2);
126    }
127    op1 = tmp;
128    op2 = NULL;
129    i += skip+1;
130  }
131
132  if(next) {
133    *next = i;
134  } else if(i != argc) {
135    goto err;
136  }
137  return op1;
138err:
139  if(op1) {
140    owl_filterelement_free(op1);
141    owl_free(op1);
142  }
143  return NULL;
144}
145
146char *owl_filter_get_name(owl_filter *f)
147{
148  return(f->name);
149}
150
151void owl_filter_set_polarity_match(owl_filter *f)
152{
153  f->polarity=0;
154}
155
156void owl_filter_set_polarity_unmatch(owl_filter *f)
157{
158  f->polarity=1;
159}
160
161void owl_filter_set_color(owl_filter *f, int color)
162{
163  f->color=color;
164}
165
166int owl_filter_get_color(owl_filter *f)
167{
168  return(f->color);
169}
170
171void owl_filter_set_cachedmsgid(owl_filter *f, int cachedmsgid)
172{
173  f->cachedmsgid=cachedmsgid;
174}
175
176int owl_filter_get_cachedmsgid(owl_filter *f)
177{
178  return(f->cachedmsgid);
179}
180
181/* return 1 if the message matches the given filter, otherwise
182 * return 0.
183 */
184int owl_filter_message_match(owl_filter *f, owl_message *m)
185{
186  if(!f->root) return 0;
187  int ret = owl_filterelement_match(f->root, m);
188  if(f->polarity) ret = !ret;
189  return ret;
190}
191
192
193void owl_filter_print(owl_filter *f, char *out)
194{
195  strcpy(out, owl_filter_get_name(f));
196  strcat(out, ": ");
197
198  if (f->color!=OWL_COLOR_DEFAULT) {
199    strcat(out, "-c ");
200    strcat(out, owl_util_color_to_string(f->color));
201    strcat(out, " ");
202  }
203  if(!f->root) return;
204  owl_filterelement_print(f->root, out);
205  strcat(out, "\n");
206}
207
208/* Return 1 if the filters 'a' and 'b' are equivalent, 0 otherwise */
209int owl_filter_equiv(owl_filter *a, owl_filter *b)
210{
211  char buff[LINE], buff2[LINE];
212
213  owl_filter_print(a, buff);
214  owl_filter_print(b, buff2);
215
216  if (!strcmp(buff, buff2)) return(1);
217  return(0);
218}
219
220
221int owl_filter_is_toodeep(owl_filter *f)
222{
223  return owl_filterelement_is_toodeep(f, f->root);
224}
225
226void owl_filter_free(owl_filter *f)
227{
228  if(f->root) {
229    owl_filterelement_free(f->root);
230    owl_free(f->root);
231  }
232  if (f->name) owl_free(f->name);
233}
234
235/**************************************************************************/
236/************************* REGRESSION TESTS *******************************/
237/**************************************************************************/
238
239#ifdef OWL_INCLUDE_REG_TESTS
240
241int owl_filter_test_string(char * filt, owl_message *m, int shouldmatch) /* noproto */ {
242  owl_filter f;
243  int ok;
244  int failed = 0;
245  if(owl_filter_init_fromstring(&f, "test-filter", filt)) {
246    printf("\tFAIL: parse %s\n", filt);
247    failed = 1;
248    goto out;
249  }
250  ok = owl_filter_message_match(&f, m);
251  if((shouldmatch && !ok) || (!shouldmatch && ok)) {
252    printf("\tFAIL: match %s (got %d, expected %d)\n", filt, ok, shouldmatch);
253    failed = 1;
254  }
255 out:
256  owl_filter_free(&f);
257  if(!failed) {
258    printf("\tok  : %s %s\n", shouldmatch ? "matches" : "doesn't match", filt);
259  }
260  return failed;
261}
262
263
264#include "test.h"
265
266
267int owl_filter_regtest(void) {
268  owl_list_create(&(g.filterlist));
269  int numfailed=0;
270  owl_message m;
271  owl_message_init(&m);
272  owl_message_set_type_zephyr(&m);
273  owl_message_set_direction_in(&m);
274  owl_message_set_class(&m, "owl");
275  owl_message_set_instance(&m, "tester");
276  owl_message_set_sender(&m, "owl-user");
277  owl_message_set_recipient(&m, "joe");
278  owl_message_set_attribute(&m, "foo", "bar");
279
280#define TEST_FILTER(f, e) numfailed += owl_filter_test_string(f, &m, e)
281
282
283  TEST_FILTER("true", 1);
284  TEST_FILTER("false", 0);
285  TEST_FILTER("( true )", 1);
286  TEST_FILTER("not false", 1);
287  TEST_FILTER("( true ) or ( false )", 1);
288  TEST_FILTER("true and false", 0);
289  TEST_FILTER("( true or true ) or ( ( false ) )", 1);
290
291  TEST_FILTER("class owl", 1);
292  TEST_FILTER("class ^owl$", 1);
293  TEST_FILTER("instance test", 1);
294  TEST_FILTER("instance ^test$", 0);
295  TEST_FILTER("instance ^tester$", 1);
296
297  TEST_FILTER("foo bar", 1);
298  TEST_FILTER("class owl and instance tester", 1);
299  TEST_FILTER("type ^zephyr$ and direction ^in$ and ( class ^owl$ or instance ^owl$ )", 1);
300
301  // Order of operations and precedence
302  TEST_FILTER("not true or false", 0);
303  TEST_FILTER("true or true and false", 0);
304  TEST_FILTER("true and true and false or true", 1);
305  TEST_FILTER("false and false or true", 1);
306  TEST_FILTER("true and false or false", 0);
307
308  owl_filter f1, f2, f3, f4;
309
310  owl_filter_init_fromstring(&f1, "f1", "class owl");
311  owl_global_add_filter(&g, &f1);
312  TEST_FILTER("filter f1", 1);
313
314  // Test recursion prevention
315  FAIL_UNLESS("self reference", owl_filter_init_fromstring(&f2, "test", "filter test"));
316
317  // mutual recursion
318  owl_filter_init_fromstring(&f3, "f3", "filter f4");
319  owl_global_add_filter(&g, &f3);
320  FAIL_UNLESS("mutual recursion",   owl_filter_init_fromstring(&f4, "f4", "filter f3"));
321
322  return 0;
323}
324
325
326#endif /* OWL_INCLUDE_REG_TESTS */
Note: See TracBrowser for help on using the repository browser.