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

Annotation of /imapfilter/filter.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.11 - (hide annotations)
Sat Feb 14 19:14:43 2004 UTC (20 years, 2 months ago) by lefcha
Branch: MAIN
CVS Tags: HEAD
Changes since 1.10: +9 -10 lines
File MIME type: text/plain
Indentation.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26