source: filter.c @ 440ce01

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