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

Contents of /imapfilter/filter.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (show annotations)
Thu Jul 31 15:46:02 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
File MIME type: text/plain
Broke up program files and created some new header files.

1 #include <stdio.h>
2 #include <string.h>
3 #include <ctype.h>
4
5 #include "config.h"
6 #include "imapfilter.h"
7 #include "account.h"
8 #include "filter.h"
9 #include "struct.h"
10
11
12 extern account_t *accounts;
13 extern mboxgrp_t *mboxgrps;
14
15 filter_t *filters = NULL; /* First node of filters tree. */
16
17 static filter_t *cur_fltr = NULL; /* Current filter. */
18
19
20 void init_filter(filter_t * node);
21
22 void init_mask(mask_t * node);
23 void convert_date(mask_t * node);
24
25 void link_mbox_filter(filter_t * cf, mboxgrp_t * cg);
26
27 void string_upper(char *str, size_t size);
28
29
30 /*
31 * Set new filter's variables to safe values.
32 */
33 void
34 init_filter(filter_t * node)
35 {
36 node->left = node->right = NULL;
37 node->key[0] = '\0';
38 node->mode = FILTER_MODE_AND;
39 node->action.type = node->action.msgflags = 0;
40 node->action.raccount = NULL;
41 node->action.destmbox[0] = node->action.args[0] = '\0';
42 node->masks = NULL;
43 node->masknum = node->masklen = 0;
44 }
45
46
47 /*
48 * A filter entry was declared, create it and set it's variables accordingly.
49 */
50 int
51 set_filter(char *line, regmatch_t * m)
52 {
53 filter_t *node;
54
55 if (cur_fltr != NULL && cur_fltr->action.type == 0)
56 return ERROR_CONFIG_PARSE;
57
58 node = (filter_t *) xmalloc(sizeof(filter_t));
59
60 init_filter(node);
61
62 strncat(node->key, line + m[1].rm_so,
63 min(m[1].rm_eo - m[1].rm_so, KEY_LEN - 1));
64
65 if (m[2].rm_so != -1) {
66 if (!strncasecmp(line + m[2].rm_so + 1, "or", 2))
67 node->mode = FILTER_MODE_OR;
68 else
69 node->mode = FILTER_MODE_AND;
70 }
71 #ifdef DEBUG
72 fprintf(stderr, "debug: FILTER: '%s' %s\n", node->key,
73 (node->mode == FILTER_MODE_OR ? "OR" : "AND"));
74 #endif
75
76 INSERT_TREE(filters, node, filter);
77
78 cur_fltr = node;
79
80 return 0;
81 }
82
83
84 /*
85 * Assign an action to the last declared filter.
86 */
87 int
88 set_action(char *line, regmatch_t * m)
89 {
90 char *c, *cp, *t;
91 account_t *a;
92
93 if (cur_fltr == NULL)
94 return ERROR_CONFIG_PARSE;
95
96 if (!strncasecmp(line + m[1].rm_so, "delete", 6))
97 cur_fltr->action.type = FILTER_ACTION_DELETE;
98 else if (!strncasecmp(line + m[1].rm_so, "copy", 4)) {
99 cur_fltr->action.type = FILTER_ACTION_COPY;
100 if (*(line + m[2].rm_so) == '"' &&
101 *(line + m[2].rm_eo - 1) == '"')
102 strncat(cur_fltr->action.destmbox,
103 line + m[2].rm_so + 1,
104 min(m[2].rm_eo - m[2].rm_so - 2,
105 MBOX_NAME_LEN - 1));
106 else
107 strncat(cur_fltr->action.destmbox, line + m[2].rm_so,
108 min(m[2].rm_eo - m[2].rm_so, MBOX_NAME_LEN - 1));
109 } else if (!strncasecmp(line + m[1].rm_so, "move", 4)) {
110 cur_fltr->action.type = FILTER_ACTION_MOVE;
111 if (*(line + m[3].rm_so) == '"' &&
112 *(line + m[3].rm_eo - 1) == '"')
113 strncat(cur_fltr->action.destmbox,
114 line + m[3].rm_so + 1,
115 min(m[3].rm_eo - m[3].rm_so - 2,
116 MBOX_NAME_LEN - 1));
117 else
118 strncat(cur_fltr->action.destmbox, line + m[3].rm_so,
119 min(m[3].rm_eo - m[3].rm_so, MBOX_NAME_LEN - 1));
120 } else if (!strncasecmp(line + m[1].rm_so, "rcopy", 5)) {
121 cur_fltr->action.type = FILTER_ACTION_RCOPY;
122 for (a = accounts; a; a = a->next)
123 if (!strncasecmp(line + m[4].rm_so, a->key,
124 strlen(a->key)))
125 cur_fltr->action.raccount = a;
126 if (!cur_fltr->action.raccount)
127 return ERROR_CONFIG_PARSE;
128
129 if (*(line + m[5].rm_so) == '"' &&
130 *(line + m[5].rm_eo - 1) == '"')
131 strncat(cur_fltr->action.destmbox,
132 line + m[5].rm_so + 1,
133 min(m[5].rm_eo - m[5].rm_so - 2,
134 MBOX_NAME_LEN - 1));
135 else
136 strncat(cur_fltr->action.destmbox, line + m[5].rm_so,
137 min(m[5].rm_eo - m[5].rm_so, MBOX_NAME_LEN - 1));
138 } else if (!strncasecmp(line + m[1].rm_so, "rmove", 5)) {
139 cur_fltr->action.type = FILTER_ACTION_RMOVE;
140 for (a = accounts; a; a = a->next)
141 if (!strncasecmp(line + m[6].rm_so, a->key,
142 strlen(a->key)))
143 cur_fltr->action.raccount = a;
144 if (!cur_fltr->action.raccount)
145 return ERROR_CONFIG_PARSE;
146
147 if (*(line + m[7].rm_so) == '"' &&
148 *(line + m[7].rm_eo - 1) == '"')
149 strncat(cur_fltr->action.destmbox,
150 line + m[7].rm_so + 1,
151 min(m[7].rm_eo - m[7].rm_so - 2,
152 MBOX_NAME_LEN - 1));
153 else
154 strncat(cur_fltr->action.destmbox, line + m[7].rm_so,
155 min(m[7].rm_eo - m[7].rm_so, MBOX_NAME_LEN - 1));
156 } else if (!strncasecmp(line + m[1].rm_so, "flag", 4)) {
157 if (!strncasecmp(line + m[8].rm_so, "replace", 7))
158 cur_fltr->action.type = FILTER_ACTION_FLAG_REPLACE;
159 else if (!strncasecmp(line + m[8].rm_so, "add", 3))
160 cur_fltr->action.type = FILTER_ACTION_FLAG_ADD;
161 else
162 cur_fltr->action.type = FILTER_ACTION_FLAG_REMOVE;
163
164 c = cp = (char *)malloc(m[9].rm_eo - m[9].rm_so + 1);
165 xstrncpy(c, line + m[9].rm_so, m[9].rm_eo - m[9].rm_so);
166
167 t = strtok_r(c, ",", &c);
168 while (t) {
169 if (!strcasecmp(t, "none")) {
170 if (m[9].rm_eo - m[9].rm_so != strlen("none"))
171 return ERROR_CONFIG_PARSE;
172 } else if (!strcasecmp(t, "seen"))
173 cur_fltr->action.msgflags |= MESSAGE_FLAG_SEEN;
174 else if (!strcasecmp(t, "answered"))
175 cur_fltr->action.msgflags |=
176 MESSAGE_FLAG_ANSWERED;
177 else if (!strcasecmp(t, "flagged"))
178 cur_fltr->action.msgflags |=
179 MESSAGE_FLAG_FLAGGED;
180 else if (!strcasecmp(t, "deleted"))
181 cur_fltr->action.msgflags |=
182 MESSAGE_FLAG_DELETED;
183 else if (!strcasecmp(t, "draft"))
184 cur_fltr->action.msgflags |= MESSAGE_FLAG_DRAFT;
185 else
186 return ERROR_CONFIG_PARSE;
187
188 t = strtok_r(NULL, ",", &c);
189 }
190 xfree(cp);
191 } else if (!strncasecmp(line + m[1].rm_so, "list", 4)) {
192 cur_fltr->action.type = FILTER_ACTION_LIST;
193 }
194 if (m[10].rm_so != -1) {
195 strncat(cur_fltr->action.args, line + m[10].rm_so,
196 min(m[10].rm_eo - m[10].rm_so, ARGS_LEN - 2));
197 while ((c = strchr(cur_fltr->action.args, ',')))
198 *c = ' ';
199 }
200 #ifdef DEBUG
201 fprintf(stderr, "debug: ACTION: %d '%s' '%s' %d '%s'\n",
202 cur_fltr->action.type,
203 (cur_fltr->action.raccount ? cur_fltr->action.raccount->key : ""),
204 cur_fltr->action.destmbox,
205 cur_fltr->action.msgflags,
206 cur_fltr->action.args);
207 #endif
208 return 0;
209 }
210
211
212 /*
213 * Set new mask's variables to safe values.
214 */
215 void
216 init_mask(mask_t * node)
217 {
218 node->next = NULL;
219 node->body[0] = '\0';
220 node->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;
232 mask_t *node;
233 char *bp;
234
235 if (cur_fltr == NULL)
236 return ERROR_CONFIG_PARSE;
237
238 node = (mask_t *) xmalloc(sizeof(mask_t));
239
240 init_mask(node);
241
242 bp = node->body;
243
244 /* If specified set mask's type. */
245 if (m[2].rm_so != -1 && cur_fltr->masks) {
246 if (!strncasecmp(line + m[2].rm_so, "or", 2)) {
247 node->type = MASK_TYPE_OR;
248 } else
249 node->type = MASK_TYPE_AND;
250 }
251 /* Add NOT if specified. */
252 if (m[3].rm_so != -1) {
253 n = min(m[3].rm_eo - m[3].rm_so,
254 MASK_BODY_LEN - (bp - node->body) - 1);
255 xstrncpy(bp, line + m[3].rm_so, n);
256 string_upper(bp, n);
257 *(bp + n - 1) = ' '; /* In case it's '\t'. */
258 *(bp + n) = '\0';
259 bp += n;
260 }
261 /* Keyword of the search key. */
262 n = min(m[4].rm_eo - m[4].rm_so,
263 MASK_BODY_LEN - (bp - node->body) - 3);
264 xstrncpy(bp, line + m[4].rm_so, n);
265 string_upper(bp, n);
266 *(bp + n) = '\0';
267 bp += n;
268
269 if (mmt != MASK_MATCH_1) {
270 *(bp++) = ' ';
271
272 if (mmt != MASK_MATCH_4 && *(line + m[5].rm_so) != '"')
273 *(bp++) = '"';
274 *bp = '\0';
275
276 n = min(m[5].rm_eo - m[5].rm_so,
277 MASK_BODY_LEN - (bp - node->body) - 2);
278 xstrncpy(bp, line + m[5].rm_so, n);
279 *(bp + n) = '\0';
280 bp += n;
281
282 if (mmt != MASK_MATCH_4 && *(line + m[5].rm_so) != '"')
283 *(bp++) = '"';
284 *bp = '\0';
285
286 if (mmt == MASK_MATCH_3) {
287 *(bp++) = ' ';
288
289 if (*(line + m[6].rm_so) != '"')
290 *(bp++) = '"';
291 *bp = '\0';
292
293 n = min(m[6].rm_eo - m[6].rm_so,
294 MASK_BODY_LEN - (bp - node->body) - 2);
295 xstrncpy(bp, line + m[6].rm_so, n);
296 *(bp + n) = '\0';
297 bp += n;
298
299 if (*(line + m[6].rm_so) != '"')
300 *(bp++) = '"';
301 *bp = '\0';
302 }
303 if (mmt == MASK_MATCH_4 && (strstr(node->body, "OLDER") ||
304 strstr(node->body, "NEWER"))) {
305 convert_date(node);
306 bp = node->body + strlen(node->body);
307 }
308 }
309 APPEND_LINKED_LIST(cur_fltr->masks, node, mask);
310
311 cur_fltr->masknum++;
312 cur_fltr->masklen += (bp - node->body);
313
314 #ifdef DEBUG
315 fprintf(stderr, "debug: MASK: '%s'\n", node->body);
316 #endif
317
318 return 0;
319 }
320
321
322 /*
323 * Converts masks related to date filtering, because IMAP servers do not
324 * understand for example "OLDER 3", but "BEFORE 18-Oct-2001" (if
325 * hypothetically current date was 21-Oct-2001).
326 */
327 void
328 convert_date(mask_t * node)
329 {
330 char *cp, *c;
331 char s[16];
332 time_t te;
333 struct tm *tl;
334
335 cp = xstrdup(node->body);
336 node->body[0] = '\0';
337
338 if (strstr(cp, "NOT"))
339 strncat(node->body, "NOT ", 4);
340
341 if ((c = strstr(cp, "OLDER")))
342 strncat(node->body, "BEFORE ", 7);
343 else if ((c = strstr(cp, "NEWER")))
344 strncat(node->body, "SINCE ", 6);
345
346 c += 6;
347
348 te = time(NULL) - (time_t) (strtoul(c, NULL, 10) * 24 * 60 * 60);
349 tl = localtime(&te);
350
351 if (strftime(s, 15, "%d-%b-%Y", tl))
352 strncat(node->body, s, 15);
353
354 xfree(cp);
355 }
356
357
358 /*
359 * A new job was declared, link filters with mailbox-groups.
360 */
361 int
362 set_job(char *line, regmatch_t * match)
363 {
364 int n;
365 char *ftok, *gtok, *fltr, *mbgrp, *f, *g;
366 filter_t *cf;
367 mboxgrp_t *cg;
368
369 if (accounts == NULL || filters == NULL || cur_fltr->action.type == 0)
370 return ERROR_CONFIG_PARSE;
371
372 n = match[1].rm_eo - match[1].rm_so;
373 fltr = (char *)xmalloc(n + 1);
374
375 f = xstrncpy(fltr, line + match[1].rm_so, n);
376 f[n] = '\0';
377
378 n = match[2].rm_eo - match[2].rm_so;
379 mbgrp = (char *)xmalloc(n + 1);
380
381 /* Go through filters. */
382 ftok = strtok_r(f, ",", &f);
383 while (ftok != NULL) {
384 FIND_TREE(filters, ftok, cf);
385 if (cf == NULL)
386 return ERROR_CONFIG_PARSE;
387
388 g = xstrncpy(mbgrp, line + match[2].rm_so, n);
389 g[n] = '\0';
390
391 /* Go through mailbox groups. */
392 gtok = strtok_r(g, ",", &g);
393 while (gtok != NULL) {
394 FIND_TREE(mboxgrps, gtok, cg);
395 if (cg == NULL)
396 return ERROR_CONFIG_PARSE;
397 link_mbox_filter(cf, cg);
398
399 gtok = strtok_r(NULL, ",", &g);
400 }
401
402 ftok = strtok_r(NULL, ",", &f);
403 }
404
405 xfree(fltr);
406 xfree(mbgrp);
407
408 return 0;
409 }
410
411
412 /*
413 * Link a filter with a mailbox.
414 */
415 void
416 link_mbox_filter(filter_t * cf, mboxgrp_t * cg)
417 {
418 int i, j, f;
419
420 for (i = 0; cg->mboxes[i] != NULL; i++) {
421 for (f = j = 0; cg->mboxes[i]->filters[j] != NULL; j++)
422 if (j == MBOX_FILTERS_MAX - 1 ||
423 !strcmp(cf->key, cg->mboxes[i]->filters[j]->key))
424 f = 1;
425
426 if (f)
427 continue;
428
429 cg->mboxes[i]->filters[j] = cf;
430 cg->mboxes[i]->filters[j + 1] = NULL;
431
432 }
433
434 #ifdef DEBUG
435 fprintf(stderr, "debug: JOB: '%s' '%s'\n", cf->key, cg->key);
436 #endif
437 }
438
439
440 /*
441 * Convert a string of specified size to upper case.
442 */
443 void
444 string_upper(char *str, size_t size)
445 {
446 unsigned int i;
447
448 for (i = 0; i < size; i++, str++)
449 *str = toupper(*str);
450 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26