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

Contents of /imapfilter/filter.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.9 - (show annotations)
Fri Feb 13 12:17:16 2004 UTC (20 years, 2 months ago) by lefcha
Branch: MAIN
Changes since 1.8: +109 -109 lines
File MIME type: text/plain
Stylistic changes.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26