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

Annotation of /imapfilter/filter.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (hide annotations)
Fri Aug 1 13:30:04 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.1: +1 -1 lines
File MIME type: text/plain
When destroying data structures cur_acct and cur_fltr must be also reset.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26