/[imapfilter]/imapfilter/filter.c
ViewVC logotype

Annotation of /imapfilter/filter.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.8 - (hide annotations)
Mon Feb 9 17:34:56 2004 UTC (20 years, 2 months ago) by lefcha
Branch: MAIN
Changes since 1.7: +4 -12 lines
File MIME type: text/plain
Move DEBUG from compilation #define variable to runtime command line option.

1 lefcha 1.1 #include <stdio.h>
2 lefcha 1.3 #include <stdlib.h>
3 lefcha 1.1 #include <string.h>
4 lefcha 1.4 #include <strings.h>
5 lefcha 1.1 #include <ctype.h>
6 lefcha 1.4 #include <sys/types.h>
7 lefcha 1.3 #include <time.h>
8 lefcha 1.4 #include <regex.h>
9 lefcha 1.1
10     #include "config.h"
11     #include "imapfilter.h"
12     #include "account.h"
13     #include "filter.h"
14     #include "struct.h"
15    
16    
17     extern account_t *accounts;
18     extern mboxgrp_t *mboxgrps;
19    
20     filter_t *filters = NULL; /* First node of filters tree. */
21    
22 lefcha 1.2 filter_t *cur_fltr = NULL; /* Current filter. */
23 lefcha 1.1
24    
25     void init_filter(filter_t * node);
26    
27     void init_mask(mask_t * node);
28    
29     void link_mbox_filter(filter_t * cf, mboxgrp_t * cg);
30    
31     void string_upper(char *str, size_t size);
32    
33    
34     /*
35     * Set new filter's variables to safe values.
36     */
37     void
38     init_filter(filter_t * node)
39     {
40     node->left = node->right = NULL;
41     node->key[0] = '\0';
42     node->mode = FILTER_MODE_AND;
43     node->action.type = node->action.msgflags = 0;
44     node->action.raccount = NULL;
45     node->action.destmbox[0] = node->action.args[0] = '\0';
46     node->masks = NULL;
47     node->masknum = node->masklen = 0;
48     }
49    
50    
51     /*
52     * A filter entry was declared, create it and set it's variables accordingly.
53     */
54     int
55     set_filter(char *line, regmatch_t * m)
56     {
57     filter_t *node;
58    
59     if (cur_fltr != NULL && cur_fltr->action.type == 0)
60     return ERROR_CONFIG_PARSE;
61    
62     node = (filter_t *) xmalloc(sizeof(filter_t));
63    
64     init_filter(node);
65    
66     strncat(node->key, line + m[1].rm_so,
67     min(m[1].rm_eo - m[1].rm_so, KEY_LEN - 1));
68    
69     if (m[2].rm_so != -1) {
70     if (!strncasecmp(line + m[2].rm_so + 1, "or", 2))
71     node->mode = FILTER_MODE_OR;
72     else
73     node->mode = FILTER_MODE_AND;
74     }
75 lefcha 1.8 debug("FILTER: '%s' %s\n", node->key,
76 lefcha 1.1 (node->mode == FILTER_MODE_OR ? "OR" : "AND"));
77    
78     INSERT_TREE(filters, node, filter);
79    
80     cur_fltr = node;
81    
82     return 0;
83     }
84    
85    
86     /*
87     * Assign an action to the last declared filter.
88     */
89     int
90     set_action(char *line, regmatch_t * m)
91     {
92     char *c, *cp, *t;
93     account_t *a;
94    
95     if (cur_fltr == NULL)
96     return ERROR_CONFIG_PARSE;
97    
98     if (!strncasecmp(line + m[1].rm_so, "delete", 6))
99     cur_fltr->action.type = FILTER_ACTION_DELETE;
100     else if (!strncasecmp(line + m[1].rm_so, "copy", 4)) {
101     cur_fltr->action.type = FILTER_ACTION_COPY;
102     if (*(line + m[2].rm_so) == '"' &&
103     *(line + m[2].rm_eo - 1) == '"')
104     strncat(cur_fltr->action.destmbox,
105     line + m[2].rm_so + 1,
106     min(m[2].rm_eo - m[2].rm_so - 2,
107     MBOX_NAME_LEN - 1));
108     else
109     strncat(cur_fltr->action.destmbox, line + m[2].rm_so,
110     min(m[2].rm_eo - m[2].rm_so, MBOX_NAME_LEN - 1));
111     } else if (!strncasecmp(line + m[1].rm_so, "move", 4)) {
112     cur_fltr->action.type = FILTER_ACTION_MOVE;
113     if (*(line + m[3].rm_so) == '"' &&
114     *(line + m[3].rm_eo - 1) == '"')
115     strncat(cur_fltr->action.destmbox,
116     line + m[3].rm_so + 1,
117     min(m[3].rm_eo - m[3].rm_so - 2,
118     MBOX_NAME_LEN - 1));
119     else
120     strncat(cur_fltr->action.destmbox, line + m[3].rm_so,
121     min(m[3].rm_eo - m[3].rm_so, MBOX_NAME_LEN - 1));
122     } else if (!strncasecmp(line + m[1].rm_so, "rcopy", 5)) {
123     cur_fltr->action.type = FILTER_ACTION_RCOPY;
124     for (a = accounts; a; a = a->next)
125     if (!strncasecmp(line + m[4].rm_so, a->key,
126     strlen(a->key)))
127     cur_fltr->action.raccount = a;
128     if (!cur_fltr->action.raccount)
129     return ERROR_CONFIG_PARSE;
130    
131     if (*(line + m[5].rm_so) == '"' &&
132     *(line + m[5].rm_eo - 1) == '"')
133     strncat(cur_fltr->action.destmbox,
134     line + m[5].rm_so + 1,
135     min(m[5].rm_eo - m[5].rm_so - 2,
136     MBOX_NAME_LEN - 1));
137     else
138     strncat(cur_fltr->action.destmbox, line + m[5].rm_so,
139     min(m[5].rm_eo - m[5].rm_so, MBOX_NAME_LEN - 1));
140     } else if (!strncasecmp(line + m[1].rm_so, "rmove", 5)) {
141     cur_fltr->action.type = FILTER_ACTION_RMOVE;
142     for (a = accounts; a; a = a->next)
143     if (!strncasecmp(line + m[6].rm_so, a->key,
144     strlen(a->key)))
145     cur_fltr->action.raccount = a;
146     if (!cur_fltr->action.raccount)
147     return ERROR_CONFIG_PARSE;
148    
149     if (*(line + m[7].rm_so) == '"' &&
150     *(line + m[7].rm_eo - 1) == '"')
151     strncat(cur_fltr->action.destmbox,
152     line + m[7].rm_so + 1,
153     min(m[7].rm_eo - m[7].rm_so - 2,
154     MBOX_NAME_LEN - 1));
155     else
156     strncat(cur_fltr->action.destmbox, line + m[7].rm_so,
157     min(m[7].rm_eo - m[7].rm_so, MBOX_NAME_LEN - 1));
158     } else if (!strncasecmp(line + m[1].rm_so, "flag", 4)) {
159     if (!strncasecmp(line + m[8].rm_so, "replace", 7))
160     cur_fltr->action.type = FILTER_ACTION_FLAG_REPLACE;
161     else if (!strncasecmp(line + m[8].rm_so, "add", 3))
162     cur_fltr->action.type = FILTER_ACTION_FLAG_ADD;
163     else
164     cur_fltr->action.type = FILTER_ACTION_FLAG_REMOVE;
165    
166     c = cp = (char *)malloc(m[9].rm_eo - m[9].rm_so + 1);
167     xstrncpy(c, line + m[9].rm_so, m[9].rm_eo - m[9].rm_so);
168    
169     t = strtok_r(c, ",", &c);
170     while (t) {
171     if (!strcasecmp(t, "none")) {
172     if (m[9].rm_eo - m[9].rm_so != strlen("none"))
173     return ERROR_CONFIG_PARSE;
174     } else if (!strcasecmp(t, "seen"))
175     cur_fltr->action.msgflags |= MESSAGE_FLAG_SEEN;
176     else if (!strcasecmp(t, "answered"))
177     cur_fltr->action.msgflags |=
178     MESSAGE_FLAG_ANSWERED;
179     else if (!strcasecmp(t, "flagged"))
180     cur_fltr->action.msgflags |=
181     MESSAGE_FLAG_FLAGGED;
182     else if (!strcasecmp(t, "deleted"))
183     cur_fltr->action.msgflags |=
184     MESSAGE_FLAG_DELETED;
185     else if (!strcasecmp(t, "draft"))
186     cur_fltr->action.msgflags |= MESSAGE_FLAG_DRAFT;
187     else
188     return ERROR_CONFIG_PARSE;
189    
190     t = strtok_r(NULL, ",", &c);
191     }
192     xfree(cp);
193     } else if (!strncasecmp(line + m[1].rm_so, "list", 4)) {
194     cur_fltr->action.type = FILTER_ACTION_LIST;
195     }
196     if (m[10].rm_so != -1) {
197     strncat(cur_fltr->action.args, line + m[10].rm_so,
198     min(m[10].rm_eo - m[10].rm_so, ARGS_LEN - 2));
199     while ((c = strchr(cur_fltr->action.args, ',')))
200     *c = ' ';
201     }
202 lefcha 1.8 debug("ACTION: %d '%s' '%s' %d '%s'\n",
203 lefcha 1.1 cur_fltr->action.type,
204     (cur_fltr->action.raccount ? cur_fltr->action.raccount->key : ""),
205     cur_fltr->action.destmbox,
206     cur_fltr->action.msgflags,
207     cur_fltr->action.args);
208     return 0;
209     }
210    
211    
212     /*
213     * Set new mask's variables to safe values.
214     */
215     void
216     init_mask(mask_t * node)
217     {
218     node->next = NULL;
219     node->body[0] = '\0';
220     node->type = 0;
221     }
222    
223    
224     /*
225     * A new mask entry was declared, create it and set it's
226     * variables accordingly.
227     */
228     int
229     set_mask(char *line, regmatch_t * m, int mmt)
230     {
231 lefcha 1.5 int n, len;
232 lefcha 1.1 mask_t *node;
233     char *bp;
234    
235 lefcha 1.7 len = 0;
236    
237 lefcha 1.1 if (cur_fltr == NULL)
238     return ERROR_CONFIG_PARSE;
239    
240     node = (mask_t *) xmalloc(sizeof(mask_t));
241    
242     init_mask(node);
243    
244     bp = node->body;
245    
246     /* If specified set mask's type. */
247     if (m[2].rm_so != -1 && cur_fltr->masks) {
248     if (!strncasecmp(line + m[2].rm_so, "or", 2)) {
249     node->type = MASK_TYPE_OR;
250     } else
251     node->type = MASK_TYPE_AND;
252     }
253     /* Add NOT if specified. */
254     if (m[3].rm_so != -1) {
255     n = min(m[3].rm_eo - m[3].rm_so,
256     MASK_BODY_LEN - (bp - node->body) - 1);
257     xstrncpy(bp, line + m[3].rm_so, n);
258     string_upper(bp, n);
259     *(bp + n - 1) = ' '; /* In case it's '\t'. */
260     *(bp + n) = '\0';
261     bp += n;
262     }
263     /* Keyword of the search key. */
264     n = min(m[4].rm_eo - m[4].rm_so,
265     MASK_BODY_LEN - (bp - node->body) - 3);
266     xstrncpy(bp, line + m[4].rm_so, n);
267     string_upper(bp, n);
268     *(bp + n) = '\0';
269     bp += n;
270    
271 lefcha 1.5 switch (mmt) {
272     case MASK_MATCH_1:
273 lefcha 1.6 /* Mask is ANSWERED, DELETED, DRAFT, FLAGGED, NEW, OLD, etc. */
274    
275 lefcha 1.5 len = bp - node->body;
276    
277     break;
278    
279     case MASK_MATCH_2:
280 lefcha 1.6 /* Mask is BCC, BODY, CC, FROM, SUBJECT, TEXT, TO. */
281    
282 lefcha 1.1 *(bp++) = ' ';
283    
284 lefcha 1.5 if (*(line + m[5].rm_so) != '"')
285 lefcha 1.1 *(bp++) = '"';
286     *bp = '\0';
287    
288     n = min(m[5].rm_eo - m[5].rm_so,
289     MASK_BODY_LEN - (bp - node->body) - 2);
290     xstrncpy(bp, line + m[5].rm_so, n);
291     *(bp + n) = '\0';
292     bp += n;
293    
294 lefcha 1.5 if (*(line + m[5].rm_so) != '"')
295 lefcha 1.1 *(bp++) = '"';
296     *bp = '\0';
297    
298 lefcha 1.5 len = bp - node->body;
299    
300     break;
301    
302     case MASK_MATCH_3:
303 lefcha 1.6 /* Mask is HEADER. */
304    
305 lefcha 1.5 *(bp++) = ' ';
306    
307     if (*(line + m[5].rm_so) != '"')
308     *(bp++) = '"';
309     *bp = '\0';
310    
311     n = min(m[5].rm_eo - m[5].rm_so,
312     MASK_BODY_LEN - (bp - node->body) - 2);
313     xstrncpy(bp, line + m[5].rm_so, n);
314     *(bp + n) = '\0';
315     bp += n;
316 lefcha 1.1
317 lefcha 1.5 if (*(line + m[5].rm_so) != '"')
318     *(bp++) = '"';
319     *bp = '\0';
320    
321     *(bp++) = ' ';
322    
323     if (*(line + m[6].rm_so) != '"')
324     *(bp++) = '"';
325     *bp = '\0';
326 lefcha 1.1
327 lefcha 1.5 n = min(m[6].rm_eo - m[6].rm_so,
328     MASK_BODY_LEN - (bp - node->body) - 2);
329     xstrncpy(bp, line + m[6].rm_so, n);
330     *(bp + n) = '\0';
331     bp += n;
332 lefcha 1.1
333 lefcha 1.5 if (*(line + m[6].rm_so) != '"')
334     *(bp++) = '"';
335     *bp = '\0';
336 lefcha 1.1
337 lefcha 1.5 len = bp - node->body;
338 lefcha 1.1
339 lefcha 1.5 break;
340 lefcha 1.1
341 lefcha 1.5 case MASK_MATCH_4:
342 lefcha 1.6 /* Mask is LARGER, SMALLER, OLDER, NEWER. */
343    
344 lefcha 1.5 *(bp++) = ' ';
345 lefcha 1.1
346 lefcha 1.5 n = min(m[5].rm_eo - m[5].rm_so,
347     MASK_BODY_LEN - (bp - node->body) - 2);
348     xstrncpy(bp, line + m[5].rm_so, n);
349     *(bp + n) = '\0';
350     bp += n;
351     *bp = '\0';
352 lefcha 1.1
353 lefcha 1.6 /* Mask length after conversion to IMAP4rev1 date format. */
354 lefcha 1.5 if (strstr(node->body, "OLDER"))
355     len = strlen("NOT BEFORE DD-MMM-YYYY");
356     else if (strstr(node->body, "NEWER"))
357     len = strlen("NOT SINCE DD-MMM-YYYY");
358     else
359     len = bp - node->body;
360 lefcha 1.1
361 lefcha 1.5 break;
362     default:
363     break;
364     }
365 lefcha 1.1
366 lefcha 1.5 APPEND_LINKED_LIST(cur_fltr->masks, node, mask);
367 lefcha 1.1
368 lefcha 1.5 cur_fltr->masknum++;
369     cur_fltr->masklen += len;
370 lefcha 1.1
371 lefcha 1.8 debug("MASK: '%s'\n", node->body);
372 lefcha 1.1
373 lefcha 1.5 return 0;
374 lefcha 1.1 }
375    
376    
377     /*
378     * A new job was declared, link filters with mailbox-groups.
379     */
380     int
381     set_job(char *line, regmatch_t * match)
382     {
383     int n;
384     char *ftok, *gtok, *fltr, *mbgrp, *f, *g;
385     filter_t *cf;
386     mboxgrp_t *cg;
387    
388     if (accounts == NULL || filters == NULL || cur_fltr->action.type == 0)
389     return ERROR_CONFIG_PARSE;
390    
391     n = match[1].rm_eo - match[1].rm_so;
392     fltr = (char *)xmalloc(n + 1);
393    
394     f = xstrncpy(fltr, line + match[1].rm_so, n);
395     f[n] = '\0';
396    
397     n = match[2].rm_eo - match[2].rm_so;
398     mbgrp = (char *)xmalloc(n + 1);
399    
400     /* Go through filters. */
401     ftok = strtok_r(f, ",", &f);
402     while (ftok != NULL) {
403     FIND_TREE(filters, ftok, cf);
404     if (cf == NULL)
405     return ERROR_CONFIG_PARSE;
406    
407     g = xstrncpy(mbgrp, line + match[2].rm_so, n);
408     g[n] = '\0';
409    
410     /* Go through mailbox groups. */
411     gtok = strtok_r(g, ",", &g);
412     while (gtok != NULL) {
413     FIND_TREE(mboxgrps, gtok, cg);
414     if (cg == NULL)
415     return ERROR_CONFIG_PARSE;
416     link_mbox_filter(cf, cg);
417    
418     gtok = strtok_r(NULL, ",", &g);
419     }
420    
421     ftok = strtok_r(NULL, ",", &f);
422     }
423    
424     xfree(fltr);
425     xfree(mbgrp);
426    
427     return 0;
428     }
429    
430    
431     /*
432     * Link a filter with a mailbox.
433     */
434     void
435     link_mbox_filter(filter_t * cf, mboxgrp_t * cg)
436     {
437     int i, j, f;
438    
439     for (i = 0; cg->mboxes[i] != NULL; i++) {
440     for (f = j = 0; cg->mboxes[i]->filters[j] != NULL; j++)
441     if (j == MBOX_FILTERS_MAX - 1 ||
442     !strcmp(cf->key, cg->mboxes[i]->filters[j]->key))
443     f = 1;
444    
445     if (f)
446     continue;
447    
448     cg->mboxes[i]->filters[j] = cf;
449     cg->mboxes[i]->filters[j + 1] = NULL;
450    
451     }
452    
453 lefcha 1.8 debug("JOB: '%s' '%s'\n", cf->key, cg->key);
454 lefcha 1.1 }
455    
456    
457     /*
458     * Convert a string of specified size to upper case.
459     */
460     void
461     string_upper(char *str, size_t size)
462     {
463     unsigned int i;
464    
465     for (i = 0; i < size; i++, str++)
466     *str = toupper(*str);
467     }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26