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

Contents of /imapfilter/filter.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (show annotations)
Sun Aug 3 16:01:53 2003 UTC (20 years, 7 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 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <time.h>
6
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 filter_t *cur_fltr = NULL; /* Current filter. */
20
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