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

Contents of /imapfilter/filter.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.11 - (show annotations)
Sat Feb 14 19:14:43 2004 UTC (20 years, 1 month ago) by lefcha
Branch: MAIN
CVS Tags: HEAD
Changes since 1.10: +9 -10 lines
File MIME type: text/plain
Indentation.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26