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

Contents of /imapfilter/filter.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (show 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 #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 *cur_fltr = NULL; /* Current filter. */
23
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