source: filter.c @ 3abf28b

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 3abf28b was 3abf28b, checked in by James M. Kretchmar <kretch@mit.edu>, 18 years ago
make smartnarrow work for AIM (though it will crash on names with spaces) don't set an away message by default better default format bold them like personal zephyrs same with terminal bell do some basic HTML stripping (buggy, in progress)
  • Property mode set to 100644
File size: 10.1 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      match=owl_message_type_to_string(m);
153    } else if (!strcasecmp(field, "direction")) {
154      if (owl_message_is_direction_out(m)) {
155        match="out";
156      } else if (owl_message_is_direction_in(m)) {
157        match="in";
158      } else if (owl_message_is_direction_none(m)) {
159        match="none";
160      } else {
161        match="";
162      }
163    }
164   
165    tmp=owl_regex_compare(owl_filterelement_get_re(fe), match);
166    if (!tmp) {
167      owl_list_replace_element(&work_fes, i, owl_global_get_filterelement_true(&g));
168    } else {
169      owl_list_replace_element(&work_fes, i, owl_global_get_filterelement_false(&g));
170    }
171  }
172
173  /* call the recrsive helper */
174  i=_owl_filter_message_match_recurse(f, m, &work_fes, 0, owl_list_get_size(&(f->fes))-1);
175
176  /* now there will be only one TRUE / FALSE, find it among the NULL's */
177  tmp=0;
178  for (i=0; i<j; i++) {
179    fe=owl_list_get_element(&work_fes, i);
180    if (owl_filterelement_is_null(fe)) continue;
181    if (owl_filterelement_is_true(fe)) {
182      tmp=1;
183      break;
184    }
185    if (owl_filterelement_is_false(fe)) {
186      tmp=0;
187      break;
188    }
189  } 
190
191  /* reverse the answer if negative polarity is in use */
192  if (f->polarity) tmp=!tmp;
193
194  owl_list_free_simple(&work_fes);
195  return(tmp);
196}
197
198int _owl_filter_message_match_recurse(owl_filter *f, owl_message *m, owl_list *fes, int start, int end) {
199  int a=0, b=0, i, x, y, z, score, ret, type;
200  owl_filterelement *fe, *tmpfe=NULL;
201
202  /* Deal with parens first. */
203  for (i=0; i<OWL_FILTER_MAX_DEPTH; i++) {
204    /* Find first open paren and matching close paren, store in x, y */
205    score=x=y=0;
206    for (i=start; i<=end; i++) {
207      fe=owl_list_get_element(fes, i);
208      if (owl_filterelement_is_openbrace(fe)) {
209        if (score==0) x=i;
210        score++;
211      } else if (owl_filterelement_is_closebrace(fe)) {
212        score--;
213        if (score<0) {
214          /* unblanaced parens */
215          return(-1);
216        } else if (score==0) {
217          y=i; /* this is the matching close paren */
218          break;
219        }
220      }
221    }
222    if (score>0) {
223      /* unblanaced parens */
224      return(-1);
225    }
226
227    /* Simply the parens by removing them and evaluating what was in between */
228    if (y>0) {
229      /* null out the parens */
230      owl_list_replace_element(fes, x, owl_global_get_filterelement_null(&g));
231      owl_list_replace_element(fes, y, owl_global_get_filterelement_null(&g));
232
233      /* evaluate expression in between */
234      ret=_owl_filter_message_match_recurse(f, m, fes, x+1, y-1);
235      if (ret<0) return(-1);
236
237      /* there may be more, so we continue */
238      continue;
239    } else {
240      /* otherwise we're done with this part */
241      break;
242    }
243  }
244  if (i==OWL_FILTER_MAX_DEPTH) {
245    /* hit the saftey limit, consider it invalid */
246    return(-1);
247  }
248
249  /* Find AND / OR / NOT.
250   *   For binary expressions (AND/OR):
251   *     "type" is 1
252   *     "x" will index first val, "y" the operator and "z" the second val
253   *   For unary expressions (NOT):
254   *     "type" is 2
255   *     "x" will index the operator, "y" the value
256   *   "score" tallys how many expression elements have been found so far
257   */
258  for (i=0; i<OWL_FILTER_MAX_DEPTH; i++) {
259    type=score=x=y=z=0;
260    for (i=start; i<=end; i++) {
261      fe=owl_list_get_element(fes, i);
262      if (owl_filterelement_is_null(fe)) continue;
263      if (score==0) {
264        if (owl_filterelement_is_value(fe)) {
265          x=i;
266          score=1;
267          type=1;
268        } else if (owl_filterelement_is_not(fe)) {
269          x=i;
270          score=1;
271          type=2;
272        }
273      } else if (score==1) {
274        if (type==1) {
275          if (owl_filterelement_is_and(fe) || owl_filterelement_is_or(fe)) {
276            score=2;
277            y=i;
278          } else {
279            /* it's not a valid binary expression */
280            x=y=z=score=0;
281          }
282        } else if (type==2) {
283          if (owl_filterelement_is_value(fe)) {
284            /* valid unary expression, we're done */
285            y=i;
286            break;
287          }
288        }
289      } else if (score==2) {
290        if (owl_filterelement_is_value(fe)) {
291          /* valid binary expression, we're done */
292          z=i;
293          break;
294        } else {
295          x=y=z=score=0;
296        }
297      }
298    }
299
300    /* simplify AND / OR */
301    if ((type==1) && (z>0)) {
302      fe=owl_list_get_element(fes, x);
303      if (owl_filterelement_is_true(fe)) {
304        a=1;
305      } else if (owl_filterelement_is_false(fe)) {
306        a=0;
307      }
308
309      fe=owl_list_get_element(fes, z);
310      if (owl_filterelement_is_true(fe)) {
311        b=1;
312      } else if (owl_filterelement_is_false(fe)) {
313        b=0;
314      }
315
316      fe=owl_list_get_element(fes, y);
317      if (owl_filterelement_is_and(fe)) {
318        if (a && b) {
319          tmpfe=owl_global_get_filterelement_true(&g);
320        } else {
321          tmpfe=owl_global_get_filterelement_false(&g);
322        }
323      } else if (owl_filterelement_is_or(fe)) {
324        if (a || b) {
325          tmpfe=owl_global_get_filterelement_true(&g);
326        } else {
327          tmpfe=owl_global_get_filterelement_false(&g);
328        }
329      }
330      owl_list_replace_element(fes, x, owl_global_get_filterelement_null(&g));
331      owl_list_replace_element(fes, y, tmpfe);
332      owl_list_replace_element(fes, z, owl_global_get_filterelement_null(&g));
333    } else if ((type==2) && (y>0)) {
334      /* simplify NOT */
335      fe=owl_list_get_element(fes, y);
336      owl_list_replace_element(fes, x, owl_global_get_filterelement_null(&g));
337      if (owl_filterelement_is_false(fe)) {
338        owl_list_replace_element(fes, y, owl_global_get_filterelement_true(&g));
339      } else {
340        owl_list_replace_element(fes, y, owl_global_get_filterelement_false(&g));
341      }
342    } else {
343      break;
344    }
345  }
346  return(0);
347
348}
349
350void owl_filter_print(owl_filter *f, char *out) {
351  int i, j;
352  owl_filterelement *fe;
353  char *tmp;
354
355  strcpy(out, owl_filter_get_name(f));
356  strcat(out, ": ");
357
358  if (f->color!=OWL_COLOR_DEFAULT) {
359    strcat(out, "-c ");
360    strcat(out, owl_util_color_to_string(f->color));
361    strcat(out, " ");
362  }
363
364  j=owl_list_get_size(&(f->fes));
365  for (i=0; i<j; i++) {
366    fe=owl_list_get_element(&(f->fes), i);
367    tmp=owl_filterelement_to_string(fe);
368    strcat(out, tmp);
369    owl_free(tmp);
370  }
371  strcat(out, "\n");
372}
373
374int owl_filter_equiv(owl_filter *a, owl_filter *b) {
375  char buff[LINE], buff2[LINE];
376
377  owl_filter_print(a, buff);
378  owl_filter_print(b, buff2);
379
380  if (!strcmp(buff, buff2)) return(1);
381  return(0);
382}
383
384void owl_filter_free(owl_filter *f) {
385  void (*func)();
386
387  func=&owl_filterelement_free;
388 
389  if (f->name) owl_free(f->name);
390  owl_list_free_all(&(f->fes), func);
391}
Note: See TracBrowser for help on using the repository browser.