source: filter.c @ 79a0e82

barnowl_perlaimdebianowlrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 79a0e82 was e187445, checked in by James M. Kretchmar <kretch@mit.edu>, 21 years ago
reformatted filter, filterelement and regex to new code style
  • Property mode set to 100644
File size: 10.3 KB
Line 
1#include <string.h>
2#include "owl.h"
3
4static const char fileIdent[] = "$Id$";
5
6int owl_filter_init_fromstring(owl_filter *f, char *name, char *string)
7{
8  char **argv;
9  int argc, out;
10
11  argv=owl_parseline(string, &argc);
12  out=owl_filter_init(f, name, argc, argv);
13  /* owl_parsefree(argv, argc); */
14  return(out);
15}
16
17int owl_filter_init(owl_filter *f, char *name, int argc, char **argv)
18{
19  int i, error;
20  owl_filterelement *fe;
21  char *regexstr;
22   
23  f->name=owl_strdup(name);
24  f->polarity=0;
25  f->color=OWL_COLOR_DEFAULT;
26  f->cachedmsgid=-1;
27  owl_list_create(&(f->fes));
28 
29  /* first take arguments that have to come first */
30  /* set the color */
31  if (argc>=2 && !strcmp(argv[0], "-c")) {
32    f->color=owl_util_string_to_color(argv[1]);
33    argc-=2;
34    argv+=2;
35  }
36 
37  /* then deal with the expression */
38  for (i=0; i<argc; i++) {
39    error=0;
40    fe=owl_malloc(sizeof(owl_filterelement));
41   
42    /* all the 0 argument possibilities */
43    if (!strcmp(argv[i], "(")) {
44      owl_filterelement_create_openbrace(fe);
45    } else if (!strcmp(argv[i], ")")) {
46      owl_filterelement_create_closebrace(fe);
47    } else if (!strcasecmp(argv[i], "and")) {
48      owl_filterelement_create_and(fe);
49    } else if (!strcasecmp(argv[i], "or")) {
50      owl_filterelement_create_or(fe);
51    } else if (!strcasecmp(argv[i], "not")) {
52      owl_filterelement_create_not(fe);
53    } else if (!strcasecmp(argv[i], "true")) {
54      owl_filterelement_create_true(fe);
55    } else if (!strcasecmp(argv[i], "false")) {
56      owl_filterelement_create_false(fe);
57     
58    } else if (i==argc-1) {
59      error=1;
60    } else {
61      if (!strcasecmp(argv[i], "class") ||
62          !strcasecmp(argv[i], "instance") ||
63          !strcasecmp(argv[i], "sender") ||
64          !strcasecmp(argv[i], "recipient") ||
65          !strcasecmp(argv[i], "body") ||
66          !strcasecmp(argv[i], "opcode") ||
67          !strcasecmp(argv[i], "realm") ||
68          !strcasecmp(argv[i], "type") ||
69          !strcasecmp(argv[i], "direction") ||
70          !strcasecmp(argv[i], "login")) {
71        regexstr=owl_util_substitute(argv[i+1], "%me%", ZGetSender());
72        owl_filterelement_create_re(fe, argv[i], regexstr);
73        owl_free(regexstr);
74        i++;
75      } else {
76        error=1;
77      }
78    }
79
80    if (!error) {
81      owl_list_append_element(&(f->fes), fe);
82    } else {
83      owl_free(fe);
84      owl_filter_free(f);
85      return(-1);
86    }
87
88  }
89  return(0);
90}
91
92char *owl_filter_get_name(owl_filter *f)
93{
94  return(f->name);
95}
96
97void owl_filter_set_polarity_match(owl_filter *f)
98{
99  f->polarity=0;
100}
101
102void owl_filter_set_polarity_unmatch(owl_filter *f)
103{
104  f->polarity=1;
105}
106
107void owl_filter_set_color(owl_filter *f, int color)
108{
109  f->color=color;
110}
111
112int owl_filter_get_color(owl_filter *f)
113{
114  return(f->color);
115}
116
117void owl_filter_set_cachedmsgid(owl_filter *f, int cachedmsgid)
118{
119  f->cachedmsgid=cachedmsgid;
120}
121
122int owl_filter_get_cachedmsgid(owl_filter *f)
123{
124  return(f->cachedmsgid);
125}
126
127int owl_filter_message_match(owl_filter *f, owl_message *m)
128{
129  int i, j, tmp;
130  owl_list work_fes, *fes;
131  owl_filterelement *fe;
132  char *field, *match;
133
134  /* create the working list of expression elements */
135  fes=&(f->fes);
136  owl_list_create(&work_fes);
137  j=owl_list_get_size(fes);
138  for (i=0; i<j; i++) {
139    owl_list_append_element(&work_fes, owl_list_get_element(fes, i));
140  }
141
142  /* first go thru and evaluate all RE elements to true or false */
143  match="";
144  for (i=0; i<j; i++) {
145    fe=owl_list_get_element(&work_fes, i);
146    if (!owl_filterelement_is_re(fe)) continue;
147    field=owl_filterelement_get_field(fe);
148    if (!strcasecmp(field, "class")) {
149      match=owl_message_get_class(m);
150    } else if (!strcasecmp(field, "instance")) {
151      match=owl_message_get_instance(m);
152    } else if (!strcasecmp(field, "sender")) {
153      match=owl_message_get_sender(m);
154    } else if (!strcasecmp(field, "recipient")) {
155      match=owl_message_get_recipient(m);
156    } else if (!strcasecmp(field, "body")) {
157      match=owl_message_get_body(m);
158    } else if (!strcasecmp(field, "opcode")) {
159      match=owl_message_get_opcode(m);
160    } else if (!strcasecmp(field, "realm")) {
161      match=owl_message_get_realm(m);
162    } else if (!strcasecmp(field, "type")) {
163      match=owl_message_type_to_string(m);
164    } else if (!strcasecmp(field, "direction")) {
165      if (owl_message_is_direction_out(m)) {
166        match="out";
167      } else if (owl_message_is_direction_in(m)) {
168        match="in";
169      } else if (owl_message_is_direction_none(m)) {
170        match="none";
171      } else {
172        match="";
173      }
174    } else if (!strcasecmp(field, "login")) {
175      if (owl_message_is_login(m)) {
176        match="login";
177      } else if (owl_message_is_logout(m)) {
178        match="logout";
179      } else {
180        match="none";
181      }
182    }
183   
184    tmp=owl_regex_compare(owl_filterelement_get_re(fe), match);
185    if (!tmp) {
186      owl_list_replace_element(&work_fes, i, owl_global_get_filterelement_true(&g));
187    } else {
188      owl_list_replace_element(&work_fes, i, owl_global_get_filterelement_false(&g));
189    }
190  }
191
192  /* call the recrsive helper */
193  i=_owl_filter_message_match_recurse(f, m, &work_fes, 0, owl_list_get_size(&(f->fes))-1);
194
195  /* now there will be only one TRUE / FALSE, find it among the NULL's */
196  tmp=0;
197  for (i=0; i<j; i++) {
198    fe=owl_list_get_element(&work_fes, i);
199    if (owl_filterelement_is_null(fe)) continue;
200    if (owl_filterelement_is_true(fe)) {
201      tmp=1;
202      break;
203    }
204    if (owl_filterelement_is_false(fe)) {
205      tmp=0;
206      break;
207    }
208  } 
209
210  /* reverse the answer if negative polarity is in use */
211  if (f->polarity) tmp=!tmp;
212
213  owl_list_free_simple(&work_fes);
214  return(tmp);
215}
216
217int _owl_filter_message_match_recurse(owl_filter *f, owl_message *m, owl_list *fes, int start, int end)
218{
219  int a=0, b=0, i, x, y, z, score, ret, type;
220  owl_filterelement *fe, *tmpfe=NULL;
221
222  /* Deal with parens first. */
223  for (i=0; i<OWL_FILTER_MAX_DEPTH; i++) {
224    /* Find first open paren and matching close paren, store in x, y */
225    score=x=y=0;
226    for (i=start; i<=end; i++) {
227      fe=owl_list_get_element(fes, i);
228      if (owl_filterelement_is_openbrace(fe)) {
229        if (score==0) x=i;
230        score++;
231      } else if (owl_filterelement_is_closebrace(fe)) {
232        score--;
233        if (score<0) {
234          /* unblanaced parens */
235          return(-1);
236        } else if (score==0) {
237          y=i; /* this is the matching close paren */
238          break;
239        }
240      }
241    }
242    if (score>0) {
243      /* unblanaced parens */
244      return(-1);
245    }
246
247    /* Simply the parens by removing them and evaluating what was in between */
248    if (y>0) {
249      /* null out the parens */
250      owl_list_replace_element(fes, x, owl_global_get_filterelement_null(&g));
251      owl_list_replace_element(fes, y, owl_global_get_filterelement_null(&g));
252
253      /* evaluate expression in between */
254      ret=_owl_filter_message_match_recurse(f, m, fes, x+1, y-1);
255      if (ret<0) return(-1);
256
257      /* there may be more, so we continue */
258      continue;
259    } else {
260      /* otherwise we're done with this part */
261      break;
262    }
263  }
264  if (i==OWL_FILTER_MAX_DEPTH) {
265    /* hit the saftey limit, consider it invalid */
266    return(-1);
267  }
268
269  /* Find AND / OR / NOT.
270   *   For binary expressions (AND/OR):
271   *     "type" is 1
272   *     "x" will index first val, "y" the operator and "z" the second val
273   *   For unary expressions (NOT):
274   *     "type" is 2
275   *     "x" will index the operator, "y" the value
276   *   "score" tallys how many expression elements have been found so far
277   */
278  for (i=0; i<OWL_FILTER_MAX_DEPTH; i++) {
279    type=score=x=y=z=0;
280    for (i=start; i<=end; i++) {
281      fe=owl_list_get_element(fes, i);
282      if (owl_filterelement_is_null(fe)) continue;
283      if (score==0) {
284        if (owl_filterelement_is_value(fe)) {
285          x=i;
286          score=1;
287          type=1;
288        } else if (owl_filterelement_is_not(fe)) {
289          x=i;
290          score=1;
291          type=2;
292        }
293      } else if (score==1) {
294        if (type==1) {
295          if (owl_filterelement_is_and(fe) || owl_filterelement_is_or(fe)) {
296            score=2;
297            y=i;
298          } else {
299            /* it's not a valid binary expression */
300            x=y=z=score=0;
301          }
302        } else if (type==2) {
303          if (owl_filterelement_is_value(fe)) {
304            /* valid unary expression, we're done */
305            y=i;
306            break;
307          }
308        }
309      } else if (score==2) {
310        if (owl_filterelement_is_value(fe)) {
311          /* valid binary expression, we're done */
312          z=i;
313          break;
314        } else {
315          x=y=z=score=0;
316        }
317      }
318    }
319
320    /* simplify AND / OR */
321    if ((type==1) && (z>0)) {
322      fe=owl_list_get_element(fes, x);
323      if (owl_filterelement_is_true(fe)) {
324        a=1;
325      } else if (owl_filterelement_is_false(fe)) {
326        a=0;
327      }
328
329      fe=owl_list_get_element(fes, z);
330      if (owl_filterelement_is_true(fe)) {
331        b=1;
332      } else if (owl_filterelement_is_false(fe)) {
333        b=0;
334      }
335
336      fe=owl_list_get_element(fes, y);
337      if (owl_filterelement_is_and(fe)) {
338        if (a && b) {
339          tmpfe=owl_global_get_filterelement_true(&g);
340        } else {
341          tmpfe=owl_global_get_filterelement_false(&g);
342        }
343      } else if (owl_filterelement_is_or(fe)) {
344        if (a || b) {
345          tmpfe=owl_global_get_filterelement_true(&g);
346        } else {
347          tmpfe=owl_global_get_filterelement_false(&g);
348        }
349      }
350      owl_list_replace_element(fes, x, owl_global_get_filterelement_null(&g));
351      owl_list_replace_element(fes, y, tmpfe);
352      owl_list_replace_element(fes, z, owl_global_get_filterelement_null(&g));
353    } else if ((type==2) && (y>0)) {
354      /* simplify NOT */
355      fe=owl_list_get_element(fes, y);
356      owl_list_replace_element(fes, x, owl_global_get_filterelement_null(&g));
357      if (owl_filterelement_is_false(fe)) {
358        owl_list_replace_element(fes, y, owl_global_get_filterelement_true(&g));
359      } else {
360        owl_list_replace_element(fes, y, owl_global_get_filterelement_false(&g));
361      }
362    } else {
363      break;
364    }
365  }
366  return(0);
367
368}
369
370void owl_filter_print(owl_filter *f, char *out)
371{
372  int i, j;
373  owl_filterelement *fe;
374  char *tmp;
375
376  strcpy(out, owl_filter_get_name(f));
377  strcat(out, ": ");
378
379  if (f->color!=OWL_COLOR_DEFAULT) {
380    strcat(out, "-c ");
381    strcat(out, owl_util_color_to_string(f->color));
382    strcat(out, " ");
383  }
384
385  j=owl_list_get_size(&(f->fes));
386  for (i=0; i<j; i++) {
387    fe=owl_list_get_element(&(f->fes), i);
388    tmp=owl_filterelement_to_string(fe);
389    strcat(out, tmp);
390    owl_free(tmp);
391  }
392  strcat(out, "\n");
393}
394
395int owl_filter_equiv(owl_filter *a, owl_filter *b)
396{
397  char buff[LINE], buff2[LINE];
398
399  owl_filter_print(a, buff);
400  owl_filter_print(b, buff2);
401
402  if (!strcmp(buff, buff2)) return(1);
403  return(0);
404}
405
406void owl_filter_free(owl_filter *f)
407{
408  void (*func)();
409
410  func=&owl_filterelement_free;
411 
412  if (f->name) owl_free(f->name);
413  owl_list_free_all(&(f->fes), func);
414}
Note: See TracBrowser for help on using the repository browser.