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

Annotation of /imapfilter/filter.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (hide annotations)
Sun Aug 3 16:01:53 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
CVS Tags: release-0_9
Branch point for: release-0_9-patches
Changes since 1.2: +2 -0 lines
File MIME type: text/plain
Added missing stdlib.h header.

1 lefcha 1.1 #include <stdio.h>
2 lefcha 1.3 #include <stdlib.h>
3 lefcha 1.1 #include <string.h>
4     #include <ctype.h>
5 lefcha 1.3 #include <time.h>
6 lefcha 1.1
7     #include "config.h"
8     #include "imapfilter.h"
9     #include "account.h"
10     #include "filter.h"
11     #include "struct.h"
12    
13    
14     extern account_t *accounts;
15     extern mboxgrp_t *mboxgrps;
16    
17     filter_t *filters = NULL; /* First node of filters tree. */
18    
19 lefcha 1.2 filter_t *cur_fltr = NULL; /* Current filter. */
20 lefcha 1.1
21    
22     void init_filter(filter_t * node);
23    
24     void init_mask(mask_t * node);
25     void convert_date(mask_t * node);
26    
27     void link_mbox_filter(filter_t * cf, mboxgrp_t * cg);
28    
29     void string_upper(char *str, size_t size);
30    
31    
32     /*
33     * Set new filter's variables to safe values.
34     */
35     void
36     init_filter(filter_t * node)
37     {
38     node->left = node->right = NULL;
39     node->key[0] = '\0';
40     node->mode = FILTER_MODE_AND;
41     node->action.type = node->action.msgflags = 0;
42     node->action.raccount = NULL;
43     node->action.destmbox[0] = node->action.args[0] = '\0';
44     node->masks = NULL;
45     node->masknum = node->masklen = 0;
46     }
47    
48    
49     /*
50     * A filter entry was declared, create it and set it's variables accordingly.
51     */
52     int
53     set_filter(char *line, regmatch_t * m)
54     {
55     filter_t *node;
56    
57     if (cur_fltr != NULL && cur_fltr->action.type == 0)
58     return ERROR_CONFIG_PARSE;
59    
60     node = (filter_t *) xmalloc(sizeof(filter_t));
61    
62     init_filter(node);
63    
64     strncat(node->key, line + m[1].rm_so,
65     min(m[1].rm_eo - m[1].rm_so, KEY_LEN - 1));
66    
67     if (m[2].rm_so != -1) {
68     if (!strncasecmp(line + m[2].rm_so + 1, "or", 2))
69     node->mode = FILTER_MODE_OR;
70     else
71     node->mode = FILTER_MODE_AND;
72     }
73     #ifdef DEBUG
74     fprintf(stderr, "debug: FILTER: '%s' %s\n", node->key,
75     (node->mode == FILTER_MODE_OR ? "OR" : "AND"));
76     #endif
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     #ifdef DEBUG
203     fprintf(stderr, "debug: ACTION: %d '%s' '%s' %d '%s'\n",
204     cur_fltr->action.type,
205     (cur_fltr->action.raccount ? cur_fltr->action.raccount->key : ""),
206     cur_fltr->action.destmbox,
207     cur_fltr->action.msgflags,
208     cur_fltr->action.args);
209     #endif
210     return 0;
211     }
212    
213    
214     /*
215     * Set new mask's variables to safe values.
216     */
217     void
218     init_mask(mask_t * node)
219     {
220     node->next = NULL;
221     node->body[0] = '\0';
222     node->type = 0;
223     }
224    
225    
226     /*
227     * A new mask entry was declared, create it and set it's
228     * variables accordingly.
229     */
230     int
231     set_mask(char *line, regmatch_t * m, int mmt)
232     {
233     int n;
234     mask_t *node;
235     char *bp;
236    
237     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     if (mmt != MASK_MATCH_1) {
272     *(bp++) = ' ';
273    
274     if (mmt != MASK_MATCH_4 && *(line + m[5].rm_so) != '"')
275     *(bp++) = '"';
276     *bp = '\0';
277    
278     n = min(m[5].rm_eo - m[5].rm_so,
279     MASK_BODY_LEN - (bp - node->body) - 2);
280     xstrncpy(bp, line + m[5].rm_so, n);
281     *(bp + n) = '\0';
282     bp += n;
283    
284     if (mmt != MASK_MATCH_4 && *(line + m[5].rm_so) != '"')
285     *(bp++) = '"';
286     *bp = '\0';
287    
288     if (mmt == MASK_MATCH_3) {
289     *(bp++) = ' ';
290    
291     if (*(line + m[6].rm_so) != '"')
292     *(bp++) = '"';
293     *bp = '\0';
294    
295     n = min(m[6].rm_eo - m[6].rm_so,
296     MASK_BODY_LEN - (bp - node->body) - 2);
297     xstrncpy(bp, line + m[6].rm_so, n);
298     *(bp + n) = '\0';
299     bp += n;
300    
301     if (*(line + m[6].rm_so) != '"')
302     *(bp++) = '"';
303     *bp = '\0';
304     }
305     if (mmt == MASK_MATCH_4 && (strstr(node->body, "OLDER") ||
306     strstr(node->body, "NEWER"))) {
307     convert_date(node);
308     bp = node->body + strlen(node->body);
309     }
310     }
311     APPEND_LINKED_LIST(cur_fltr->masks, node, mask);
312    
313     cur_fltr->masknum++;
314     cur_fltr->masklen += (bp - node->body);
315    
316     #ifdef DEBUG
317     fprintf(stderr, "debug: MASK: '%s'\n", node->body);
318     #endif
319    
320     return 0;
321     }
322    
323    
324     /*
325     * Converts masks related to date filtering, because IMAP servers do not
326     * understand for example "OLDER 3", but "BEFORE 18-Oct-2001" (if
327     * hypothetically current date was 21-Oct-2001).
328     */
329     void
330     convert_date(mask_t * node)
331     {
332     char *cp, *c;
333     char s[16];
334     time_t te;
335     struct tm *tl;
336    
337     cp = xstrdup(node->body);
338     node->body[0] = '\0';
339    
340     if (strstr(cp, "NOT"))
341     strncat(node->body, "NOT ", 4);
342    
343     if ((c = strstr(cp, "OLDER")))
344     strncat(node->body, "BEFORE ", 7);
345     else if ((c = strstr(cp, "NEWER")))
346     strncat(node->body, "SINCE ", 6);
347    
348     c += 6;
349    
350     te = time(NULL) - (time_t) (strtoul(c, NULL, 10) * 24 * 60 * 60);
351     tl = localtime(&te);
352    
353     if (strftime(s, 15, "%d-%b-%Y", tl))
354     strncat(node->body, s, 15);
355    
356     xfree(cp);
357     }
358    
359    
360     /*
361     * A new job was declared, link filters with mailbox-groups.
362     */
363     int
364     set_job(char *line, regmatch_t * match)
365     {
366     int n;
367     char *ftok, *gtok, *fltr, *mbgrp, *f, *g;
368     filter_t *cf;
369     mboxgrp_t *cg;
370    
371     if (accounts == NULL || filters == NULL || cur_fltr->action.type == 0)
372     return ERROR_CONFIG_PARSE;
373    
374     n = match[1].rm_eo - match[1].rm_so;
375     fltr = (char *)xmalloc(n + 1);
376    
377     f = xstrncpy(fltr, line + match[1].rm_so, n);
378     f[n] = '\0';
379    
380     n = match[2].rm_eo - match[2].rm_so;
381     mbgrp = (char *)xmalloc(n + 1);
382    
383     /* Go through filters. */
384     ftok = strtok_r(f, ",", &f);
385     while (ftok != NULL) {
386     FIND_TREE(filters, ftok, cf);
387     if (cf == NULL)
388     return ERROR_CONFIG_PARSE;
389    
390     g = xstrncpy(mbgrp, line + match[2].rm_so, n);
391     g[n] = '\0';
392    
393     /* Go through mailbox groups. */
394     gtok = strtok_r(g, ",", &g);
395     while (gtok != NULL) {
396     FIND_TREE(mboxgrps, gtok, cg);
397     if (cg == NULL)
398     return ERROR_CONFIG_PARSE;
399     link_mbox_filter(cf, cg);
400    
401     gtok = strtok_r(NULL, ",", &g);
402     }
403    
404     ftok = strtok_r(NULL, ",", &f);
405     }
406    
407     xfree(fltr);
408     xfree(mbgrp);
409    
410     return 0;
411     }
412    
413    
414     /*
415     * Link a filter with a mailbox.
416     */
417     void
418     link_mbox_filter(filter_t * cf, mboxgrp_t * cg)
419     {
420     int i, j, f;
421    
422     for (i = 0; cg->mboxes[i] != NULL; i++) {
423     for (f = j = 0; cg->mboxes[i]->filters[j] != NULL; j++)
424     if (j == MBOX_FILTERS_MAX - 1 ||
425     !strcmp(cf->key, cg->mboxes[i]->filters[j]->key))
426     f = 1;
427    
428     if (f)
429     continue;
430    
431     cg->mboxes[i]->filters[j] = cf;
432     cg->mboxes[i]->filters[j + 1] = NULL;
433    
434     }
435    
436     #ifdef DEBUG
437     fprintf(stderr, "debug: JOB: '%s' '%s'\n", cf->key, cg->key);
438     #endif
439     }
440    
441    
442     /*
443     * Convert a string of specified size to upper case.
444     */
445     void
446     string_upper(char *str, size_t size)
447     {
448     unsigned int i;
449    
450     for (i = 0; i < size; i++, str++)
451     *str = toupper(*str);
452     }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26