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

Annotation of /imapfilter/filter.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (hide annotations)
Fri Aug 8 00:18:45 2003 UTC (20 years, 7 months ago) by lefcha
Branch: MAIN
Changes since 1.3: +3 -0 lines
File MIME type: text/plain
Corrected header includes.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26