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

Contents of /imapfilter/data.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.18.2.2 - (show annotations)
Mon Jan 21 15:44:51 2002 UTC (22 years, 3 months ago) by lefcha
Branch: release-0_7-patches
Changes since 1.18.2.1: +17 -6 lines
File MIME type: text/plain
Spaces inside mailbox names.

1 #include <stdio.h>
2 #include <errno.h>
3 #include <sys/types.h>
4 #include <regex.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <limits.h>
8 #include <sys/stat.h>
9 #include <ctype.h>
10 #include <time.h>
11
12 #include "config.h"
13 #include "imapfilter.h"
14 #include "data.h"
15
16
17 account_t *accounts = NULL; /* First node of accounts linked list. */
18 filter_t *filters = NULL; /* First node of filters tree. */
19
20 static mboxgrp_t *mboxgrps = NULL; /* First node of mailbox-groups
21 tree. */
22
23 static account_t *cur_acct = NULL; /* Current account. */
24 static filter_t *cur_fltr = NULL; /* Current filter. */
25
26
27 /*
28 * Set new account's variables to safe values.
29 */
30 void init_account(account_t * node)
31 {
32 node->next = NULL;
33 node->server[0] = node->username[0] = node->password[0] = 0;
34 node->port = 143;
35 #ifdef SSL_TLS
36 node->ssl = SSL_DISABLED;
37 #endif
38 node->mboxes = NULL;
39 }
40
41
42 /*
43 * Append account node to linked list.
44 */
45 void append_account(account_t * node)
46 {
47 account_t *pos;
48 account_t **app;
49
50 APPEND_LINKED_LIST(accounts, node, pos, app);
51 }
52
53
54 /*
55 * A new account entry was declared. Create it and set it's variables
56 * accordingly.
57 */
58 int set_account(char *line, regmatch_t * match)
59 {
60 int n;
61 char p[6];
62 account_t *node;
63
64 node = (account_t *) create_node(sizeof(account_t));
65
66 init_account(node);
67
68 strncat(node->username, line + match[1].rm_so,
69 min(match[1].rm_eo - match[1].rm_so, USERNAME_LEN - 1));
70 if (strchr(node->username, '%'))
71 if (string_decode(node->username))
72 return ERROR_CONFIG_PARSE;
73 #ifdef DEBUG
74 printf("debug: USERNAME: '%s'\n", node->username);
75 #endif
76
77 strncat(node->password, line + match[2].rm_so,
78 min(match[2].rm_eo - match[2].rm_so, PASSWORD_LEN - 1));
79 if (strchr(node->password, '%'))
80 if (string_decode(node->password))
81 return ERROR_CONFIG_PARSE;
82 #ifdef DEBUG
83 printf("debug: PASSWORD: '%s'\n", node->password);
84 #endif
85
86 strncat(node->server, line + match[3].rm_so,
87 min(match[3].rm_eo - match[3].rm_so, SERVER_LEN - 1));
88 #ifdef DEBUG
89 printf("debug: SERVER: '%s'\n", node->server);
90 #endif
91
92 if (match[4].rm_so != -1) {
93 n = min(match[4].rm_eo - match[4].rm_so - 1, 5);
94 xstrncpy(p, line + match[4].rm_so + 1, n);
95 p[n] = 0;
96 node->port = strtoul(p, NULL, 10);
97 #ifdef DEBUG
98 printf("debug: PORT: %d\n", node->port);
99 #endif
100 }
101 #ifdef SSL_TLS
102 if (match[5].rm_so != -1) {
103 if (match[4].rm_so == -1)
104 node->port = 993;
105
106 if (strcasestr(line + match[5].rm_so, "ssl3"))
107 node->ssl = SSL_SSL_V3;
108 else if (strcasestr(line + match[5].rm_so, "tls1"))
109 node->ssl = SSL_TLS_V1;
110 else
111 node->ssl = SSL_SSL_V2;
112 }
113 #endif
114 append_account(node);
115 cur_acct = node;
116
117 return 0;
118 }
119
120
121 /*
122 * Set new mailbox-group's variables to safe values.
123 */
124 void init_mboxgrp(mboxgrp_t * node)
125 {
126 node->left = node->right = NULL;
127 node->key[0] = 0;
128 node->mboxes[0] = NULL;
129 }
130
131
132 /*
133 * Insert mailbox-group node in tree.
134 */
135 void insert_mboxgrp(mboxgrp_t * node)
136 {
137 int cmp;
138 mboxgrp_t *pos;
139 mboxgrp_t **ins;
140
141 INSERT_TREE(mboxgrps, node, pos, ins, cmp);
142 }
143
144
145 /*
146 * A new mailbox-group entry was declared. Create it and set it's variables
147 * accordingly.
148 */
149 int set_mboxgrp(char *line, regmatch_t * match)
150 {
151 mboxgrp_t *node;
152 char mboxs[LINE_MAX];
153
154 mboxs[0] = 0;
155
156 if (!accounts)
157 return ERROR_CONFIG_PARSE;
158
159 node = (mboxgrp_t *) create_node(sizeof(mboxgrp_t));
160
161 init_mboxgrp(node);
162
163 strncat(node->key, line + match[1].rm_so,
164 min(match[1].rm_eo - match[1].rm_so, KEY_LEN - 1));
165
166 #ifdef DEBUG
167 printf("debug: FOLDER: '%s'\n", node->key);
168 #endif
169
170 strncat(mboxs, line + match[2].rm_so,
171 min(match[2].rm_eo - match[2].rm_so, LINE_MAX - 1));
172
173 process_mboxgrp(node, mboxs);
174
175 insert_mboxgrp(node);
176
177 return 0;
178 }
179
180
181 /*
182 * Calls set_mbox() in order to create mailboxes that are part of
183 * the mailbox-group.
184 */
185 void process_mboxgrp(mboxgrp_t * node, char *mboxs)
186 {
187 unsigned int i = 0;
188 const char *delim = ",";
189 char *tok;
190
191 while (i < MBOXGRP_MBOXES_MAX - 1 && (tok = strsep(&mboxs, delim))) {
192 node->mboxes[i] = (mbox_t *) set_mbox(tok);
193 node->mboxes[++i] = NULL;
194 }
195 }
196
197
198 /*
199 * Find in the mailbox-group tree, the node with the specified key,
200 * and return a pointer to it.
201 */
202 mboxgrp_t *find_mboxgrp(char *key)
203 {
204 int cmp;
205 mboxgrp_t *pos;
206
207 FIND_TREE(mboxgrps, key, pos, cmp);
208 }
209
210
211 /*
212 * Set new mailbox's variables to safe values.
213 */
214 void init_mbox(mbox_t * node)
215 {
216 node->next = NULL;
217 node->name[0] = 0;
218 node->filters[0] = NULL;
219 }
220
221
222 /*
223 * Append mailbox node to linked list.
224 */
225 void append_mbox(mbox_t * node)
226 {
227 mbox_t *pos;
228 mbox_t **ins;
229
230 APPEND_LINKED_LIST(cur_acct->mboxes, node, pos, ins);
231 }
232
233
234 /*
235 * A new mailbox was declared, create it and set it's variables accordingly.
236 */
237 mbox_t *set_mbox(char *name)
238 {
239 mbox_t *node;
240
241 node = (mbox_t *) create_node(sizeof(mbox_t));
242
243 init_mbox(node);
244
245 if (*name == '"' && *(name + strlen(name) - 1) == '"')
246 strncat(node->name, name + 1, min(strlen(name) - 2, MBOX_NAME_LEN - 1));
247 else
248 strncat(node->name, name, min(strlen(name), MBOX_NAME_LEN - 1));
249
250 #ifdef DEBUG
251 printf("debug: MBOX: '%s'\n", node->name);
252 #endif
253
254 append_mbox(node);
255
256 return node;
257 }
258
259
260 /*
261 * Set new filter's variables to safe values.
262 */
263 void init_filter(filter_t * node)
264 {
265 node->left = node->right = NULL;
266 node->key[0] = 0;
267 node->mode = FILTER_MODE_AND;
268 node->action.type = 0;
269 node->action.destmbox[0] = node->action.args[0] = 0;
270 node->masks = NULL;
271 node->masknum = node->masklen = 0;
272 }
273
274
275 /*
276 * Insert filter node to tree.
277 */
278 void insert_filter(filter_t * node)
279 {
280 int cmp;
281 filter_t *pos;
282 filter_t **ins;
283
284 INSERT_TREE(filters, node, pos, ins, cmp);
285 }
286
287
288 /*
289 * A filter entry was declared, create it and set it's variables accordingly.
290 */
291 int set_filter(char *line, regmatch_t * match)
292 {
293 filter_t *node;
294
295 if (cur_fltr && !cur_fltr->action.type)
296 return ERROR_CONFIG_PARSE;
297
298 node = (filter_t *) create_node(sizeof(filter_t));
299
300 init_filter(node);
301
302 strncat(node->key, line + match[1].rm_so,
303 min(match[1].rm_eo - match[1].rm_so, KEY_LEN - 1));
304
305 if (match[2].rm_so != -1) {
306 if (!strncasecmp(line + match[2].rm_so + 1, "or", 2))
307 node->mode = FILTER_MODE_OR;
308 else
309 node->mode = FILTER_MODE_AND;
310 }
311 #ifdef DEBUG
312 printf("debug: FILTER: '%s' %s\n", node->key,
313 (node->mode == FILTER_MODE_OR ? "OR" : "AND"));
314 #endif
315
316 insert_filter(node);
317 cur_fltr = node;
318
319 return 0;
320 }
321
322
323 /*
324 * Find in the filter tree, the node with the specified key and
325 * return a pointer to it.
326 */
327 filter_t *find_filter(char *key)
328 {
329 int cmp;
330 filter_t *pos;
331
332 FIND_TREE(filters, key, pos, cmp);
333 }
334
335
336 /*
337 * Assign an action to the last declared filter.
338 */
339 int set_action(char *line, regmatch_t * match)
340 {
341 if (!cur_fltr)
342 return ERROR_CONFIG_PARSE;
343
344 if (!strncasecmp(line + match[1].rm_so, "delete", 6))
345 cur_fltr->action.type = FILTER_ACTION_DELETE;
346 else if (!strncasecmp(line + match[1].rm_so, "copy", 4)) {
347 cur_fltr->action.type = FILTER_ACTION_COPY;
348 if (*(line + match[2].rm_so) == '"' && *(line + match[2].rm_eo - 1) == '"')
349 strncat(cur_fltr->action.destmbox, line + match[2].rm_so + 1,
350 min(match[2].rm_eo - match[2].rm_so - 2, MBOX_NAME_LEN - 1));
351 else
352 strncat(cur_fltr->action.destmbox, line + match[2].rm_so,
353 min(match[2].rm_eo - match[2].rm_so, MBOX_NAME_LEN - 1));
354 } else if (!strncasecmp(line + match[1].rm_so, "move", 4)) {
355 cur_fltr->action.type = FILTER_ACTION_MOVE;
356 if (*(line + match[3].rm_so) == '"' && *(line + match[3].rm_eo - 1) == '"')
357 strncat(cur_fltr->action.destmbox, line + match[3].rm_so + 1,
358 min(match[3].rm_eo - match[3].rm_so - 2, MBOX_NAME_LEN - 1));
359 else
360 strncat(cur_fltr->action.destmbox, line + match[3].rm_so,
361 min(match[3].rm_eo - match[3].rm_so, MBOX_NAME_LEN - 1));
362 } else if (!strncasecmp(line + match[1].rm_so, "list", 4))
363 cur_fltr->action.type = FILTER_ACTION_LIST;
364
365 if (match[4].rm_so != -1)
366 strncat(cur_fltr->action.args, line + match[4].rm_so,
367 min(match[4].rm_eo - match[4].rm_so, ARGS_LEN - 1));
368
369 return 0;
370
371 }
372
373
374 /*
375 * Set new mask's variables to safe values.
376 */
377 void init_mask(mask_t * node)
378 {
379 node->next = NULL;
380 node->body[0] = 0;
381 node->type = 0;
382 }
383
384
385 /*
386 * Append mask node to linked list.
387 */
388 void append_mask(mask_t * node)
389 {
390 mask_t *pos;
391 mask_t **app;
392
393 APPEND_LINKED_LIST(cur_fltr->masks, node, pos, app);
394 }
395
396
397 /*
398 * A new mask entry was declared, create it and set it's
399 * variables accordingly.
400 */
401 int set_mask(char *line, regmatch_t * match)
402 {
403 int n, i, f = 0;
404 mask_t *node;
405 char *bp;
406
407 if (!cur_fltr)
408 return ERROR_CONFIG_PARSE;
409
410 node = (mask_t *) create_node(sizeof(mask_t));
411
412 init_mask(node);
413
414 bp = node->body;
415
416 /* If specified set mask's type. */
417 if (match[2].rm_so != -1 && cur_fltr->masks) {
418 if (!strncasecmp(line + match[2].rm_so, "or", 2))
419 node->type = MASK_TYPE_OR;
420 else
421 node->type = MASK_TYPE_AND;
422 }
423 /* Add NOT if specified. */
424 if (match[3].rm_so != -1) {
425 n = min(match[3].rm_eo - match[3].rm_so,
426 MASK_BODY_LEN - (bp - node->body) - 1);
427 xstrncpy(bp, line + match[3].rm_so, n);
428 string_upper(bp, n);
429 *(bp + n - 1) = ' '; /* In case it's '\t'. */
430 *(bp + n) = 0;
431 bp += n;
432 }
433 /* Keyword of the search key. */
434 n = min(match[4].rm_eo - match[4].rm_so,
435 MASK_BODY_LEN - (bp - node->body) - 3);
436 xstrncpy(bp, line + match[4].rm_so, n);
437 string_upper(bp, n);
438 *(bp + n) = 0;
439 bp += n;
440
441 /* Body of the search key (string/number). */
442 for (i = 5; i <= 6; i++)
443 if (match[i].rm_so != -1) {
444 *(bp++) = ' ';
445
446 /* Add '"' if not supplied and search key not a number. */
447 if (match[6].rm_so == -1 &&
448 (strstr(node->body, "LARGER") ||
449 strstr(node->body, "SMALLER") ||
450 strstr(node->body, "OLDER") ||
451 strstr(node->body, "NEWER")))
452 f = 1;
453 else if (*(line + match[i].rm_so) != '"')
454 *(bp++) = '"';
455
456 *bp = 0;
457
458 n = min(match[i].rm_eo - match[i].rm_so,
459 MASK_BODY_LEN - (bp - node->body) - 2);
460 xstrncpy(bp, line + match[i].rm_so, n);
461 *(bp + n) = 0;
462 bp += n;
463
464 if (*(line + match[i].rm_so) != '"' && !f)
465 *(bp++) = '"';
466 *bp = 0;
467 }
468 if (f && (strstr(node->body, "OLDER") || strstr(node->body, "NEWER"))) {
469 convert_date(node);
470 bp = node->body + strlen(node->body);
471 }
472 append_mask(node);
473
474 cur_fltr->masknum++;
475 cur_fltr->masklen += (bp - node->body);
476
477
478 #ifdef DEBUG
479 printf("debug: MASK: '%s'\n", node->body);
480 #endif
481
482 return 0;
483 }
484
485
486 /*
487 * Converts masks related to date filtering, because IMAP servers do not
488 * understand for example "OLDER 3", but "BEFORE 18-Oct-2001" (if
489 * hypothetically current date was 21-Oct-2001).
490 */
491 void convert_date(mask_t * node)
492 {
493 char *cp, *c;
494 char s[16];
495 time_t t;
496 struct tm *bt;
497
498 cp = xstrdup(node->body);
499 node->body[0] = 0;
500
501 if (strstr(cp, "NOT"))
502 strncat(node->body, "NOT ", 4);
503
504 if ((c = strstr(cp, "OLDER")))
505 strncat(node->body, "BEFORE ", 7);
506 else if ((c = strstr(cp, "NEWER")))
507 strncat(node->body, "SINCE ", 6);
508
509 c += 6;
510
511 t = time(NULL) - (time_t) (strtoul(c, NULL, 10) * 24 * 60 * 60);
512 bt = localtime(&t);
513
514 if (strftime(s, 15, "%d-%b-%Y", bt))
515 strncat(node->body, s, 15);
516
517 free(cp);
518 }
519
520
521 /*
522 * A new job was declared, link filters with mailbox-groups.
523 */
524 int set_job(char *line, regmatch_t * match)
525 {
526 int n;
527 const char *delim = ",";
528 char *ftok, *gtok, *fltr, *mbgrp, *f, *g;
529 filter_t *cf;
530 mboxgrp_t *cg;
531
532 if (!accounts || !filters || !cur_fltr->action.type)
533 return ERROR_CONFIG_PARSE;
534
535 n = match[1].rm_eo - match[1].rm_so;
536 fltr = (char *) xmalloc(n + 1);
537
538 f = xstrncpy(fltr, line + match[1].rm_so, n);
539 f[n] = 0;
540
541 n = match[2].rm_eo - match[2].rm_so;
542 mbgrp = (char *) xmalloc(n + 1);
543
544 /* Go through filters. */
545 while ((ftok = strsep(&f, delim))) {
546 cf = (filter_t *) find_filter(ftok);
547 if (!cf)
548 return ERROR_CONFIG_PARSE;
549
550 g = xstrncpy(mbgrp, line + match[2].rm_so, n);
551 g[n] = 0;
552
553 /* Go through mailbox groups. */
554 while ((gtok = strsep(&g, delim))) {
555 cg = (mboxgrp_t *) find_mboxgrp(gtok);
556 if (!cg)
557 return ERROR_CONFIG_PARSE;
558 link_mbox_filter(cf, cg);
559 }
560 }
561
562 free(fltr);
563 free(mbgrp);
564
565 return 0;
566 }
567
568
569 /*
570 * Link a filter with a mailbox.
571 */
572 void link_mbox_filter(filter_t * cf, mboxgrp_t * cg)
573 {
574 int i, j, f;
575
576 for (i = 0; cg->mboxes[i]; i++) {
577 for (f = j = 0; cg->mboxes[i]->filters[j]; j++)
578 if (j == MBOX_FILTERS_MAX - 1 ||
579 !strncmp(cf->key, cg->mboxes[i]->filters[j]->key, KEY_LEN))
580 f = 1;
581
582 if (f)
583 continue;
584
585 cg->mboxes[i]->filters[j] = cf;
586 cg->mboxes[i]->filters[j + 1] = NULL;
587
588 }
589
590 #ifdef DEBUG
591 printf("debug: JOB: '%s' '%s'\n", cf->key, cg->key);
592 #endif
593 }
594
595
596 /*
597 * Free allocated memory of data structures that are not needed anymore.
598 */
599 void destroy_data(void)
600 {
601 destroy_mboxgrp(mboxgrps);
602 }
603
604
605 /*
606 * Go through the mailbox-group tree, and free the allocated memory of
607 * each node.
608 */
609 void destroy_mboxgrp(mboxgrp_t * node)
610 {
611 if (node->left) {
612 destroy_mboxgrp(node->left);
613 node->left = NULL;
614 }
615 if (node->right) {
616 destroy_mboxgrp(node->right);
617 node->right = NULL;
618 }
619 #ifdef DEBUG
620 printf("debug: deleting FOLDER: '%s'\n", node->key);
621 #endif
622
623 free(node);
624 }
625
626
627 /*
628 * Overwrite the memory space that contains the user's passwords.
629 */
630 void overwrite_passwords(void)
631 {
632 account_t *a;
633
634 for (a = accounts; a; a = a->next)
635 memset(a->password, 0, PASSWORD_LEN);
636 }
637
638
639 /*
640 * Convert a string of specified size to upper case.
641 */
642 void string_upper(char *str, size_t size)
643 {
644 unsigned int i;
645
646 for (i = 0; i < size; i++, str++)
647 *str = toupper(*str);
648 }
649
650
651 /*
652 * Decode the character triplet, consisting of the character '%'
653 * followed by two hexadecimal digits to its corresponding ASCII
654 * character (described in Section 2.2 of RFC 1738).
655 */
656 int string_decode(char *str)
657 {
658 char *c;
659 char hex[3];
660
661 c = str;
662
663 while (*c) {
664 if (*c == '%') {
665 if (!isxdigit(*(c + 1)) || !isxdigit(*(c + 2)))
666 return ERROR_CONFIG_PARSE;
667
668 xstrncpy(hex, ++c, 2);
669 hex[2] = 0;
670
671 if (!isprint(*str = (char) strtoul(hex, NULL, 16)))
672 return ERROR_CONFIG_PARSE;
673
674 str++;
675 c += 2;
676 } else
677 *(str++) = *(c++);
678 }
679 *str = 0;
680
681 return 0;
682 }
683
684
685 /*
686 * Convert the names of personal mailboxes using the namespace specified
687 * by the mail server.
688 */
689 char *apply_namespace(char *mbox, char *prefix, char delim)
690 {
691 static char m[MBOX_NAME_LEN];
692 char *c;
693
694 if ((!prefix[0] && !delim) || (!prefix[0] && delim == '/')
695 || !strcasecmp(mbox, "INBOX"))
696 return mbox;
697
698 m[0] = 0;
699 strncat(m, prefix, MBOX_NAME_LEN - 1);
700 strncat(m, mbox, MBOX_NAME_LEN - strlen(m) - 1);
701
702 c = m;
703 while ((c = strchr(c, '/')))
704 *(c++) = delim;
705
706 #ifdef DEBUG
707 printf("debug: MAILBOX: '%s'\n", m);
708 #endif
709
710 return m;
711 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26