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

Contents of /imapfilter/data.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.19 - (show annotations)
Sat Dec 8 14:38:16 2001 UTC (22 years, 3 months ago) by lefcha
Branch: MAIN
Changes since 1.18: +56 -18 lines
File MIME type: text/plain
Namespace support and interactive password asking added.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26