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

Contents of /imapfilter/data.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.23 - (show annotations)
Thu Jan 31 17:06:38 2002 UTC (22 years, 2 months ago) by lefcha
Branch: MAIN
Changes since 1.22: +5 -1 lines
File MIME type: text/plain
Return if no candidate passwords for encryption.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26