source: filter.c @ 70b53ec

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