source: filter.c @ 12c35df

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