Initial commit of the port of CMU's sieve engine. It builds, and some
actions work, but has seen very little use.
Showing
41 changed files
with
8017 additions
and
0 deletions
sieve/.cvsignore
0 → 100644
sieve/AUTHORS
0 → 100644
sieve/COPYING
0 → 100644
1 | /* cmu-sieve | ||
2 | * Larry Greenfield | ||
3 | * $Id$ | ||
4 | */ | ||
5 | /*********************************************************** | ||
6 | Copyright 1998 by Carnegie Mellon University | ||
7 | |||
8 | All Rights Reserved | ||
9 | |||
10 | Permission to use, copy, modify, and distribute this software and its | ||
11 | documentation for any purpose and without fee is hereby granted, | ||
12 | provided that the above copyright notice appear in all copies and that | ||
13 | both that copyright notice and this permission notice appear in | ||
14 | supporting documentation, and that the name of Carnegie Mellon | ||
15 | University not be used in advertising or publicity pertaining to | ||
16 | distribution of the software without specific, written prior | ||
17 | permission. | ||
18 | |||
19 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
20 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
21 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
22 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
23 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
24 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
25 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
26 | ******************************************************************/ |
sieve/Makefile.am
0 → 100644
1 | CFLAGS = -Wall -pedantic -g -DTESTING | ||
2 | INCLUDES = -I${top_srcdir}/include -I${top_srcdir}/lib | ||
3 | |||
4 | MOSTLYCLEANFILES= | ||
5 | CLEANFILES= | ||
6 | DISTCLEANFILES= | ||
7 | MAINTAINERCLEANFILES=\ | ||
8 | sieve-gram.c sieve-gram.h \ | ||
9 | sieve-lex.c \ | ||
10 | addr-lex.c \ | ||
11 | addr.c addr.h | ||
12 | |||
13 | bin_PROGRAMS = test sieve | ||
14 | |||
15 | SRC = \ | ||
16 | addr-lex.c \ | ||
17 | addr.c \ | ||
18 | comparator.c \ | ||
19 | imparse.c \ | ||
20 | interp.c \ | ||
21 | md5.c \ | ||
22 | message.c \ | ||
23 | parseaddr.c \ | ||
24 | script.c \ | ||
25 | sieve-lex.c \ | ||
26 | sieve-gram.c \ | ||
27 | sieve_err.c \ | ||
28 | svfield.c \ | ||
29 | tree.c \ | ||
30 | util.c \ | ||
31 | xmalloc.c | ||
32 | |||
33 | test_DEPENDENCIES = | ||
34 | test_LDADD = | ||
35 | test_SOURCES = \ | ||
36 | test.c \ | ||
37 | ${SRC} | ||
38 | |||
39 | |||
40 | sieve_DEPENDENCIES = ../mailbox/libmailbox.la | ||
41 | sieve_LDADD = ../mailbox/libmailbox.la ../lib/libmailutils.a | ||
42 | sieve_SOURCES = \ | ||
43 | sieve.c \ | ||
44 | ${SRC} | ||
45 | |||
46 | YACC = bison -y | ||
47 | YFLAGS = -d | ||
48 | LEX = flex | ||
49 | |||
50 | addr-lex.c: addr-lex.l addr.h | ||
51 | $(LEX) -t -Paddr addr-lex.l > $@ | ||
52 | |||
53 | addr.c addr.h: addr.y | ||
54 | $(YACC) $(YFLAGS) -p addr addr.y | ||
55 | mv -f y.tab.c addr.c | ||
56 | mv -f y.tab.h addr.h | ||
57 | |||
58 | sieve-lex.c: sieve-lex.l sieve-gram.h | ||
59 | $(LEX) -t sieve-lex.l > $@ | ||
60 | |||
61 | sieve-gram.c sieve-gram.h: sieve-gram.y | ||
62 | $(YACC) $(YFLAGS) sieve-gram.y | ||
63 | mv -f y.tab.c sieve-gram.c | ||
64 | mv -f y.tab.h sieve-gram.h | ||
65 | |||
66 | comparator.o: sieve-gram.h | ||
67 | script.o: sieve-gram.h | ||
68 | tree.o: sieve-gram.h | ||
69 |
sieve/NEWS
0 → 100644
1 | $Id$ | ||
2 | |||
3 | CMU Sieve 2.0 | ||
4 | ------------- | ||
5 | |||
6 | - Compliant with draft-showalter-sieve-11.txt and | ||
7 | draft-showalter-sieve-vacation-03.txt. | ||
8 | |||
9 | - Added support for the regex, imapflags, notify and subaddress extensions. | ||
10 | See README for references. | ||
11 | |||
12 | - Verifies email addresses in redirect and vacation actions are syntactically | ||
13 | correct (compliant with RFC822). | ||
14 | |||
15 | - Run-time error reporting. | ||
16 | |||
17 | - Changed callback interface to use callback contexts instead of individual | ||
18 | parameters. Also added an error string buffer for run-time error reporting. | ||
19 | |||
20 | - Vacation will not reply to any message containing an "auto-submitted" | ||
21 | header containing anything other than "no". | ||
22 | |||
23 | CMU Sieve 1.4 | ||
24 | ------------- | ||
25 | |||
26 | Now included with imapd distribution (hell, why not?). | ||
27 | |||
28 | Error returning and recovering: | ||
29 | added error recovering to the parser (but not much!) | ||
30 | added error messages to the parser | ||
31 | |||
32 | Working on error returning and error recovering. | ||
33 | run-time errors | ||
34 | detect some errors in lexer? | ||
35 | |||
36 | Working on even better parsing: | ||
37 | verify addresses could be addresses | ||
38 | verify mailboxes could be mailboxes | ||
39 | verify outgoing headers can be headers | ||
40 | |||
41 | CMU Sieve 1.3 | ||
42 | ------------- | ||
43 | |||
44 | Changed for integration with cyrus deliver. | ||
45 | |||
46 | CMU Sieve 1.2 | ||
47 | ------------- | ||
48 | |||
49 | Added additional callbacks (ok, so I want to make my integration with deliver | ||
50 | easier) and envelope and vacation support. | ||
51 | |||
52 | Made it compile without libcyrus. | ||
53 | It should compile without libcyrus, but then it does not implement the | ||
54 | "address" test. That's just too much work to do when I have a neato | ||
55 | library to do it for me. | ||
56 | |||
57 | Todo: | ||
58 | - regex matching | ||
59 | |||
60 | CMU Sieve 1.1 | ||
61 | ------------- | ||
62 | |||
63 | - Updated to draft-showalter-sieve-07bis.txt | ||
64 | |||
65 | - Simple API (see sieve_interface.h; currently mostly undocumented) | ||
66 | |||
67 | - Implements all of the optional features except "envelope" | ||
68 | |||
69 | - Maintains "if it parses, it probably runs" behavior. (Goal: minimize | ||
70 | run-time errors.) | ||
71 | |||
72 | CMU Sieve 1.0 | ||
73 | ------------- | ||
74 | |||
75 | - prototype implementation |
sieve/README
0 → 100644
1 | $Id$ | ||
2 | |||
3 | CMU Sieve 2.0 | ||
4 | ------------- | ||
5 | |||
6 | This code is typically distributed as part of Cyrus imapd 1.6 and higher. | ||
7 | This code will be configured and compiled from the cyrus-imapd directory. | ||
8 | |||
9 | Notes on implementation | ||
10 | ----------------------- | ||
11 | |||
12 | This is an implementation of a simple Sieve API. This API is | ||
13 | well-suited for incorporating in other programs, but is not | ||
14 | extensible. (If there is interest, we may implement an extensible API | ||
15 | in the future.) | ||
16 | |||
17 | If you wish to compile Sieve without compiling all of imapd, you'll | ||
18 | have to create a Makefile for it. I recommend you use Makefile.in as | ||
19 | a guide. | ||
20 | |||
21 | It should compile without libcyrus, but then it does not implement the | ||
22 | "address" test. That's just too much work to do when I have a neato | ||
23 | library to do it for me. | ||
24 | |||
25 | There's a simple "test" application included, which is not built by | ||
26 | default (type "make test" to build it). It expects: | ||
27 | |||
28 | test <message> <script> | ||
29 | |||
30 | And prints out the actions taken or errors encountered. (This | ||
31 | implementation will attempt all the actions or no actions.) | ||
32 | |||
33 | Questions and comments to: | ||
34 | Larry Greenfield (leg+sieve@andrew.cmu.edu) | ||
35 | |||
36 | References: | ||
37 | |||
38 | [SIEVE] Showalter, T., "Sieve: A Mail Filtering Language", | ||
39 | draft-showalter-sieve-11.txt, May, 2000. | ||
40 | |||
41 | [VACATION] Showalter, T., "Sieve: Vacation Extension", | ||
42 | draft-showalter-sieve-vacation-03.txt, May, 2000. | ||
43 | |||
44 | [IMAPFLAGS] Melnikov, A., "Sieve -- IMAP flag extension", | ||
45 | draft-melnikov-sieve-imapflags-02.txt, June, 1999. | ||
46 | |||
47 | [NOTIFY] Martin, T., "Sieve -- An extension for providing instant | ||
48 | notifications", draft-ietf-sieve-notify-00.txt, February, 2000. | ||
49 | |||
50 | [REGEX] Murchison, K., "Sieve: Regular Expression Extension", | ||
51 | draft-murchison-sieve-regex-01.txt, March, 2000. | ||
52 | |||
53 | [SUBADDR] Murchison, K., "Sieve: Subaddress Extension", | ||
54 | draft-murchison-sieve-subaddress-00.txt, March, 2000. |
sieve/addr-lex.l
0 → 100644
1 | %{ | ||
2 | /* | ||
3 | * addr-lex.l -- RFC 822 address lexer | ||
4 | */ | ||
5 | |||
6 | #include "addr.h" | ||
7 | #include <string.h> | ||
8 | |||
9 | #undef YY_INPUT | ||
10 | #define YY_INPUT(b, r, ms) (r = addrinput(b, ms)) | ||
11 | |||
12 | int addrinput(char *buf, int max_size); | ||
13 | void addrerror(const char *); | ||
14 | |||
15 | static int ncom; /* number of open comments */ | ||
16 | %} | ||
17 | |||
18 | %option noyywrap | ||
19 | %x QSTRING DOMAINLIT COMMENT | ||
20 | |||
21 | %% | ||
22 | |||
23 | \" { BEGIN QSTRING; return yytext[0]; } | ||
24 | \[ { BEGIN DOMAINLIT; return yytext[0]; } | ||
25 | \( { ncom = 1; BEGIN COMMENT; } | ||
26 | \) { addrerror("address parse error, " | ||
27 | "unexpected `')'' " | ||
28 | "(unbalanced comment)"); | ||
29 | yyterminate(); } | ||
30 | |||
31 | [^\(\)<>@,;:\\".\[\] \n\r]+ return ATOM; | ||
32 | |||
33 | [\t \n\r]+ /* ignore whitespace */ | ||
34 | . return yytext[0]; | ||
35 | |||
36 | <QSTRING>([^\n\r"\\]|\\.)* return QTEXT; | ||
37 | <QSTRING>\" { BEGIN INITIAL; return yytext[0]; } | ||
38 | |||
39 | <DOMAINLIT>([^\[\]\n\r\\]|\\.)* return DTEXT; | ||
40 | <DOMAINLIT>\] { BEGIN INITIAL; return yytext[0]; } | ||
41 | |||
42 | <COMMENT>([^\(\)\n\0\\]|\\.)* /* ignore comments */ | ||
43 | <COMMENT>\( ncom++; | ||
44 | <COMMENT>\) { ncom--; if (ncom == 0) BEGIN INITIAL; } | ||
45 | <COMMENT><<EOF>> { addrerror("address parse error, " | ||
46 | "expecting `')'' " | ||
47 | "(unterminated comment)"); | ||
48 | yyterminate(); } | ||
49 | |||
50 | %% | ||
51 | |||
52 | /* take input from address string provided by sieve parser */ | ||
53 | int addrinput(char *buf, int max_size) | ||
54 | { | ||
55 | extern char *addrptr; /* current position in address string */ | ||
56 | int n; /* number of characters to read from string */ | ||
57 | |||
58 | n = strlen(addrptr) < max_size ? strlen(addrptr) : max_size; | ||
59 | if (n > 0) { | ||
60 | memcpy(buf, addrptr, n); | ||
61 | addrptr += n; | ||
62 | } | ||
63 | return n; | ||
64 | } |
sieve/addr.y
0 → 100644
1 | %{ | ||
2 | /* | ||
3 | * addr.y -- RFC 822 address parser | ||
4 | */ | ||
5 | |||
6 | #include <stdlib.h> | ||
7 | #include <string.h> | ||
8 | |||
9 | #include "addr.h" | ||
10 | |||
11 | int yyerror(char *msg); | ||
12 | extern int yylex(void); | ||
13 | |||
14 | #define yyparse addrparse | ||
15 | #define yyerror addrerror | ||
16 | |||
17 | #define YYERROR_VERBOSE /* i want better error messages! */ | ||
18 | %} | ||
19 | |||
20 | %token ATOM QTEXT DTEXT | ||
21 | |||
22 | %start sieve_address | ||
23 | |||
24 | %% | ||
25 | address: mailbox /* one addressee */ | ||
26 | | group /* named list */ | ||
27 | ; | ||
28 | |||
29 | group: phrase ':' ';' | ||
30 | | phrase ':' mailboxes ';' | ||
31 | ; | ||
32 | |||
33 | mailboxes: mailbox | ||
34 | | mailbox ',' mailboxes | ||
35 | ; | ||
36 | |||
37 | mailbox: addrspec /* simple address */ | ||
38 | | phrase routeaddr /* name & addr-spec */ | ||
39 | ; | ||
40 | |||
41 | routeaddr: '<' addrspec '>' | ||
42 | | '<' route ':' addrspec '>' | ||
43 | ; | ||
44 | |||
45 | route: '@' domain /* path-relative */ | ||
46 | | '@' domain ',' route | ||
47 | ; | ||
48 | |||
49 | sieve_address: addrspec /* simple address */ | ||
50 | | phrase '<' addrspec '>' /* name & addr-spec */ | ||
51 | ; | ||
52 | |||
53 | addrspec: localpart '@' domain /* global-address */ | ||
54 | ; | ||
55 | |||
56 | localpart: word /* uninterpreted, case-preserved */ | ||
57 | | word '.' localpart | ||
58 | ; | ||
59 | |||
60 | domain: subdomain | ||
61 | | subdomain '.' domain | ||
62 | ; | ||
63 | |||
64 | subdomain: domainref | ||
65 | | domainlit | ||
66 | ; | ||
67 | |||
68 | domainref: ATOM /* symbolic reference */ | ||
69 | ; | ||
70 | |||
71 | domainlit: '[' DTEXT ']' | ||
72 | ; | ||
73 | |||
74 | phrase: word | ||
75 | | word phrase | ||
76 | ; | ||
77 | |||
78 | word: ATOM | ||
79 | | qstring | ||
80 | ; | ||
81 | |||
82 | qstring: '"' QTEXT '"' | ||
83 | ; | ||
84 | |||
85 | %% | ||
86 | |||
87 | /* copy address error message into buffer provided by sieve parser */ | ||
88 | int yyerror(char *s) | ||
89 | { | ||
90 | extern char addrerr[]; | ||
91 | |||
92 | strcpy(addrerr, s); | ||
93 | return 0; | ||
94 | } |
sieve/comparator.c
0 → 100644
1 | /* comparator.c -- comparator functions | ||
2 | * Larry Greenfield | ||
3 | * $Id$ | ||
4 | */ | ||
5 | /*********************************************************** | ||
6 | Copyright 1999 by Carnegie Mellon University | ||
7 | |||
8 | All Rights Reserved | ||
9 | |||
10 | Permission to use, copy, modify, and distribute this software and its | ||
11 | documentation for any purpose and without fee is hereby granted, | ||
12 | provided that the above copyright notice appear in all copies and that | ||
13 | both that copyright notice and this permission notice appear in | ||
14 | supporting documentation, and that the name of Carnegie Mellon | ||
15 | University not be used in advertising or publicity pertaining to | ||
16 | distribution of the software without specific, written prior | ||
17 | permission. | ||
18 | |||
19 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
20 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
21 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
22 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
23 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
24 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
25 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
26 | ******************************************************************/ | ||
27 | |||
28 | #ifdef HAVE_CONFIG_H | ||
29 | #include <config.h> | ||
30 | #endif | ||
31 | |||
32 | #include <stdlib.h> | ||
33 | #include <ctype.h> | ||
34 | #include <string.h> | ||
35 | #include <fnmatch.h> | ||
36 | #ifdef HAVE_STRINGS_H | ||
37 | # include <strings.h> | ||
38 | #endif | ||
39 | |||
40 | #include "comparator.h" | ||
41 | #include "tree.h" | ||
42 | #include "sieve-gram.h" | ||
43 | |||
44 | /* --- i;octet comparators --- */ | ||
45 | |||
46 | /* just compare the two; these should be NULL terminated */ | ||
47 | static int octet_is(const char *pat, const char *text) | ||
48 | { | ||
49 | int sl; | ||
50 | sl = strlen(pat); | ||
51 | |||
52 | return (sl == strlen(text)) && !memcmp(pat, text, sl); | ||
53 | } | ||
54 | |||
55 | /* we implement boyer-moore for hell of it, since this is probably | ||
56 | not very useful for sieve */ | ||
57 | #if 0 | ||
58 | int boyer_moore(char *pat, char *text) | ||
59 | { | ||
60 | int i, j; /* indexes */ | ||
61 | int M = strlen(pat); /* length of pattern */ | ||
62 | int N = strlen(text); /* length of text */ | ||
63 | int skip[256]; /* table of how much to skip, based on each character */ | ||
64 | |||
65 | /* initialize skip table */ | ||
66 | for (i = 0; i < 256; i++) | ||
67 | skip[i] = M; | ||
68 | for (i = 0; i < M; i++) | ||
69 | skip[(int) pat[i]] = M-i-1; | ||
70 | |||
71 | /* look for pat in text */ | ||
72 | i = j = M-1; | ||
73 | do { | ||
74 | if (pat[j] == text[i]) { | ||
75 | i--; | ||
76 | j--; | ||
77 | } else { | ||
78 | if (M-j > skip[(int) text[i]]) { | ||
79 | i = i + M - j; | ||
80 | } else { | ||
81 | i = i + skip[(int) text[i]]; | ||
82 | } | ||
83 | j = M-1; | ||
84 | } | ||
85 | } while (!((j < 0) || (i >= N))); | ||
86 | /* i+1 is the position of the match if i < N */ | ||
87 | return (i < N) ? 1 : 0; | ||
88 | } | ||
89 | #endif | ||
90 | |||
91 | /* we do a brute force attack */ | ||
92 | static int octet_contains(const char *pat, const char *text) | ||
93 | { | ||
94 | return (strstr(text, pat) != NULL); | ||
95 | } | ||
96 | |||
97 | static int octet_matches(const char *pat, const char *text) | ||
98 | { | ||
99 | return !fnmatch(pat, text, 0); | ||
100 | } | ||
101 | |||
102 | #ifdef ENABLE_REGEX | ||
103 | static int octet_regex(const char *pat, const char *text) | ||
104 | { | ||
105 | return (!regexec((regex_t *) pat, text, 0, NULL, 0)); | ||
106 | } | ||
107 | #endif | ||
108 | |||
109 | |||
110 | /* --- i;ascii-casemap comparators --- */ | ||
111 | |||
112 | static int ascii_casemap_is(const char *pat, const char *text) | ||
113 | { | ||
114 | int sl; | ||
115 | sl = strlen(pat); | ||
116 | |||
117 | return (sl == strlen(text)) && !strncasecmp(pat, text, sl); | ||
118 | } | ||
119 | |||
120 | /* sheer brute force */ | ||
121 | static int ascii_casemap_contains(const char *pat, const char *text) | ||
122 | { | ||
123 | int N = strlen(text); | ||
124 | int M = strlen(pat); | ||
125 | int i, j; | ||
126 | |||
127 | i = 0, j = 0; | ||
128 | while ((j < M) && (i < N)) { | ||
129 | if (toupper(text[i]) == toupper(pat[j])) { | ||
130 | i++; j++; | ||
131 | } else { | ||
132 | i = i - j + 1; | ||
133 | j = 0; | ||
134 | } | ||
135 | } | ||
136 | return (j == M); /* we found a match! */ | ||
137 | } | ||
138 | |||
139 | static int ascii_casemap_matches(const char *pat, const char *text) | ||
140 | { | ||
141 | int ret; | ||
142 | char *p, *t; | ||
143 | int i; | ||
144 | |||
145 | /* sigh, i'll just make local copies of these guys */ | ||
146 | p = strdup(pat); t = strdup(text); | ||
147 | for (i = 0; p[i] != '\0'; i++) | ||
148 | p[i] = toupper(p[i]); | ||
149 | for (i = 0; t[i] != '\0'; i++) | ||
150 | t[i] = toupper(t[i]); | ||
151 | |||
152 | ret = !fnmatch(p, t, 0); | ||
153 | free(p); free(t); | ||
154 | |||
155 | return ret; | ||
156 | } | ||
157 | |||
158 | /* i;ascii-numeric; only supports "is" | ||
159 | equality: numerically equal, or both not numbers */ | ||
160 | static int ascii_numeric_is(const char *pat, const char *text) | ||
161 | { | ||
162 | if (isdigit((int) *pat)) { | ||
163 | if (isdigit((int) *text)) { | ||
164 | return (atoi(pat) == atoi(text)); | ||
165 | } else { | ||
166 | return 0; | ||
167 | } | ||
168 | } else if (isdigit((int) *text)) return 0; | ||
169 | else return 1; /* both not digits */ | ||
170 | } | ||
171 | |||
172 | comparator_t *lookup_comp(const char *comp, int mode) | ||
173 | { | ||
174 | comparator_t *ret; | ||
175 | |||
176 | ret = NULL; | ||
177 | if (!strcmp(comp, "i;octet")) { | ||
178 | switch (mode) { | ||
179 | case IS: | ||
180 | ret = &octet_is; | ||
181 | break; | ||
182 | case CONTAINS: | ||
183 | ret = &octet_contains; | ||
184 | break; | ||
185 | case MATCHES: | ||
186 | ret = &octet_matches; | ||
187 | break; | ||
188 | #ifdef ENABLE_REGEX | ||
189 | case REGEX: | ||
190 | ret = &octet_regex; | ||
191 | break; | ||
192 | #endif | ||
193 | } | ||
194 | } else if (!strcmp(comp, "i;ascii-casemap")) { | ||
195 | switch (mode) { | ||
196 | case IS: | ||
197 | ret = &ascii_casemap_is; | ||
198 | break; | ||
199 | case CONTAINS: | ||
200 | ret = &ascii_casemap_contains; | ||
201 | break; | ||
202 | case MATCHES: | ||
203 | ret = &ascii_casemap_matches; | ||
204 | break; | ||
205 | #ifdef ENABLE_REGEX | ||
206 | case REGEX: | ||
207 | /* the ascii-casemap destinction is made during | ||
208 | the compilation of the regex in verify_regex() */ | ||
209 | ret = &octet_regex; | ||
210 | break; | ||
211 | #endif | ||
212 | } | ||
213 | } else if (!strcmp(comp, "i;ascii-numeric")) { | ||
214 | switch (mode) { | ||
215 | case IS: | ||
216 | ret = &ascii_numeric_is; | ||
217 | break; | ||
218 | } | ||
219 | } | ||
220 | return ret; | ||
221 | } |
sieve/comparator.h
0 → 100644
1 | /* comparator.h | ||
2 | * Larry Greenfield | ||
3 | */ | ||
4 | /*********************************************************** | ||
5 | Copyright 1999 by Carnegie Mellon University | ||
6 | |||
7 | All Rights Reserved | ||
8 | |||
9 | Permission to use, copy, modify, and distribute this software and its | ||
10 | documentation for any purpose and without fee is hereby granted, | ||
11 | provided that the above copyright notice appear in all copies and that | ||
12 | both that copyright notice and this permission notice appear in | ||
13 | supporting documentation, and that the name of Carnegie Mellon | ||
14 | University not be used in advertising or publicity pertaining to | ||
15 | distribution of the software without specific, written prior | ||
16 | permission. | ||
17 | |||
18 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
19 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
20 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
21 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
22 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
23 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
24 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
25 | ******************************************************************/ | ||
26 | |||
27 | #ifndef COMPARATOR_H | ||
28 | #define COMPARATOR_H | ||
29 | |||
30 | #ifdef ENABLE_REGEX | ||
31 | #ifdef HAVE_RX | ||
32 | #include <rxposix.h> | ||
33 | #else | ||
34 | #include <sys/types.h> | ||
35 | #include <regex.h> | ||
36 | #endif | ||
37 | #endif | ||
38 | |||
39 | /* compares pat to text; returns 1 if it's true, 0 otherwise | ||
40 | first arg is pat, second arg is text */ | ||
41 | typedef int comparator_t(const char *, const char *); | ||
42 | |||
43 | /* returns a pointer to a comparator function given it's name */ | ||
44 | comparator_t *lookup_comp(const char *comp, int mode); | ||
45 | |||
46 | #endif |
sieve/exitcodes.h
0 → 100644
1 | /* exitcodes.h -- wrapper around sysextis.h | ||
2 | * $Id$ | ||
3 | * | ||
4 | * Copyright (c) 1998-2000 Carnegie Mellon University. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in | ||
15 | * the documentation and/or other materials provided with the | ||
16 | * distribution. | ||
17 | * | ||
18 | * 3. The name "Carnegie Mellon University" must not be used to | ||
19 | * endorse or promote products derived from this software without | ||
20 | * prior written permission. For permission or any other legal | ||
21 | * details, please contact | ||
22 | * Office of Technology Transfer | ||
23 | * Carnegie Mellon University | ||
24 | * 5000 Forbes Avenue | ||
25 | * Pittsburgh, PA 15213-3890 | ||
26 | * (412) 268-4387, fax: (412) 268-7395 | ||
27 | * tech-transfer@andrew.cmu.edu | ||
28 | * | ||
29 | * 4. Redistributions of any form whatsoever must retain the following | ||
30 | * acknowledgment: | ||
31 | * "This product includes software developed by Computing Services | ||
32 | * at Carnegie Mellon University (http://www.cmu.edu/computing/)." | ||
33 | * | ||
34 | * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
35 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
36 | * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE | ||
37 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
38 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | ||
39 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | ||
40 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
41 | * | ||
42 | */ | ||
43 | |||
44 | /* Sendmail has some weird ideas on what constitutes permenant failure. On | ||
45 | more than one occasion, we have gotten burned by this moving users around | ||
46 | through various inadvisable means, screwing up the mailboxes file, | ||
47 | whatever. | ||
48 | |||
49 | We don't want to fail out permenantly on things like EX_USAGE, EX_SOFTWARE, | ||
50 | etc., because that generally means someone was just screwing with the mail | ||
51 | store and we don't want to lose mail. | ||
52 | |||
53 | Instead, we map these EC_* codes to EX_* codes, thereby lying to Sendmail, | ||
54 | since we don't derive any benefit from Sendmail knowing what the error was. | ||
55 | We just want it to retry all the time anyway. This way, should sendmail's | ||
56 | behavior be different and we start deriving benefit from Sendmail knowing | ||
57 | stuff, we can easily change it back. | ||
58 | |||
59 | So other code uses the EC_* error, then we maybe change it to TEMPFAIL if | ||
60 | we don't agree on whether the error should be permenant or not. | ||
61 | |||
62 | Comments below stolen from sysexits.h. */ | ||
63 | |||
64 | #ifndef INCLUDED_EXITCODES_H | ||
65 | #define INCLUDED_EXITCODES_H | ||
66 | |||
67 | #include <sysexits.h> | ||
68 | |||
69 | #define EC_OK 0 /* successful termination */ | ||
70 | |||
71 | #define EC_USAGE EX_TEMPFAIL /* command line usage error */ | ||
72 | #define EC_DATAERR EX_DATAERR /* data format error */ | ||
73 | #define EC_NOINPUT EX_TEMPFAIL /* cannot open input */ | ||
74 | #define EC_NOUSER EX_NOUSER /* addressee unknown */ | ||
75 | #define EC_NOHOST EX_TEMPFAIL /* host name unknown */ | ||
76 | #define EC_UNAVAILABLE EX_TEMPFAIL /* service unavailable */ | ||
77 | #define EC_SOFTWARE EX_TEMPFAIL /* internal software error */ | ||
78 | #define EC_OSERR EX_TEMPFAIL /* system error (e.g., can't fork) */ | ||
79 | #define EC_OSFILE EX_TEMPFAIL /* critical OS file missing */ | ||
80 | #define EC_CANTCREAT EX_TEMPFAIL /* can't create (user) output file */ | ||
81 | #define EC_IOERR EX_TEMPFAIL /* input/output error */ | ||
82 | #define EC_TEMPFAIL EX_TEMPFAIL /* user is invited to retry */ | ||
83 | #define EC_PROTOCOL EX_TEMPFAIL /* remote error in protocol */ | ||
84 | #define EC_NOPERM EX_TEMPFAIL /* permission denied */ | ||
85 | #define EC_CONFIG EX_TEMPFAIL /* configuration error */ | ||
86 | |||
87 | #endif /* INCLUDED_EXITCODES_H */ |
sieve/hmac-md5.h
0 → 100644
1 | /* hmac-md5.h -- HMAC_MD5 functions | ||
2 | */ | ||
3 | |||
4 | #ifndef HMAC_MD5_H | ||
5 | #define HMAC_MD5_H 1 | ||
6 | |||
7 | #define HMAC_MD5_SIZE 16 | ||
8 | |||
9 | /* intermediate MD5 context */ | ||
10 | typedef struct HMAC_MD5_CTX_s { | ||
11 | MD5_CTX ictx, octx; | ||
12 | } HMAC_MD5_CTX; | ||
13 | |||
14 | /* intermediate HMAC state | ||
15 | * values stored in network byte order (Big Endian) | ||
16 | */ | ||
17 | typedef struct HMAC_MD5_STATE_s { | ||
18 | UINT4 istate[4]; | ||
19 | UINT4 ostate[4]; | ||
20 | } HMAC_MD5_STATE; | ||
21 | |||
22 | /* One step hmac computation | ||
23 | * | ||
24 | * digest may be same as text or key | ||
25 | */ | ||
26 | void hmac_md5(const unsigned char *text, int text_len, | ||
27 | const unsigned char *key, int key_len, | ||
28 | unsigned char digest[HMAC_MD5_SIZE]); | ||
29 | |||
30 | /* create context from key | ||
31 | */ | ||
32 | void hmac_md5_init(HMAC_MD5_CTX *hmac, | ||
33 | const unsigned char *key, int key_len); | ||
34 | |||
35 | /* precalculate intermediate state from key | ||
36 | */ | ||
37 | void hmac_md5_precalc(HMAC_MD5_STATE *hmac, | ||
38 | const unsigned char *key, int key_len); | ||
39 | |||
40 | /* initialize context from intermediate state | ||
41 | */ | ||
42 | void hmac_md5_import(HMAC_MD5_CTX *hmac, HMAC_MD5_STATE *state); | ||
43 | |||
44 | #define hmac_md5_update(hmac, text, text_len) MD5Update(&(hmac)->ictx, (text), (text_len)) | ||
45 | |||
46 | /* finish hmac from intermediate result. Intermediate result is zeroed. | ||
47 | */ | ||
48 | void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE], | ||
49 | HMAC_MD5_CTX *hmac); | ||
50 | |||
51 | #endif /* HMAC_MD5_H */ |
sieve/imparse.c
0 → 100644
1 | /* imparse.c -- IMxP client-side parsing routines | ||
2 | $Id$ | ||
3 | |||
4 | * Copyright (c) 1998-2000 Carnegie Mellon University. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in | ||
15 | * the documentation and/or other materials provided with the | ||
16 | * distribution. | ||
17 | * | ||
18 | * 3. The name "Carnegie Mellon University" must not be used to | ||
19 | * endorse or promote products derived from this software without | ||
20 | * prior written permission. For permission or any other legal | ||
21 | * details, please contact | ||
22 | * Office of Technology Transfer | ||
23 | * Carnegie Mellon University | ||
24 | * 5000 Forbes Avenue | ||
25 | * Pittsburgh, PA 15213-3890 | ||
26 | * (412) 268-4387, fax: (412) 268-7395 | ||
27 | * tech-transfer@andrew.cmu.edu | ||
28 | * | ||
29 | * 4. Redistributions of any form whatsoever must retain the following | ||
30 | * acknowledgment: | ||
31 | * "This product includes software developed by Computing Services | ||
32 | * at Carnegie Mellon University (http://www.cmu.edu/computing/)." | ||
33 | * | ||
34 | * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
35 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
36 | * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE | ||
37 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
38 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | ||
39 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | ||
40 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
41 | * | ||
42 | * | ||
43 | */ | ||
44 | #include <config.h> | ||
45 | #include <stdio.h> | ||
46 | #include <ctype.h> | ||
47 | |||
48 | #include "imparse.h" | ||
49 | |||
50 | /* | ||
51 | * Parse a word from the string starting at the pointer pointed to by 's'. | ||
52 | * Places a pointer to the parsed word in the pointer at 'retval', | ||
53 | * returns the character following the word, and modifies the pointer at | ||
54 | * 's' to point after the returned character. Modifies the input buffer. | ||
55 | */ | ||
56 | int imparse_word(s, retval) | ||
57 | char **s; | ||
58 | char **retval; | ||
59 | { | ||
60 | int c; | ||
61 | |||
62 | *retval = *s; | ||
63 | for (;;) { | ||
64 | c = *(*s)++; | ||
65 | if (!c || isspace(c) || c == '(' || c == ')' || c == '\"') { | ||
66 | (*s)[-1] = '\0'; | ||
67 | return c; | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * Parse an astring from the string starting at the pointer pointed to | ||
74 | * by 's'. On success, places a pointer to the parsed word in the | ||
75 | * pointer at 'retval', returns the character following the word, and | ||
76 | * modifies the pointer at 's' to point after the returned character. | ||
77 | * On failure, returns EOF, modifies the pointer at 'retval' to point | ||
78 | * at the empty string, and modifies 's' to point around the syntax error. | ||
79 | * Modifies the input buffer. | ||
80 | */ | ||
81 | int imparse_astring(s, retval) | ||
82 | char **s; | ||
83 | char **retval; | ||
84 | { | ||
85 | int c; | ||
86 | char *d; | ||
87 | int len = 0; | ||
88 | int sawdigit = 0; | ||
89 | |||
90 | switch (**s) { | ||
91 | case '\0': | ||
92 | case ' ': | ||
93 | case '(': | ||
94 | case ')': | ||
95 | case '\r': | ||
96 | case '\n': | ||
97 | /* Invalid starting character */ | ||
98 | *retval = ""; | ||
99 | return EOF; | ||
100 | |||
101 | default: | ||
102 | /* | ||
103 | * Atom -- parser is liberal in accepting specials other | ||
104 | * than whitespace, parens, or double quotes | ||
105 | */ | ||
106 | return imparse_word(s, retval); | ||
107 | |||
108 | case '\"': | ||
109 | /* | ||
110 | * Quoted-string. Parser is liberal in accepting qspecials | ||
111 | * other than double-quote, CR, and LF. | ||
112 | */ | ||
113 | *retval = d = ++(*s); | ||
114 | for (;;) { | ||
115 | c = *(*s)++; | ||
116 | if (c == '\\') { | ||
117 | c = *(*s)++; | ||
118 | } | ||
119 | else if (c == '\"') { | ||
120 | *d = '\0'; | ||
121 | return *(*s)++; | ||
122 | } | ||
123 | else if (c == '\0' || c == '\r' || c == '\n') { | ||
124 | *retval = ""; | ||
125 | return EOF; | ||
126 | } | ||
127 | *d++ = c; | ||
128 | } | ||
129 | |||
130 | case '{': | ||
131 | /* Literal */ | ||
132 | (*s)++; | ||
133 | while (isdigit(c = *(*s)++)) { | ||
134 | sawdigit = 1; | ||
135 | len = len*10 + c - '0'; | ||
136 | } | ||
137 | if (!sawdigit || c != '}' || *(*s)++ != '\r' || *(*s)++ != '\n') { | ||
138 | *retval = ""; | ||
139 | return EOF; | ||
140 | } | ||
141 | *retval = *s; | ||
142 | *s += len; | ||
143 | c = **s; | ||
144 | *(*s)++ = '\0'; /* Note that 0 and '\0' mean the same thing */ | ||
145 | return c; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * Return nonzero if 's' matches the grammar for an atom | ||
151 | */ | ||
152 | int imparse_isatom(s) | ||
153 | const char *s; | ||
154 | { | ||
155 | int len = 0; | ||
156 | |||
157 | if (!*s) return 0; | ||
158 | for (; *s; s++) { | ||
159 | len++; | ||
160 | if (*s & 0x80 || *s < 0x1f || *s == 0x7f || | ||
161 | *s == ' ' || *s == '{' || *s == '(' || *s == ')' || | ||
162 | *s == '\"' || *s == '%' || *s == '*' || *s == '\\') return 0; | ||
163 | } | ||
164 | if (len >= 1024) return 0; | ||
165 | return 1; | ||
166 | } | ||
167 | |||
168 | /* | ||
169 | * Return nonzero if 's' matches the grammar for a sequence | ||
170 | */ | ||
171 | int imparse_issequence(const char* s) | ||
172 | { | ||
173 | int c; | ||
174 | int len = 0; | ||
175 | int sawcolon = 0; | ||
176 | |||
177 | while ((c = *s)) { | ||
178 | if (c == ',') { | ||
179 | if (!len) return 0; | ||
180 | if (!isdigit((int) s[-1]) && s[-1] != '*') return 0; | ||
181 | sawcolon = 0; | ||
182 | } | ||
183 | else if (c == ':') { | ||
184 | if (sawcolon || !len) return 0; | ||
185 | if (!isdigit((int) s[-1]) && s[-1] != '*') return 0; | ||
186 | sawcolon = 1; | ||
187 | } | ||
188 | else if (c == '*') { | ||
189 | if (len && s[-1] != ',' && s[-1] != ':') return 0; | ||
190 | if (isdigit((int) s[1])) return 0; | ||
191 | } | ||
192 | else if (!isdigit(c)) { | ||
193 | return 0; | ||
194 | } | ||
195 | s++; | ||
196 | len++; | ||
197 | } | ||
198 | if (len == 0) return 0; | ||
199 | if (!isdigit((int) s[-1]) && s[-1] != '*') return 0; | ||
200 | return 1; | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * Return nonzero if 's' matches the grammar for a number | ||
205 | */ | ||
206 | int imparse_isnumber(const char *s) | ||
207 | { | ||
208 | if (!*s) return 0; | ||
209 | for (; *s; s++) { | ||
210 | if (!isdigit((int) *s)) return 0; | ||
211 | } | ||
212 | return 1; | ||
213 | } |
sieve/imparse.h
0 → 100644
1 | /* imparse.h -- IMxP client-side parsing routines | ||
2 | * $Id$ | ||
3 | * Copyright (c) 1998-2000 Carnegie Mellon University. All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions | ||
7 | * are met: | ||
8 | * | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * | ||
12 | * 2. Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * | ||
17 | * 3. The name "Carnegie Mellon University" must not be used to | ||
18 | * endorse or promote products derived from this software without | ||
19 | * prior written permission. For permission or any other legal | ||
20 | * details, please contact | ||
21 | * Office of Technology Transfer | ||
22 | * Carnegie Mellon University | ||
23 | * 5000 Forbes Avenue | ||
24 | * Pittsburgh, PA 15213-3890 | ||
25 | * (412) 268-4387, fax: (412) 268-7395 | ||
26 | * tech-transfer@andrew.cmu.edu | ||
27 | * | ||
28 | * 4. Redistributions of any form whatsoever must retain the following | ||
29 | * acknowledgment: | ||
30 | * "This product includes software developed by Computing Services | ||
31 | * at Carnegie Mellon University (http://www.cmu.edu/computing/)." | ||
32 | * | ||
33 | * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
34 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
35 | * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE | ||
36 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
37 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | ||
38 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | ||
39 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
40 | * | ||
41 | */ | ||
42 | |||
43 | #ifndef INCLUDED_IMPARSE_H | ||
44 | #define INCLUDED_IMPARSE_H | ||
45 | |||
46 | extern int imparse_word (char **s, char **retval); | ||
47 | extern int imparse_astring (char **s, char **retval); | ||
48 | extern int imparse_isatom (const char *s); | ||
49 | extern int imparse_issequence (const char *s); | ||
50 | extern int imparse_isnumber (const char *s); | ||
51 | |||
52 | #endif /* INCLUDED_IMPARSE_H */ |
sieve/interp.c
0 → 100644
1 | /* interp.c -- sieve script interpretor builder | ||
2 | * Larry Greenfield | ||
3 | * $Id$ | ||
4 | */ | ||
5 | /*********************************************************** | ||
6 | Copyright 1999 by Carnegie Mellon University | ||
7 | |||
8 | All Rights Reserved | ||
9 | |||
10 | Permission to use, copy, modify, and distribute this software and its | ||
11 | documentation for any purpose and without fee is hereby granted, | ||
12 | provided that the above copyright notice appear in all copies and that | ||
13 | both that copyright notice and this permission notice appear in | ||
14 | supporting documentation, and that the name of Carnegie Mellon | ||
15 | University not be used in advertising or publicity pertaining to | ||
16 | distribution of the software without specific, written prior | ||
17 | permission. | ||
18 | |||
19 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
20 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
21 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
22 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
23 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
24 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
25 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
26 | ******************************************************************/ | ||
27 | |||
28 | #ifdef HAVE_CONFIG_H | ||
29 | #include <config.h> | ||
30 | #endif | ||
31 | |||
32 | #include <stdlib.h> | ||
33 | |||
34 | #include "xmalloc.h" | ||
35 | |||
36 | #include "sieve_interface.h" | ||
37 | #include "interp.h" | ||
38 | |||
39 | const char *sieve_version = "cmu-sieve 2.0"; | ||
40 | |||
41 | /* build a sieve interpretor */ | ||
42 | int sieve_interp_alloc(sieve_interp_t **interp, void *interp_context) | ||
43 | { | ||
44 | sieve_interp_t *i; | ||
45 | static int initonce; | ||
46 | |||
47 | if (!initonce) { | ||
48 | initialize_siev_error_table(); | ||
49 | initonce = 1; | ||
50 | } | ||
51 | |||
52 | *interp = NULL; | ||
53 | i = (sieve_interp_t *) xmalloc(sizeof(sieve_interp_t)); | ||
54 | if (i == NULL) { | ||
55 | return SIEVE_NOMEM; | ||
56 | } | ||
57 | |||
58 | i->redirect = i->discard = i->reject = i->fileinto = i->keep = NULL; | ||
59 | i->getsize = NULL; | ||
60 | i->getheader = NULL; | ||
61 | i->getenvelope = NULL; | ||
62 | i->vacation = NULL; | ||
63 | i->notify = NULL; | ||
64 | |||
65 | i->curflags.flag = NULL; i->curflags.nflags = 0; | ||
66 | i->markflags = NULL; | ||
67 | |||
68 | i->interp_context = interp_context; | ||
69 | i->err = NULL; | ||
70 | |||
71 | *interp = i; | ||
72 | return SIEVE_OK; | ||
73 | } | ||
74 | |||
75 | static const char *sieve_extensions = "fileinto reject envelope vacation" | ||
76 | " imapflags notify subaddress" | ||
77 | #ifdef ENABLE_REGEX | ||
78 | " regex"; | ||
79 | #else | ||
80 | ""; | ||
81 | #endif /* ENABLE_REGEX */ | ||
82 | |||
83 | const char *sieve_listextensions(void) | ||
84 | { | ||
85 | return sieve_extensions; | ||
86 | } | ||
87 | |||
88 | void free_imapflags(sieve_imapflags_t *imapflags) | ||
89 | { | ||
90 | while (imapflags->nflags) | ||
91 | free(imapflags->flag[--imapflags->nflags]); | ||
92 | free(imapflags->flag); | ||
93 | |||
94 | imapflags->flag = NULL; | ||
95 | } | ||
96 | |||
97 | int sieve_interp_free(sieve_interp_t **interp) | ||
98 | { | ||
99 | free_imapflags(&(*interp)->curflags); | ||
100 | free(*interp); | ||
101 | |||
102 | return SIEVE_OK; | ||
103 | } | ||
104 | |||
105 | /* add the callbacks */ | ||
106 | int sieve_register_redirect(sieve_interp_t *interp, sieve_callback *f) | ||
107 | { | ||
108 | interp->redirect = f; | ||
109 | |||
110 | return SIEVE_OK; | ||
111 | } | ||
112 | |||
113 | int sieve_register_discard(sieve_interp_t *interp, sieve_callback *f) | ||
114 | { | ||
115 | interp->discard = f; | ||
116 | |||
117 | return SIEVE_OK; | ||
118 | } | ||
119 | |||
120 | int sieve_register_reject(sieve_interp_t *interp, sieve_callback *f) | ||
121 | { | ||
122 | interp->reject = f; | ||
123 | |||
124 | return SIEVE_OK; | ||
125 | } | ||
126 | |||
127 | int sieve_register_fileinto(sieve_interp_t *interp, sieve_callback *f) | ||
128 | { | ||
129 | interp->fileinto = f; | ||
130 | |||
131 | return SIEVE_OK; | ||
132 | } | ||
133 | |||
134 | int sieve_register_keep(sieve_interp_t *interp, sieve_callback *f) | ||
135 | { | ||
136 | interp->keep = f; | ||
137 | |||
138 | return SIEVE_OK; | ||
139 | } | ||
140 | |||
141 | static char *default_markflags[] = { "\\flagged" }; | ||
142 | static sieve_imapflags_t default_mark = { default_markflags, 1 }; | ||
143 | |||
144 | int sieve_register_imapflags(sieve_interp_t *interp, sieve_imapflags_t *mark) | ||
145 | { | ||
146 | interp->markflags = | ||
147 | (mark && mark->flag && mark->nflags) ? mark : &default_mark; | ||
148 | |||
149 | return SIEVE_OK; | ||
150 | } | ||
151 | |||
152 | int sieve_register_notify(sieve_interp_t *interp, sieve_callback *f) | ||
153 | { | ||
154 | interp->notify = f; | ||
155 | |||
156 | return SIEVE_OK; | ||
157 | } | ||
158 | |||
159 | /* add the callbacks for messages. again, undefined if used after | ||
160 | sieve_script_parse */ | ||
161 | int sieve_register_size(sieve_interp_t *interp, sieve_get_size *f) | ||
162 | { | ||
163 | interp->getsize = f; | ||
164 | return SIEVE_OK; | ||
165 | } | ||
166 | |||
167 | int sieve_register_header(sieve_interp_t *interp, sieve_get_header *f) | ||
168 | { | ||
169 | interp->getheader = f; | ||
170 | return SIEVE_OK; | ||
171 | } | ||
172 | |||
173 | int sieve_register_envelope(sieve_interp_t *interp, sieve_get_envelope *f) | ||
174 | { | ||
175 | interp->getenvelope = f; | ||
176 | return SIEVE_OK; | ||
177 | } | ||
178 | |||
179 | int sieve_register_vacation(sieve_interp_t *interp, sieve_vacation_t *v) | ||
180 | { | ||
181 | if (!interp->getenvelope) { | ||
182 | return SIEVE_NOT_FINALIZED; /* we need envelope for vacation! */ | ||
183 | } | ||
184 | |||
185 | if (v->min_response == 0) v->min_response = 3; | ||
186 | if (v->max_response == 0) v->max_response = 90; | ||
187 | if (v->min_response < 0 || v->max_response < 7 || !v->autorespond | ||
188 | || !v->send_response) { | ||
189 | return SIEVE_FAIL; | ||
190 | } | ||
191 | |||
192 | interp->vacation = v; | ||
193 | return SIEVE_OK; | ||
194 | } | ||
195 | |||
196 | int sieve_register_parse_error(sieve_interp_t *interp, sieve_parse_error *f) | ||
197 | { | ||
198 | interp->err = f; | ||
199 | return SIEVE_OK; | ||
200 | } | ||
201 | |||
202 | int sieve_register_execute_error(sieve_interp_t *interp, sieve_execute_error *f) | ||
203 | { | ||
204 | interp->execute_err = f; | ||
205 | return SIEVE_OK; | ||
206 | } | ||
207 | |||
208 | int sieve_register_summary(sieve_interp_t *interp, sieve_execute_error *f) | ||
209 | { | ||
210 | interp->summary = f; | ||
211 | return SIEVE_OK; | ||
212 | } | ||
213 | |||
214 | int interp_verify(sieve_interp_t *i) | ||
215 | { | ||
216 | if (i->redirect && i->keep && i->getsize && i->getheader) { | ||
217 | return SIEVE_OK; | ||
218 | } else { | ||
219 | return SIEVE_NOT_FINALIZED; | ||
220 | } | ||
221 | } |
sieve/interp.h
0 → 100644
1 | /* interp.h -- interpretor definition | ||
2 | * Larry Greenfield | ||
3 | * $Id$ | ||
4 | */ | ||
5 | /*********************************************************** | ||
6 | Copyright 1999 by Carnegie Mellon University | ||
7 | |||
8 | All Rights Reserved | ||
9 | |||
10 | Permission to use, copy, modify, and distribute this software and its | ||
11 | documentation for any purpose and without fee is hereby granted, | ||
12 | provided that the above copyright notice appear in all copies and that | ||
13 | both that copyright notice and this permission notice appear in | ||
14 | supporting documentation, and that the name of Carnegie Mellon | ||
15 | University not be used in advertising or publicity pertaining to | ||
16 | distribution of the software without specific, written prior | ||
17 | permission. | ||
18 | |||
19 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
20 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
21 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
22 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
23 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
24 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
25 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
26 | *****************************************************************/ | ||
27 | |||
28 | #ifndef SIEVE_INTERP_H | ||
29 | #define SIEVE_INTERP_H | ||
30 | |||
31 | #include "sieve_interface.h" | ||
32 | |||
33 | struct sieve_interp { | ||
34 | /* standard callbacks for actions */ | ||
35 | sieve_callback *redirect, *discard, *reject, *fileinto, *keep; | ||
36 | sieve_callback *notify; | ||
37 | sieve_vacation_t *vacation; | ||
38 | |||
39 | sieve_get_size *getsize; | ||
40 | sieve_get_header *getheader; | ||
41 | sieve_get_envelope *getenvelope; | ||
42 | |||
43 | sieve_parse_error *err; | ||
44 | |||
45 | /* current imapflags state */ | ||
46 | sieve_imapflags_t curflags; | ||
47 | |||
48 | /* site-specific imapflags for mark/unmark */ | ||
49 | sieve_imapflags_t *markflags; | ||
50 | |||
51 | sieve_execute_error *execute_err; | ||
52 | sieve_execute_error *summary; | ||
53 | |||
54 | /* context to pass along */ | ||
55 | void *interp_context; | ||
56 | }; | ||
57 | |||
58 | int interp_verify(sieve_interp_t *interp); | ||
59 | void free_imapflags(sieve_imapflags_t *imapflags); | ||
60 | |||
61 | #endif |
sieve/md5.c
0 → 100644
1 | /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm | ||
2 | */ | ||
3 | |||
4 | /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All | ||
5 | rights reserved. | ||
6 | |||
7 | License to copy and use this software is granted provided that it | ||
8 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest | ||
9 | Algorithm" in all material mentioning or referencing this software | ||
10 | or this function. | ||
11 | |||
12 | License is also granted to make and use derivative works provided | ||
13 | that such works are identified as "derived from the RSA Data | ||
14 | Security, Inc. MD5 Message-Digest Algorithm" in all material | ||
15 | mentioning or referencing the derived work. | ||
16 | |||
17 | RSA Data Security, Inc. makes no representations concerning either | ||
18 | the merchantability of this software or the suitability of this | ||
19 | software for any particular purpose. It is provided "as is" | ||
20 | without express or implied warranty of any kind. | ||
21 | |||
22 | These notices must be retained in any copies of any part of this | ||
23 | documentation and/or software. | ||
24 | */ | ||
25 | |||
26 | /* do i need all of this just for htonl()? damn. */ | ||
27 | #include <sys/types.h> | ||
28 | #include <sys/param.h> | ||
29 | #include <sys/socket.h> | ||
30 | #include <netinet/in.h> | ||
31 | |||
32 | #include "md5global.h" | ||
33 | #include "md5.h" | ||
34 | #include "hmac-md5.h" | ||
35 | |||
36 | /* Constants for MD5Transform routine. | ||
37 | */ | ||
38 | |||
39 | #define S11 7 | ||
40 | #define S12 12 | ||
41 | #define S13 17 | ||
42 | #define S14 22 | ||
43 | #define S21 5 | ||
44 | #define S22 9 | ||
45 | #define S23 14 | ||
46 | #define S24 20 | ||
47 | #define S31 4 | ||
48 | #define S32 11 | ||
49 | #define S33 16 | ||
50 | #define S34 23 | ||
51 | #define S41 6 | ||
52 | #define S42 10 | ||
53 | #define S43 15 | ||
54 | #define S44 21 | ||
55 | |||
56 | static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); | ||
57 | static void Encode PROTO_LIST | ||
58 | ((unsigned char *, UINT4 *, unsigned int)); | ||
59 | static void Decode PROTO_LIST | ||
60 | ((UINT4 *, unsigned char *, unsigned int)); | ||
61 | static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); | ||
62 | static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); | ||
63 | |||
64 | static unsigned char PADDING[64] = { | ||
65 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
66 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
67 | }; | ||
68 | |||
69 | /* F, G, H and I are basic MD5 functions. | ||
70 | |||
71 | */ | ||
72 | #ifdef I | ||
73 | /* This might be defined via NANA */ | ||
74 | #undef I | ||
75 | #endif | ||
76 | |||
77 | #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) | ||
78 | #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) | ||
79 | #define H(x, y, z) ((x) ^ (y) ^ (z)) | ||
80 | #define I(x, y, z) ((y) ^ ((x) | (~z))) | ||
81 | |||
82 | /* ROTATE_LEFT rotates x left n bits. | ||
83 | |||
84 | */ | ||
85 | |||
86 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) | ||
87 | |||
88 | /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. | ||
89 | Rotation is separate from addition to prevent recomputation. | ||
90 | */ | ||
91 | |||
92 | #define FF(a, b, c, d, x, s, ac) { (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } | ||
93 | #define GG(a, b, c, d, x, s, ac) { (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } | ||
94 | #define HH(a, b, c, d, x, s, ac) { (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } | ||
95 | #define II(a, b, c, d, x, s, ac) { (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } | ||
96 | |||
97 | /* MD5 initialization. Begins an MD5 operation, writing a new context. | ||
98 | */ | ||
99 | |||
100 | void MD5Init (context) | ||
101 | MD5_CTX *context; /* context */ | ||
102 | { | ||
103 | context->count[0] = context->count[1] = 0; | ||
104 | |||
105 | /* Load magic initialization constants. | ||
106 | |||
107 | */ | ||
108 | context->state[0] = 0x67452301; | ||
109 | context->state[1] = 0xefcdab89; | ||
110 | context->state[2] = 0x98badcfe; | ||
111 | context->state[3] = 0x10325476; | ||
112 | } | ||
113 | |||
114 | /* MD5 block update operation. Continues an MD5 message-digest | ||
115 | operation, processing another message block, and updating the context. | ||
116 | */ | ||
117 | |||
118 | void MD5Update (context, input, inputLen) | ||
119 | MD5_CTX *context; /* context */ | ||
120 | unsigned char *input; /* input block */ | ||
121 | unsigned int inputLen; /* length of input block */ | ||
122 | { | ||
123 | unsigned int i, index, partLen; | ||
124 | |||
125 | /* Compute number of bytes mod 64 */ | ||
126 | index = (unsigned int)((context->count[0] >> 3) & 0x3F); | ||
127 | |||
128 | /* Update number of bits */ | ||
129 | if ((context->count[0] += ((UINT4)inputLen << 3)) | ||
130 | < ((UINT4)inputLen << 3)) | ||
131 | context->count[1]++; | ||
132 | context->count[1] += ((UINT4)inputLen >> 29); | ||
133 | |||
134 | partLen = 64 - index; | ||
135 | |||
136 | /* Transform as many times as possible. | ||
137 | |||
138 | */ | ||
139 | if (inputLen >= partLen) { | ||
140 | MD5_memcpy | ||
141 | ((POINTER)&context->buffer[index], (POINTER)input, partLen); MD5Transform | ||
142 | (context->state, context->buffer); | ||
143 | |||
144 | for (i = partLen; i + 63 < inputLen; i += 64) | ||
145 | MD5Transform (context->state, &input[i]); | ||
146 | |||
147 | index = 0; | ||
148 | } | ||
149 | else | ||
150 | i = 0; | ||
151 | |||
152 | /* Buffer remaining input */ | ||
153 | MD5_memcpy | ||
154 | ((POINTER)&context->buffer[index], (POINTER)&input[i], | ||
155 | inputLen-i); | ||
156 | |||
157 | } | ||
158 | |||
159 | /* MD5 finalization. Ends an MD5 message-digest operation, writing the | ||
160 | the message digest and zeroizing the context. | ||
161 | |||
162 | */ | ||
163 | |||
164 | void MD5Final (digest, context) | ||
165 | unsigned char digest[16]; /* message digest */ | ||
166 | MD5_CTX *context; /* context */ | ||
167 | { | ||
168 | unsigned char bits[8]; | ||
169 | unsigned int index, padLen; | ||
170 | |||
171 | /* Save number of bits */ | ||
172 | Encode (bits, context->count, 8); | ||
173 | |||
174 | /* Pad out to 56 mod 64. | ||
175 | |||
176 | */ | ||
177 | index = (unsigned int)((context->count[0] >> 3) & 0x3f); | ||
178 | padLen = (index < 56) ? (56 - index) : (120 - index); | ||
179 | MD5Update (context, PADDING, padLen); | ||
180 | |||
181 | /* Append length (before padding) */ | ||
182 | MD5Update (context, bits, 8); | ||
183 | |||
184 | /* Store state in digest */ | ||
185 | Encode (digest, context->state, 16); | ||
186 | |||
187 | /* Zeroize sensitive information. | ||
188 | |||
189 | */ | ||
190 | MD5_memset ((POINTER)context, 0, sizeof (*context)); | ||
191 | } | ||
192 | |||
193 | /* MD5 basic transformation. Transforms state based on block. | ||
194 | |||
195 | */ | ||
196 | |||
197 | static void MD5Transform (state, block) | ||
198 | UINT4 state[4]; | ||
199 | unsigned char block[64]; | ||
200 | { | ||
201 | UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; | ||
202 | |||
203 | Decode (x, block, 64); | ||
204 | |||
205 | /* Round 1 */ | ||
206 | FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ | ||
207 | FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ | ||
208 | FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ | ||
209 | FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ | ||
210 | FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ | ||
211 | FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ | ||
212 | FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ | ||
213 | FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ | ||
214 | FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ | ||
215 | FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ | ||
216 | FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ | ||
217 | FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ | ||
218 | FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ | ||
219 | FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ | ||
220 | FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ | ||
221 | FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ | ||
222 | |||
223 | /* Round 2 */ | ||
224 | GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ | ||
225 | GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ | ||
226 | GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ | ||
227 | GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ | ||
228 | GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ | ||
229 | GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ | ||
230 | GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ | ||
231 | GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ | ||
232 | GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ | ||
233 | GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ | ||
234 | GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ | ||
235 | GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ | ||
236 | GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ | ||
237 | GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ | ||
238 | GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ | ||
239 | GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ | ||
240 | |||
241 | /* Round 3 */ | ||
242 | HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ | ||
243 | HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ | ||
244 | HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ | ||
245 | HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ | ||
246 | HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ | ||
247 | HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ | ||
248 | HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ | ||
249 | HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ | ||
250 | HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ | ||
251 | HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ | ||
252 | HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ | ||
253 | HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ | ||
254 | HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ | ||
255 | HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ | ||
256 | HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ | ||
257 | HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ | ||
258 | |||
259 | /* Round 4 */ | ||
260 | II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ | ||
261 | II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ | ||
262 | II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ | ||
263 | II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ | ||
264 | II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ | ||
265 | II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ | ||
266 | II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ | ||
267 | II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ | ||
268 | II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ | ||
269 | II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ | ||
270 | II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ | ||
271 | II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ | ||
272 | II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ | ||
273 | II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ | ||
274 | II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ | ||
275 | II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ | ||
276 | |||
277 | state[0] += a; | ||
278 | state[1] += b; | ||
279 | state[2] += c; | ||
280 | state[3] += d; | ||
281 | |||
282 | /* Zeroize sensitive information. | ||
283 | */ | ||
284 | MD5_memset ((POINTER)x, 0, sizeof (x)); | ||
285 | } | ||
286 | |||
287 | /* Encodes input (UINT4) into output (unsigned char). Assumes len is | ||
288 | a multiple of 4. | ||
289 | |||
290 | */ | ||
291 | |||
292 | static void Encode (output, input, len) | ||
293 | unsigned char *output; | ||
294 | UINT4 *input; | ||
295 | unsigned int len; | ||
296 | { | ||
297 | unsigned int i, j; | ||
298 | |||
299 | for (i = 0, j = 0; j < len; i++, j += 4) { | ||
300 | output[j] = (unsigned char)(input[i] & 0xff); | ||
301 | output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); | ||
302 | output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); | ||
303 | output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | /* Decodes input (unsigned char) into output (UINT4). Assumes len is | ||
308 | a multiple of 4. | ||
309 | |||
310 | */ | ||
311 | |||
312 | static void Decode (output, input, len) | ||
313 | UINT4 *output; | ||
314 | unsigned char *input; | ||
315 | unsigned int len; | ||
316 | { | ||
317 | unsigned int i, j; | ||
318 | |||
319 | for (i = 0, j = 0; j < len; i++, j += 4) | ||
320 | output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | ||
321 | | (((UINT4)input[j+3]) << 24); | ||
322 | } | ||
323 | |||
324 | /* Note: Replace "for loop" with standard memcpy if possible. | ||
325 | |||
326 | */ | ||
327 | |||
328 | static void MD5_memcpy (output, input, len) | ||
329 | POINTER output; | ||
330 | POINTER input; | ||
331 | unsigned int len; | ||
332 | { | ||
333 | unsigned int i; | ||
334 | |||
335 | for (i = 0; i < len; i++) | ||
336 | output[i] = input[i]; | ||
337 | } | ||
338 | |||
339 | /* Note: Replace "for loop" with standard memset if possible. | ||
340 | */ | ||
341 | |||
342 | static void MD5_memset (output, value, len) | ||
343 | POINTER output; | ||
344 | int value; | ||
345 | unsigned int len; | ||
346 | { | ||
347 | unsigned int i; | ||
348 | |||
349 | for (i = 0; i < len; i++) | ||
350 | ((char *)output)[i] = (char)value; | ||
351 | } | ||
352 | |||
353 | void hmac_md5_init(HMAC_MD5_CTX *hmac, | ||
354 | const unsigned char *key, | ||
355 | int key_len) | ||
356 | { | ||
357 | unsigned char k_ipad[65]; /* inner padding - | ||
358 | * key XORd with ipad | ||
359 | */ | ||
360 | unsigned char k_opad[65]; /* outer padding - | ||
361 | * key XORd with opad | ||
362 | */ | ||
363 | unsigned char tk[16]; | ||
364 | int i; | ||
365 | /* if key is longer than 64 bytes reset it to key=MD5(key) */ | ||
366 | if (key_len > 64) { | ||
367 | |||
368 | MD5_CTX tctx; | ||
369 | |||
370 | MD5Init(&tctx); | ||
371 | MD5Update(&tctx, key, key_len); | ||
372 | MD5Final(tk, &tctx); | ||
373 | |||
374 | key = tk; | ||
375 | key_len = 16; | ||
376 | } | ||
377 | |||
378 | /* | ||
379 | * the HMAC_MD5 transform looks like: | ||
380 | * | ||
381 | * MD5(K XOR opad, MD5(K XOR ipad, text)) | ||
382 | * | ||
383 | * where K is an n byte key | ||
384 | * ipad is the byte 0x36 repeated 64 times | ||
385 | * opad is the byte 0x5c repeated 64 times | ||
386 | * and text is the data being protected | ||
387 | */ | ||
388 | |||
389 | /* start out by storing key in pads */ | ||
390 | MD5_memset(k_ipad, '\0', sizeof k_ipad); | ||
391 | MD5_memset(k_opad, '\0', sizeof k_opad); | ||
392 | MD5_memcpy( k_ipad, key, key_len); | ||
393 | MD5_memcpy( k_opad, key, key_len); | ||
394 | |||
395 | /* XOR key with ipad and opad values */ | ||
396 | for (i=0; i<64; i++) { | ||
397 | k_ipad[i] ^= 0x36; | ||
398 | k_opad[i] ^= 0x5c; | ||
399 | } | ||
400 | |||
401 | MD5Init(&hmac->ictx); /* init inner context */ | ||
402 | MD5Update(&hmac->ictx, k_ipad, 64); /* apply inner pad */ | ||
403 | |||
404 | MD5Init(&hmac->octx); /* init outer context */ | ||
405 | MD5Update(&hmac->octx, k_opad, 64); /* apply outer pad */ | ||
406 | |||
407 | /* scrub the pads and key context (if used) */ | ||
408 | MD5_memset(&k_ipad, 0, sizeof(k_ipad)); | ||
409 | MD5_memset(&k_opad, 0, sizeof(k_opad)); | ||
410 | MD5_memset(&tk, 0, sizeof(tk)); | ||
411 | |||
412 | /* and we're done. */ | ||
413 | } | ||
414 | |||
415 | /* The precalc and import routines here rely on the fact that we pad | ||
416 | * the key out to 64 bytes and use that to initialize the md5 | ||
417 | * contexts, and that updating an md5 context with 64 bytes of data | ||
418 | * leaves nothing left over; all of the interesting state is contained | ||
419 | * in the state field, and none of it is left over in the count and | ||
420 | * buffer fields. So all we have to do is save the state field; we | ||
421 | * can zero the others when we reload it. Which is why the decision | ||
422 | * was made to pad the key out to 64 bytes in the first place. */ | ||
423 | void hmac_md5_precalc(HMAC_MD5_STATE *state, | ||
424 | const unsigned char *key, | ||
425 | int key_len) | ||
426 | { | ||
427 | HMAC_MD5_CTX hmac; | ||
428 | unsigned lupe; | ||
429 | |||
430 | hmac_md5_init(&hmac, key, key_len); | ||
431 | for (lupe = 0; lupe < 4; lupe++) { | ||
432 | state->istate[lupe] = htonl(hmac.ictx.state[lupe]); | ||
433 | state->ostate[lupe] = htonl(hmac.octx.state[lupe]); | ||
434 | } | ||
435 | MD5_memset(&hmac, 0, sizeof(hmac)); | ||
436 | } | ||
437 | |||
438 | |||
439 | void hmac_md5_import(HMAC_MD5_CTX *hmac, | ||
440 | HMAC_MD5_STATE *state) | ||
441 | { | ||
442 | unsigned lupe; | ||
443 | MD5_memset(hmac, 0, sizeof(HMAC_MD5_CTX)); | ||
444 | for (lupe = 0; lupe < 4; lupe++) { | ||
445 | hmac->ictx.state[lupe] = ntohl(state->istate[lupe]); | ||
446 | hmac->octx.state[lupe] = ntohl(state->ostate[lupe]); | ||
447 | } | ||
448 | /* Init the counts to account for our having applied | ||
449 | * 64 bytes of key; this works out to 0x200 (64 << 3; see | ||
450 | * MD5Update above...) */ | ||
451 | hmac->ictx.count[0] = hmac->octx.count[0] = 0x200; | ||
452 | } | ||
453 | |||
454 | void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE], | ||
455 | HMAC_MD5_CTX *hmac) | ||
456 | { | ||
457 | MD5Final(digest, &hmac->ictx); /* Finalize inner md5 */ | ||
458 | MD5Update(&hmac->octx, digest, 16); /* Update outer ctx */ | ||
459 | MD5Final(digest, &hmac->octx); /* Finalize outer md5 */ | ||
460 | } | ||
461 | |||
462 | |||
463 | void hmac_md5(text, text_len, key, key_len, digest) | ||
464 | const unsigned char* text; /* pointer to data stream */ | ||
465 | int text_len; /* length of data stream */ | ||
466 | const unsigned char* key; /* pointer to authentication key */ | ||
467 | int key_len; /* length of authentication key */ | ||
468 | unsigned char *digest; /* caller digest to be filled in */ | ||
469 | { | ||
470 | MD5_CTX context; | ||
471 | |||
472 | unsigned char k_ipad[65]; /* inner padding - | ||
473 | * key XORd with ipad | ||
474 | */ | ||
475 | unsigned char k_opad[65]; /* outer padding - | ||
476 | * key XORd with opad | ||
477 | */ | ||
478 | unsigned char tk[16]; | ||
479 | int i; | ||
480 | /* if key is longer than 64 bytes reset it to key=MD5(key) */ | ||
481 | if (key_len > 64) { | ||
482 | |||
483 | MD5_CTX tctx; | ||
484 | |||
485 | MD5Init(&tctx); | ||
486 | MD5Update(&tctx, key, key_len); | ||
487 | MD5Final(tk, &tctx); | ||
488 | |||
489 | key = tk; | ||
490 | key_len = 16; | ||
491 | } | ||
492 | |||
493 | /* | ||
494 | * the HMAC_MD5 transform looks like: | ||
495 | * | ||
496 | * MD5(K XOR opad, MD5(K XOR ipad, text)) | ||
497 | * | ||
498 | * where K is an n byte key | ||
499 | * ipad is the byte 0x36 repeated 64 times | ||
500 | * opad is the byte 0x5c repeated 64 times | ||
501 | * and text is the data being protected | ||
502 | */ | ||
503 | |||
504 | /* start out by storing key in pads */ | ||
505 | MD5_memset(k_ipad, '\0', sizeof k_ipad); | ||
506 | MD5_memset(k_opad, '\0', sizeof k_opad); | ||
507 | MD5_memcpy( k_ipad, key, key_len); | ||
508 | MD5_memcpy( k_opad, key, key_len); | ||
509 | |||
510 | /* XOR key with ipad and opad values */ | ||
511 | for (i=0; i<64; i++) { | ||
512 | k_ipad[i] ^= 0x36; | ||
513 | k_opad[i] ^= 0x5c; | ||
514 | } | ||
515 | /* | ||
516 | * perform inner MD5 | ||
517 | */ | ||
518 | |||
519 | MD5Init(&context); /* init context for 1st | ||
520 | * pass */ | ||
521 | MD5Update(&context, k_ipad, 64); /* start with inner pad */ | ||
522 | MD5Update(&context, text, text_len); /* then text of datagram */ | ||
523 | MD5Final(digest, &context); /* finish up 1st pass */ | ||
524 | |||
525 | /* | ||
526 | * perform outer MD5 | ||
527 | */ | ||
528 | MD5Init(&context); /* init context for 2nd | ||
529 | * pass */ | ||
530 | MD5Update(&context, k_opad, 64); /* start with outer pad */ | ||
531 | MD5Update(&context, digest, 16); /* then results of 1st | ||
532 | * hash */ | ||
533 | MD5Final(digest, &context); /* finish up 2nd pass */ | ||
534 | |||
535 | } |
sieve/md5.h
0 → 100644
1 | /* MD5.H - header file for MD5C.C | ||
2 | */ | ||
3 | |||
4 | /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All | ||
5 | rights reserved. | ||
6 | |||
7 | License to copy and use this software is granted provided that it | ||
8 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest | ||
9 | Algorithm" in all material mentioning or referencing this software | ||
10 | or this function. | ||
11 | |||
12 | License is also granted to make and use derivative works provided | ||
13 | that such works are identified as "derived from the RSA Data | ||
14 | Security, Inc. MD5 Message-Digest Algorithm" in all material | ||
15 | mentioning or referencing the derived work. | ||
16 | |||
17 | RSA Data Security, Inc. makes no representations concerning either | ||
18 | the merchantability of this software or the suitability of this | ||
19 | software for any particular purpose. It is provided "as is" | ||
20 | without express or implied warranty of any kind. | ||
21 | These notices must be retained in any copies of any part of this | ||
22 | documentation and/or software. | ||
23 | */ | ||
24 | |||
25 | /* MD5 context. */ | ||
26 | typedef struct { | ||
27 | UINT4 state[4]; /* state (ABCD) */ | ||
28 | UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ | ||
29 | unsigned char buffer[64]; /* input buffer */ | ||
30 | } MD5_CTX; | ||
31 | |||
32 | void MD5Init PROTO_LIST ((MD5_CTX *)); | ||
33 | void MD5Update PROTO_LIST | ||
34 | ((MD5_CTX *, unsigned char *, unsigned int)); | ||
35 | void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); | ||
36 | |||
37 | void hmac_md5 PROTO_LIST ((unsigned char *, int, unsigned char *, int, unsigned char*)); |
sieve/md5global.h
0 → 100644
1 | /* GLOBAL.H - RSAREF types and constants | ||
2 | */ | ||
3 | |||
4 | /* PROTOTYPES should be set to one if and only if the compiler supports | ||
5 | function argument prototyping. | ||
6 | The following makes PROTOTYPES default to 0 if it has not already | ||
7 | been defined with C compiler flags. | ||
8 | */ | ||
9 | #ifndef PROTOTYPES | ||
10 | #define PROTOTYPES 0 | ||
11 | #endif | ||
12 | |||
13 | /* POINTER defines a generic pointer type */ | ||
14 | typedef unsigned char *POINTER; | ||
15 | |||
16 | /* UINT2 defines a two byte word */ | ||
17 | typedef unsigned short int UINT2; | ||
18 | |||
19 | /* UINT4 defines a four byte word */ | ||
20 | typedef unsigned long int UINT4; | ||
21 | |||
22 | /* PROTO_LIST is defined depending on how PROTOTYPES is defined above. | ||
23 | If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it | ||
24 | returns an empty list. | ||
25 | */ | ||
26 | #if PROTOTYPES | ||
27 | #define PROTO_LIST(list) list | ||
28 | #else | ||
29 | #define PROTO_LIST(list) () | ||
30 | #endif | ||
31 |
sieve/message.c
0 → 100644
1 | /* message.c -- message parsing functions | ||
2 | * Larry Greenfield | ||
3 | * $Id$ | ||
4 | */ | ||
5 | /*********************************************************** | ||
6 | Copyright 1999 by Carnegie Mellon University | ||
7 | |||
8 | All Rights Reserved | ||
9 | |||
10 | Permission to use, copy, modify, and distribute this software and its | ||
11 | documentation for any purpose and without fee is hereby granted, | ||
12 | provided that the above copyright notice appear in all copies and that | ||
13 | both that copyright notice and this permission notice appear in | ||
14 | supporting documentation, and that the name of Carnegie Mellon | ||
15 | University not be used in advertising or publicity pertaining to | ||
16 | distribution of the software without specific, written prior | ||
17 | permission. | ||
18 | |||
19 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
20 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
21 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
22 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
23 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
24 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
25 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
26 | ******************************************************************/ | ||
27 | |||
28 | #ifdef HAVE_CONFIG_H | ||
29 | #include <config.h> | ||
30 | #endif | ||
31 | |||
32 | #include <stdlib.h> | ||
33 | #include <unistd.h> | ||
34 | #include <sys/mman.h> | ||
35 | #include <sys/stat.h> | ||
36 | #include <sys/types.h> | ||
37 | #include <sys/stat.h> | ||
38 | #include <fcntl.h> | ||
39 | #include <string.h> | ||
40 | #ifdef HAVE_STRINGS_H | ||
41 | # include <strings.h> | ||
42 | #endif | ||
43 | |||
44 | #include "sieve_interface.h" | ||
45 | #include "interp.h" | ||
46 | #include "message.h" | ||
47 | #include "parseaddr.h" | ||
48 | #include "xmalloc.h" | ||
49 | #include "util.h" | ||
50 | |||
51 | /* reject message m with message msg | ||
52 | * | ||
53 | * incompatible with: fileinto, forward | ||
54 | */ | ||
55 | int do_reject(action_list_t *a, char *msg) | ||
56 | { | ||
57 | action_list_t *b = NULL; | ||
58 | |||
59 | /* see if this conflicts with any previous actions taken on this message */ | ||
60 | while (a != NULL) { | ||
61 | b = a; | ||
62 | if (a->a == ACTION_FILEINTO || | ||
63 | a->a == ACTION_KEEP || | ||
64 | a->a == ACTION_REDIRECT || | ||
65 | a->a == ACTION_REJECT || | ||
66 | a->a == ACTION_VACATION || | ||
67 | a->a == ACTION_SETFLAG || | ||
68 | a->a == ACTION_ADDFLAG || | ||
69 | a->a == ACTION_REMOVEFLAG || | ||
70 | a->a == ACTION_MARK || | ||
71 | a->a == ACTION_UNMARK | ||
72 | ) | ||
73 | return SIEVE_RUN_ERROR; | ||
74 | a = a->next; | ||
75 | } | ||
76 | |||
77 | /* add to the action list */ | ||
78 | a = (action_list_t *) xmalloc(sizeof(action_list_t)); | ||
79 | if (a == NULL) | ||
80 | return SIEVE_NOMEM; | ||
81 | a->a = ACTION_REJECT; | ||
82 | a->u.rej.msg = msg; | ||
83 | b->next = a; | ||
84 | a->next = NULL; | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | /* fileinto message m into mailbox | ||
89 | * | ||
90 | * incompatible with: reject | ||
91 | */ | ||
92 | int do_fileinto(action_list_t *a, char *mbox, sieve_imapflags_t *imapflags) | ||
93 | { | ||
94 | action_list_t *b = NULL; | ||
95 | |||
96 | /* see if this conflicts with any previous actions taken on this message */ | ||
97 | while (a != NULL) { | ||
98 | b = a; | ||
99 | if (a->a == ACTION_REJECT) | ||
100 | return SIEVE_RUN_ERROR; | ||
101 | a = a->next; | ||
102 | } | ||
103 | |||
104 | /* add to the action list */ | ||
105 | a = (action_list_t *) xmalloc(sizeof(action_list_t)); | ||
106 | if (a == NULL) | ||
107 | return SIEVE_NOMEM; | ||
108 | a->a = ACTION_FILEINTO; | ||
109 | a->u.fil.mailbox = mbox; | ||
110 | a->u.fil.imapflags = imapflags; | ||
111 | b->next = a; | ||
112 | a->next = NULL; | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | /* forward message m to to addr | ||
117 | * | ||
118 | * incompatible with: reject | ||
119 | */ | ||
120 | int do_forward(action_list_t *a, char *addr) | ||
121 | { | ||
122 | action_list_t *b = NULL; | ||
123 | |||
124 | /* xxx we should validate addr */ | ||
125 | |||
126 | /* see if this conflicts with any previous actions taken on this message */ | ||
127 | while (a != NULL) { | ||
128 | b = a; | ||
129 | if (a->a == ACTION_REJECT) | ||
130 | return SIEVE_RUN_ERROR; | ||
131 | a = a->next; | ||
132 | } | ||
133 | |||
134 | /* add to the action list */ | ||
135 | a = (action_list_t *) xmalloc(sizeof(action_list_t)); | ||
136 | if (a == NULL) | ||
137 | return SIEVE_NOMEM; | ||
138 | a->a = ACTION_REDIRECT; | ||
139 | a->u.red.addr = addr; | ||
140 | a->next = NULL; | ||
141 | b->next = a; | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | /* keep message | ||
146 | * | ||
147 | * incompatible with: reject | ||
148 | */ | ||
149 | int do_keep(action_list_t *a, sieve_imapflags_t *imapflags) | ||
150 | { | ||
151 | action_list_t *b = NULL; | ||
152 | |||
153 | /* see if this conflicts with any previous actions taken on this message */ | ||
154 | while (a != NULL) { | ||
155 | b = a; | ||
156 | if (a->a == ACTION_REJECT) | ||
157 | return SIEVE_RUN_ERROR; | ||
158 | if (a->a == ACTION_KEEP) /* don't bother doing it twice */ | ||
159 | return 0; | ||
160 | a = a->next; | ||
161 | } | ||
162 | |||
163 | /* add to the action list */ | ||
164 | a = (action_list_t *) xmalloc(sizeof(action_list_t)); | ||
165 | if (a == NULL) | ||
166 | return SIEVE_NOMEM; | ||
167 | a->a = ACTION_KEEP; | ||
168 | a->u.keep.imapflags = imapflags; | ||
169 | a->next = NULL; | ||
170 | b->next = a; | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | /* discard message m | ||
175 | * | ||
176 | * incompatible with: nothing---it doesn't cancel any actions | ||
177 | */ | ||
178 | int do_discard(action_list_t *a) | ||
179 | { | ||
180 | action_list_t *b = NULL; | ||
181 | |||
182 | /* see if this conflicts with any previous actions taken on this message */ | ||
183 | while (a != NULL) { | ||
184 | b = a; | ||
185 | if (a->a == ACTION_DISCARD) /* don't bother doing twice */ | ||
186 | return 0; | ||
187 | a = a->next; | ||
188 | } | ||
189 | |||
190 | /* add to the action list */ | ||
191 | a = (action_list_t *) xmalloc(sizeof(action_list_t)); | ||
192 | if (a == NULL) | ||
193 | return SIEVE_NOMEM; | ||
194 | a->a = ACTION_DISCARD; | ||
195 | a->next = NULL; | ||
196 | b->next = a; | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | int do_vacation(action_list_t *a, char *addr, char *fromaddr, | ||
201 | char *subj, char *msg, int days, | ||
202 | int mime) | ||
203 | { | ||
204 | action_list_t *b = NULL; | ||
205 | |||
206 | /* see if this conflicts with any previous actions taken on this message */ | ||
207 | while (a != NULL) { | ||
208 | b = a; | ||
209 | if (a->a == ACTION_REJECT || | ||
210 | a->a == ACTION_VACATION) /* vacation can't be used twice */ | ||
211 | return SIEVE_RUN_ERROR; | ||
212 | a = a->next; | ||
213 | } | ||
214 | |||
215 | /* add to the action list */ | ||
216 | a = (action_list_t *) xmalloc(sizeof(action_list_t)); | ||
217 | if (a == NULL) | ||
218 | return SIEVE_NOMEM; | ||
219 | a->a = ACTION_VACATION; | ||
220 | a->u.vac.send.addr = addr; | ||
221 | a->u.vac.send.fromaddr = fromaddr; | ||
222 | a->u.vac.send.subj = subj; /* user specified subject */ | ||
223 | a->u.vac.send.msg = msg; | ||
224 | a->u.vac.send.mime = mime; | ||
225 | a->u.vac.autoresp.days = days; | ||
226 | a->next = NULL; | ||
227 | b->next = a; | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | /* setflag f on message m | ||
232 | * | ||
233 | * incompatible with: reject | ||
234 | */ | ||
235 | int do_setflag(action_list_t *a, char *flag) | ||
236 | { | ||
237 | action_list_t *b = NULL; | ||
238 | |||
239 | /* see if this conflicts with any previous actions taken on this message */ | ||
240 | while (a != NULL) { | ||
241 | b = a; | ||
242 | if (a->a == ACTION_REJECT) | ||
243 | return SIEVE_RUN_ERROR; | ||
244 | a = a->next; | ||
245 | } | ||
246 | |||
247 | /* add to the action list */ | ||
248 | a = (action_list_t *) xmalloc(sizeof(action_list_t)); | ||
249 | if (a == NULL) | ||
250 | return SIEVE_NOMEM; | ||
251 | a->a = ACTION_SETFLAG; | ||
252 | a->u.fla.flag = flag; | ||
253 | b->next = a; | ||
254 | a->next = NULL; | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | /* addflag f on message m | ||
259 | * | ||
260 | * incompatible with: reject | ||
261 | */ | ||
262 | int do_addflag(action_list_t *a, char *flag) | ||
263 | { | ||
264 | action_list_t *b = NULL; | ||
265 | |||
266 | /* see if this conflicts with any previous actions taken on this message */ | ||
267 | while (a != NULL) { | ||
268 | b = a; | ||
269 | if (a->a == ACTION_REJECT) | ||
270 | return SIEVE_RUN_ERROR; | ||
271 | a = a->next; | ||
272 | } | ||
273 | |||
274 | /* add to the action list */ | ||
275 | a = (action_list_t *) xmalloc(sizeof(action_list_t)); | ||
276 | if (a == NULL) | ||
277 | return SIEVE_NOMEM; | ||
278 | a->a = ACTION_ADDFLAG; | ||
279 | a->u.fla.flag = flag; | ||
280 | b->next = a; | ||
281 | a->next = NULL; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | /* removeflag f on message m | ||
286 | * | ||
287 | * incompatible with: reject | ||
288 | */ | ||
289 | int do_removeflag(action_list_t *a, char *flag) | ||
290 | { | ||
291 | action_list_t *b = NULL; | ||
292 | |||
293 | /* see if this conflicts with any previous actions taken on this message */ | ||
294 | while (a != NULL) { | ||
295 | b = a; | ||
296 | if (a->a == ACTION_REJECT) | ||
297 | return SIEVE_RUN_ERROR; | ||
298 | a = a->next; | ||
299 | } | ||
300 | |||
301 | /* add to the action list */ | ||
302 | a = (action_list_t *) xmalloc(sizeof(action_list_t)); | ||
303 | if (a == NULL) | ||
304 | return SIEVE_NOMEM; | ||
305 | a->a = ACTION_REMOVEFLAG; | ||
306 | a->u.fla.flag = flag; | ||
307 | b->next = a; | ||
308 | a->next = NULL; | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | |||
313 | /* mark message m | ||
314 | * | ||
315 | * incompatible with: reject | ||
316 | */ | ||
317 | int do_mark(action_list_t *a) | ||
318 | { | ||
319 | action_list_t *b = NULL; | ||
320 | |||
321 | /* see if this conflicts with any previous actions taken on this message */ | ||
322 | while (a != NULL) { | ||
323 | b = a; | ||
324 | if (a->a == ACTION_REJECT) | ||
325 | return SIEVE_RUN_ERROR; | ||
326 | a = a->next; | ||
327 | } | ||
328 | |||
329 | /* add to the action list */ | ||
330 | a = (action_list_t *) xmalloc(sizeof(action_list_t)); | ||
331 | if (a == NULL) | ||
332 | return SIEVE_NOMEM; | ||
333 | a->a = ACTION_MARK; | ||
334 | b->next = a; | ||
335 | a->next = NULL; | ||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | |||
340 | /* unmark message m | ||
341 | * | ||
342 | * incompatible with: reject | ||
343 | */ | ||
344 | int do_unmark(action_list_t *a) | ||
345 | { | ||
346 | action_list_t *b = NULL; | ||
347 | |||
348 | /* see if this conflicts with any previous actions taken on this message */ | ||
349 | while (a != NULL) { | ||
350 | b = a; | ||
351 | if (a->a == ACTION_REJECT) | ||
352 | return SIEVE_RUN_ERROR; | ||
353 | a = a->next; | ||
354 | } | ||
355 | |||
356 | /* add to the action list */ | ||
357 | a = (action_list_t *) xmalloc(sizeof(action_list_t)); | ||
358 | if (a == NULL) | ||
359 | return SIEVE_NOMEM; | ||
360 | a->a = ACTION_UNMARK; | ||
361 | b->next = a; | ||
362 | a->next = NULL; | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int priority_tonum(const char *str) | ||
367 | { | ||
368 | switch (*str) { | ||
369 | case 'l': | ||
370 | if (strcasecmp(str,"low")==0) return 1; | ||
371 | break; | ||
372 | |||
373 | case 'm': | ||
374 | if (strcasecmp(str,"medium")==0) return 2; | ||
375 | break; | ||
376 | |||
377 | case 'h': | ||
378 | if (strcasecmp(str,"high")==0) return 3; | ||
379 | break; | ||
380 | } | ||
381 | |||
382 | /* didn't match */ | ||
383 | return -1; | ||
384 | } | ||
385 | /* returns 1 if new is less than old */ | ||
386 | static int priority_compare(const char *old, const char *new) | ||
387 | { | ||
388 | if (priority_tonum(new) < priority_tonum(old)) return 1; | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | /* notify | ||
394 | * | ||
395 | * incomaptible with: none | ||
396 | */ | ||
397 | int do_notify(sieve_interp_t *i,void *m, notify_action_t *notify, | ||
398 | const char *priority, char *message, stringlist_t *sl) | ||
399 | { | ||
400 | /* if non-default action exists, and | ||
401 | * priority is < old priority then leave current one | ||
402 | */ | ||
403 | if ((notify->exists > 0) && (priority_compare(notify->priority, priority)==1)) | ||
404 | return 0; | ||
405 | |||
406 | /* free old stuff if exists */ | ||
407 | if (notify->exists) | ||
408 | { | ||
409 | if (notify->message) | ||
410 | free(notify->message); | ||
411 | if (notify->headers) | ||
412 | free_sl(notify->headers); | ||
413 | } | ||
414 | |||
415 | notify->exists = 1; | ||
416 | notify->priority = priority; | ||
417 | notify->message = message; | ||
418 | notify->headers = sl; | ||
419 | |||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | /* denotify | ||
424 | * | ||
425 | * incomaptible with: none | ||
426 | */ | ||
427 | int do_denotify(notify_action_t *notify) | ||
428 | { | ||
429 | |||
430 | /* free old stuff if exists */ | ||
431 | if (notify->exists) | ||
432 | { | ||
433 | if (notify->message) | ||
434 | free(notify->message); | ||
435 | if (notify->headers) | ||
436 | free_sl(notify->headers); | ||
437 | } | ||
438 | |||
439 | notify->exists = 0; | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | |||
445 | |||
446 | /* given a header, extract an address out of it. if marker points to NULL, | ||
447 | extract the first address. otherwise, it's an index into the header to | ||
448 | say where to start extracting */ | ||
449 | struct addr_marker { | ||
450 | struct address *where; | ||
451 | char *freeme; | ||
452 | }; | ||
453 | |||
454 | int parse_address(const char *header, void **data, void **marker) | ||
455 | { | ||
456 | struct addr_marker *am = (struct addr_marker *) *marker; | ||
457 | |||
458 | parseaddr_list(header, (struct address **) data); | ||
459 | am = (void *) xmalloc(sizeof(struct addr_marker)); | ||
460 | am->where = *data; | ||
461 | am->freeme = NULL; | ||
462 | *marker = am; | ||
463 | return SIEVE_OK; | ||
464 | } | ||
465 | |||
466 | char *get_address(address_part_t addrpart, void **data, void **marker, | ||
467 | int canon_domain) | ||
468 | { | ||
469 | char *ret = NULL; | ||
470 | struct address *a; | ||
471 | struct addr_marker *am = *marker; | ||
472 | |||
473 | a = am->where; | ||
474 | if (am->freeme) { | ||
475 | free(am->freeme); | ||
476 | am->freeme = NULL; | ||
477 | } | ||
478 | |||
479 | if (a == NULL) { | ||
480 | ret = NULL; | ||
481 | } else { | ||
482 | if (canon_domain && a->domain) | ||
483 | lcase(a->domain); | ||
484 | |||
485 | switch (addrpart) { | ||
486 | case ADDRESS_ALL: | ||
487 | #define U_DOMAIN "unspecified-domain" | ||
488 | #define U_USER "unknown-user" | ||
489 | if (a->mailbox || a->domain) { | ||
490 | char *m = a->mailbox ? a->mailbox : U_USER; | ||
491 | char *d = a->domain ? a->domain : U_DOMAIN; | ||
492 | am->freeme = (char *) xmalloc(strlen(m) + strlen(d) + 2); | ||
493 | |||
494 | sprintf(am->freeme, "%s@%s", m, d); | ||
495 | ret = am->freeme; | ||
496 | } else { | ||
497 | ret = NULL; | ||
498 | } | ||
499 | break; | ||
500 | |||
501 | case ADDRESS_LOCALPART: | ||
502 | ret = a->mailbox; | ||
503 | break; | ||
504 | |||
505 | case ADDRESS_DOMAIN: | ||
506 | ret = a->domain; | ||
507 | break; | ||
508 | |||
509 | case ADDRESS_USER: | ||
510 | if (a->mailbox) { | ||
511 | char *p = strchr(a->mailbox, '+'); | ||
512 | int len = p ? p - a->mailbox : strlen(a->mailbox); | ||
513 | |||
514 | am->freeme = (char *) xmalloc(len + 1); | ||
515 | strncpy(am->freeme, a->mailbox, len); | ||
516 | am->freeme[len] = '\0'; | ||
517 | ret = am->freeme; | ||
518 | } else { | ||
519 | ret = NULL; | ||
520 | } | ||
521 | break; | ||
522 | |||
523 | case ADDRESS_DETAIL: | ||
524 | if (a->mailbox) { | ||
525 | char *p = strchr(a->mailbox, '+'); | ||
526 | ret = (p ? p + 1 : NULL); | ||
527 | } else { | ||
528 | ret = NULL; | ||
529 | } | ||
530 | break; | ||
531 | } | ||
532 | a = a->next; | ||
533 | am->where = a; | ||
534 | } | ||
535 | *marker = am; | ||
536 | return ret; | ||
537 | } | ||
538 | |||
539 | int free_address(void **data, void **marker) | ||
540 | { | ||
541 | struct addr_marker *am = (struct addr_marker *) *marker; | ||
542 | |||
543 | if (*data) | ||
544 | parseaddr_free((struct address *) *data); | ||
545 | *data = NULL; | ||
546 | if (am->freeme) free(am->freeme); | ||
547 | free(am); | ||
548 | *marker = NULL; | ||
549 | return SIEVE_OK; | ||
550 | } | ||
551 | |||
552 | #define NEWMAIL_MSG "You have new mail" | ||
553 | |||
554 | notify_action_t *default_notify_action(void) | ||
555 | { | ||
556 | notify_action_t *ret = xmalloc(sizeof(notify_action_t)); | ||
557 | |||
558 | ret->exists = -1; /* flag as default action */ | ||
559 | ret->priority = "medium"; | ||
560 | ret->message = xstrdup(NEWMAIL_MSG); | ||
561 | ret->headers = NULL; /* subject, to, from */ | ||
562 | |||
563 | return ret; | ||
564 | } | ||
565 | |||
566 | action_list_t *new_action_list(void) | ||
567 | { | ||
568 | action_list_t *ret = xmalloc(sizeof(action_list_t)); | ||
569 | |||
570 | if (ret != NULL) { | ||
571 | ret->a = ACTION_NONE; | ||
572 | ret->param = NULL; | ||
573 | ret->next = NULL; | ||
574 | } | ||
575 | return ret; | ||
576 | } | ||
577 | |||
578 | void free_action_list(action_list_t *a) | ||
579 | { | ||
580 | while (a) { | ||
581 | action_list_t *b = a->next; | ||
582 | switch (a->a) { | ||
583 | case ACTION_VACATION: | ||
584 | if (a->u.vac.send.addr) free(a->u.vac.send.addr); | ||
585 | if (a->u.vac.send.fromaddr) free(a->u.vac.send.fromaddr); | ||
586 | if (a->u.vac.send.subj) free(a->u.vac.send.subj); | ||
587 | break; | ||
588 | |||
589 | default: | ||
590 | break; | ||
591 | } | ||
592 | free(a); | ||
593 | a = b; | ||
594 | } | ||
595 | } | ||
596 |
sieve/message.h
0 → 100644
1 | /* message.h | ||
2 | * Larry Greenfield | ||
3 | * $Id$ | ||
4 | */ | ||
5 | /*********************************************************** | ||
6 | Copyright 1999 by Carnegie Mellon University | ||
7 | |||
8 | All Rights Reserved | ||
9 | |||
10 | Permission to use, copy, modify, and distribute this software and its | ||
11 | documentation for any purpose and without fee is hereby granted, | ||
12 | provided that the above copyright notice appear in all copies and that | ||
13 | both that copyright notice and this permission notice appear in | ||
14 | supporting documentation, and that the name of Carnegie Mellon | ||
15 | University not be used in advertising or publicity pertaining to | ||
16 | distribution of the software without specific, written prior | ||
17 | permission. | ||
18 | |||
19 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
20 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
21 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
22 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
23 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
24 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
25 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
26 | ******************************************************************/ | ||
27 | |||
28 | #ifndef MESSAGE_H | ||
29 | #define MESSAGE_H | ||
30 | |||
31 | #include "sieve_interface.h" /* for action contexts */ | ||
32 | #include "tree.h" /* for stringlist_t */ | ||
33 | |||
34 | typedef struct Action action_list_t; | ||
35 | |||
36 | typedef enum { | ||
37 | ACTION_NONE, | ||
38 | ACTION_REJECT, | ||
39 | ACTION_FILEINTO, | ||
40 | ACTION_KEEP, | ||
41 | ACTION_REDIRECT, | ||
42 | ACTION_DISCARD, | ||
43 | ACTION_VACATION, | ||
44 | ACTION_SETFLAG, | ||
45 | ACTION_ADDFLAG, | ||
46 | ACTION_REMOVEFLAG, | ||
47 | ACTION_MARK, | ||
48 | ACTION_UNMARK, | ||
49 | ACTION_NOTIFY, | ||
50 | ACTION_DENOTIFY | ||
51 | } action_t; | ||
52 | |||
53 | /* information */ | ||
54 | action_list_t *new_action_list(void); | ||
55 | void free_action_list(action_list_t *actions); | ||
56 | |||
57 | /* invariant: always have a dummy element when free_action_list, param | ||
58 | and vac_subj are freed. none of the others are automatically freed. | ||
59 | |||
60 | the do_action() functions should copy param */ | ||
61 | struct Action { | ||
62 | action_t a; | ||
63 | union { | ||
64 | sieve_reject_context_t rej; | ||
65 | sieve_fileinto_context_t fil; | ||
66 | sieve_keep_context_t keep; | ||
67 | sieve_redirect_context_t red; | ||
68 | struct { | ||
69 | /* addr, fromaddr, subj - freed! */ | ||
70 | sieve_send_response_context_t send; | ||
71 | sieve_autorespond_context_t autoresp; | ||
72 | } vac; | ||
73 | struct { | ||
74 | char *flag; | ||
75 | } fla; | ||
76 | } u; | ||
77 | char *param; /* freed! */ | ||
78 | struct Action *next; | ||
79 | char *vac_subj; /* freed! */ | ||
80 | char *vac_msg; | ||
81 | int vac_days; | ||
82 | }; | ||
83 | |||
84 | typedef struct notify_action_s { | ||
85 | |||
86 | int exists; /* 0 = no +/-1 = yes (-1 flags default action) */ | ||
87 | |||
88 | const char *priority; | ||
89 | char *message; | ||
90 | stringlist_t *headers; | ||
91 | |||
92 | } notify_action_t; | ||
93 | |||
94 | /* header parsing */ | ||
95 | typedef enum { | ||
96 | ADDRESS_ALL, | ||
97 | ADDRESS_LOCALPART, | ||
98 | ADDRESS_DOMAIN, | ||
99 | ADDRESS_USER, | ||
100 | ADDRESS_DETAIL | ||
101 | } address_part_t; | ||
102 | |||
103 | int parse_address(const char *header, void **data, void **marker); | ||
104 | char *get_address(address_part_t addrpart, void **data, void **marker, | ||
105 | int canon_domain); | ||
106 | int free_address(void **data, void **marker); | ||
107 | notify_action_t *default_notify_action(void); | ||
108 | |||
109 | /* actions; return negative on failure. | ||
110 | * these don't actually perform the actions, they just add it to the | ||
111 | * action list */ | ||
112 | int do_reject(action_list_t *m, char *msg); | ||
113 | int do_fileinto(action_list_t *m, char *mbox, sieve_imapflags_t *imapflags); | ||
114 | int do_forward(action_list_t *m, char *addr); | ||
115 | int do_keep(action_list_t *m, sieve_imapflags_t *imapflags); | ||
116 | int do_discard(action_list_t *m); | ||
117 | int do_vacation(action_list_t *m, char *addr, char *fromaddr, | ||
118 | char *subj, char *msg, | ||
119 | int days, int mime); | ||
120 | int do_setflag(action_list_t *m, char *flag); | ||
121 | int do_addflag(action_list_t *m, char *flag); | ||
122 | int do_removeflag(action_list_t *m, char *flag); | ||
123 | int do_mark(action_list_t *m); | ||
124 | int do_unmark(action_list_t *m); | ||
125 | int do_notify(sieve_interp_t *i,void *m, notify_action_t *notify, | ||
126 | const char *priority, char *message, stringlist_t *sl); | ||
127 | int do_denotify(notify_action_t *notify); | ||
128 | |||
129 | |||
130 | #endif |
sieve/parseaddr.c
0 → 100644
1 | /* parseaddr.c -- RFC 822 address parser | ||
2 | * $Id$ | ||
3 | * | ||
4 | * Copyright (c) 1998-2000 Carnegie Mellon University. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in | ||
15 | * the documentation and/or other materials provided with the | ||
16 | * distribution. | ||
17 | * | ||
18 | * 3. The name "Carnegie Mellon University" must not be used to | ||
19 | * endorse or promote products derived from this software without | ||
20 | * prior written permission. For permission or any other legal | ||
21 | * details, please contact | ||
22 | * Office of Technology Transfer | ||
23 | * Carnegie Mellon University | ||
24 | * 5000 Forbes Avenue | ||
25 | * Pittsburgh, PA 15213-3890 | ||
26 | * (412) 268-4387, fax: (412) 268-7395 | ||
27 | * tech-transfer@andrew.cmu.edu | ||
28 | * | ||
29 | * 4. Redistributions of any form whatsoever must retain the following | ||
30 | * acknowledgment: | ||
31 | * "This product includes software developed by Computing Services | ||
32 | * at Carnegie Mellon University (http://www.cmu.edu/computing/)." | ||
33 | * | ||
34 | * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
35 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
36 | * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE | ||
37 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
38 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | ||
39 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | ||
40 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
41 | * | ||
42 | */ | ||
43 | |||
44 | #include <config.h> | ||
45 | #include <stdio.h> | ||
46 | #include <stdlib.h> | ||
47 | #include <ctype.h> | ||
48 | #include <string.h> | ||
49 | |||
50 | #include "parseaddr.h" | ||
51 | #include "xmalloc.h" | ||
52 | |||
53 | static char parseaddr_unspecified_domain[] = "unspecified-domain"; | ||
54 | |||
55 | static void parseaddr_append (struct address ***addrpp, char *name, | ||
56 | char *route, char *mailbox, char *domain, | ||
57 | char **freemep); | ||
58 | static int parseaddr_phrase (char **inp, char **phrasep, char *specials); | ||
59 | static int parseaddr_domain (char **inp, char **domainp, char **commmentp); | ||
60 | static int parseaddr_route (char **inp, char **routep); | ||
61 | |||
62 | /* | ||
63 | * Parse an address list in 's', appending address structures to | ||
64 | * the list pointed to by 'addrp'. | ||
65 | */ | ||
66 | void | ||
67 | parseaddr_list(str, addrp) | ||
68 | const char *str; | ||
69 | struct address **addrp; | ||
70 | { | ||
71 | char *s; | ||
72 | int ingroup = 0; | ||
73 | char *freeme; | ||
74 | int tok = ' '; | ||
75 | char *phrase, *route, *mailbox, *domain, *comment; | ||
76 | |||
77 | /* Skip down to the tail */ | ||
78 | while (*addrp) { | ||
79 | addrp = &(*addrp)->next; | ||
80 | } | ||
81 | |||
82 | s = freeme = xstrdup(str); | ||
83 | |||
84 | while (tok) { | ||
85 | tok = parseaddr_phrase(&s, &phrase, ingroup ? ",@<;" : ",@<:"); | ||
86 | switch (tok) { | ||
87 | case ',': | ||
88 | case '\0': | ||
89 | case ';': | ||
90 | if (*phrase) { | ||
91 | parseaddr_append(&addrp, 0, 0, phrase, "", &freeme); | ||
92 | } | ||
93 | if (tok == ';') { | ||
94 | parseaddr_append(&addrp, 0, 0, 0, 0, &freeme); | ||
95 | ingroup = 0; | ||
96 | } | ||
97 | continue; | ||
98 | |||
99 | case ':': | ||
100 | parseaddr_append(&addrp, 0, 0, phrase, 0, &freeme); | ||
101 | ingroup++; | ||
102 | continue; | ||
103 | |||
104 | case '@': | ||
105 | tok = parseaddr_domain(&s, &domain, &comment); | ||
106 | parseaddr_append(&addrp, comment, 0, phrase, domain, &freeme); | ||
107 | continue; | ||
108 | |||
109 | case '<': | ||
110 | tok = parseaddr_phrase(&s, &mailbox, "@>"); | ||
111 | if (tok == '@') { | ||
112 | route = 0; | ||
113 | if (!*mailbox) { | ||
114 | *--s = '@'; | ||
115 | tok = parseaddr_route(&s, &route); | ||
116 | if (tok != ':') { | ||
117 | parseaddr_append(&addrp, phrase, route, "", "", &freeme); | ||
118 | while (tok && tok != '>') tok = *s++; | ||
119 | continue; | ||
120 | } | ||
121 | tok = parseaddr_phrase(&s, &mailbox, "@>"); | ||
122 | if (tok != '@') { | ||
123 | parseaddr_append(&addrp, phrase, route, mailbox, "", | ||
124 | &freeme); | ||
125 | continue; | ||
126 | } | ||
127 | } | ||
128 | tok = parseaddr_domain(&s, &domain, 0); | ||
129 | parseaddr_append(&addrp, phrase, route, mailbox, domain, | ||
130 | &freeme); | ||
131 | while (tok && tok != '>') tok = *s++; | ||
132 | continue; /* effectively auto-inserts a comma */ | ||
133 | } | ||
134 | else { | ||
135 | parseaddr_append(&addrp, phrase, 0, mailbox, "", &freeme); | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | if (ingroup) parseaddr_append(&addrp, 0, 0, 0, 0, &freeme); | ||
140 | |||
141 | if (freeme) free(freeme); | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * Free the address list 'addr' | ||
146 | */ | ||
147 | void | ||
148 | parseaddr_free(addr) | ||
149 | struct address *addr; | ||
150 | { | ||
151 | struct address *next; | ||
152 | |||
153 | while (addr) { | ||
154 | if (addr->freeme) free(addr->freeme); | ||
155 | next = addr->next; | ||
156 | free((char *)addr); | ||
157 | addr = next; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * Helper function to append a new address structure to and address list. | ||
163 | */ | ||
164 | static void | ||
165 | parseaddr_append(addrpp, name, route, mailbox, domain, freemep) | ||
166 | struct address ***addrpp; | ||
167 | char *name; | ||
168 | char *route; | ||
169 | char *mailbox; | ||
170 | char *domain; | ||
171 | char **freemep; | ||
172 | { | ||
173 | struct address *newaddr; | ||
174 | |||
175 | newaddr = (struct address *)xmalloc(sizeof(struct address)); | ||
176 | if (name && *name) { | ||
177 | newaddr->name = name; | ||
178 | } | ||
179 | else { | ||
180 | newaddr->name = 0; | ||
181 | } | ||
182 | |||
183 | if (route && *route) { | ||
184 | newaddr->route = route; | ||
185 | } | ||
186 | else { | ||
187 | newaddr->route = 0; | ||
188 | } | ||
189 | |||
190 | newaddr->mailbox = mailbox; | ||
191 | |||
192 | if (domain && !*domain) { | ||
193 | domain = parseaddr_unspecified_domain; | ||
194 | } | ||
195 | newaddr->domain = domain; | ||
196 | |||
197 | newaddr->next = 0; | ||
198 | newaddr->freeme = *freemep; | ||
199 | *freemep = 0; | ||
200 | |||
201 | **addrpp = newaddr; | ||
202 | *addrpp = &newaddr->next; | ||
203 | } | ||
204 | |||
205 | /* Macro to skip white space and rfc822 comments */ | ||
206 | |||
207 | #define SKIPWHITESPACE(s) \ | ||
208 | { \ | ||
209 | int _c, _comment = 0; \ | ||
210 | \ | ||
211 | while ((_c = *(s))) { \ | ||
212 | if (_c == '(') { \ | ||
213 | _comment = 1; \ | ||
214 | (s)++; \ | ||
215 | while ((_comment && (_c = *(s)))) { \ | ||
216 | (s)++; \ | ||
217 | if (_c == '\\' && *(s)) (s)++; \ | ||
218 | else if (_c == '(') _comment++; \ | ||
219 | else if (_c == ')') _comment--; \ | ||
220 | } \ | ||
221 | (s)--; \ | ||
222 | } \ | ||
223 | else if (!isspace(_c)) break; \ | ||
224 | (s)++; \ | ||
225 | } \ | ||
226 | } | ||
227 | |||
228 | /* | ||
229 | * Parse an RFC 822 "phrase", stopping at 'specials' | ||
230 | */ | ||
231 | static int parseaddr_phrase(inp, phrasep, specials) | ||
232 | char **inp; | ||
233 | char **phrasep; | ||
234 | char *specials; | ||
235 | { | ||
236 | int c; | ||
237 | char *src = *inp; | ||
238 | char *dst; | ||
239 | |||
240 | SKIPWHITESPACE(src); | ||
241 | |||
242 | *phrasep = dst = src; | ||
243 | |||
244 | for (;;) { | ||
245 | c = *src++; | ||
246 | if (c == '\"') { | ||
247 | while ((c = *src)) { | ||
248 | src++; | ||
249 | if (c == '\"') break; | ||
250 | if (c == '\\') { | ||
251 | if (!(c = *src)) break; | ||
252 | src++; | ||
253 | } | ||
254 | *dst++ = c; | ||
255 | } | ||
256 | } | ||
257 | else if (isspace(c) || c == '(') { | ||
258 | src--; | ||
259 | SKIPWHITESPACE(src); | ||
260 | *dst++ = ' '; | ||
261 | } | ||
262 | else if (!c || strchr(specials, c)) { | ||
263 | if (dst > *phrasep && dst[-1] == ' ') dst--; | ||
264 | *dst = '\0'; | ||
265 | *inp = src; | ||
266 | return c; | ||
267 | } | ||
268 | else { | ||
269 | *dst++ = c; | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | |||
274 | /* | ||
275 | * Parse a domain. If 'commentp' is non-nil, parses any trailing comment | ||
276 | */ | ||
277 | static int parseaddr_domain(inp, domainp, commentp) | ||
278 | char **inp; | ||
279 | char **domainp; | ||
280 | char **commentp; | ||
281 | { | ||
282 | int c; | ||
283 | char *src = *inp; | ||
284 | char *dst; | ||
285 | char *cdst; | ||
286 | int comment; | ||
287 | |||
288 | if (commentp) *commentp = 0; | ||
289 | SKIPWHITESPACE(src); | ||
290 | |||
291 | *domainp = dst = src; | ||
292 | |||
293 | for (;;) { | ||
294 | c = *src++; | ||
295 | if (isalnum(c) || c == '-' || c == '[' || c == ']') { | ||
296 | *dst++ = c; | ||
297 | if (commentp) *commentp = 0; | ||
298 | } | ||
299 | else if (c == '.') { | ||
300 | if (dst > *domainp && dst[-1] != '.') *dst++ = c; | ||
301 | if (commentp) *commentp = 0; | ||
302 | } | ||
303 | else if (c == '(') { | ||
304 | if (commentp) { | ||
305 | *commentp = cdst = src; | ||
306 | comment = 1; | ||
307 | while (comment && (c = *src)) { | ||
308 | src++; | ||
309 | if (c == '(') comment++; | ||
310 | else if (c == ')') comment--; | ||
311 | else if (c == '\\' && (c = *src)) src++; | ||
312 | |||
313 | if (comment) *cdst++ = c; | ||
314 | } | ||
315 | *cdst = '\0'; | ||
316 | } | ||
317 | else { | ||
318 | src--; | ||
319 | SKIPWHITESPACE(src); | ||
320 | } | ||
321 | } | ||
322 | else if (!isspace(c)) { | ||
323 | if (dst > *domainp && dst[-1] == '.') dst--; | ||
324 | *dst = '\0'; | ||
325 | *inp = src; | ||
326 | return c; | ||
327 | } | ||
328 | } | ||
329 | } | ||
330 | |||
331 | /* | ||
332 | * Parse a source route (at-domain-list) | ||
333 | */ | ||
334 | static int parseaddr_route(inp, routep) | ||
335 | char **inp; | ||
336 | char **routep; | ||
337 | { | ||
338 | int c; | ||
339 | char *src = *inp; | ||
340 | char *dst; | ||
341 | |||
342 | SKIPWHITESPACE(src); | ||
343 | |||
344 | *routep = dst = src; | ||
345 | |||
346 | for (;;) { | ||
347 | c = *src++; | ||
348 | if (isalnum(c) || c == '-' || c == '[' || c == ']' || | ||
349 | c == ',' || c == '@') { | ||
350 | *dst++ = c; | ||
351 | } | ||
352 | else if (c == '.') { | ||
353 | if (dst > *routep && dst[-1] != '.') *dst++ = c; | ||
354 | } | ||
355 | else if (isspace(c) || c == '(') { | ||
356 | src--; | ||
357 | SKIPWHITESPACE(src); | ||
358 | } | ||
359 | else { | ||
360 | while (dst > *routep && | ||
361 | (dst[-1] == '.' || dst[-1] == ',' || dst[-1] == '@')) dst--; | ||
362 | *dst = '\0'; | ||
363 | *inp = src; | ||
364 | return c; | ||
365 | } | ||
366 | } | ||
367 | } | ||
368 |
sieve/parseaddr.h
0 → 100644
1 | /* parseaddr.h -- RFC 822 address parser | ||
2 | $Id$ | ||
3 | |||
4 | * Copyright (c) 1998-2000 Carnegie Mellon University. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in | ||
15 | * the documentation and/or other materials provided with the | ||
16 | * distribution. | ||
17 | * | ||
18 | * 3. The name "Carnegie Mellon University" must not be used to | ||
19 | * endorse or promote products derived from this software without | ||
20 | * prior written permission. For permission or any other legal | ||
21 | * details, please contact | ||
22 | * Office of Technology Transfer | ||
23 | * Carnegie Mellon University | ||
24 | * 5000 Forbes Avenue | ||
25 | * Pittsburgh, PA 15213-3890 | ||
26 | * (412) 268-4387, fax: (412) 268-7395 | ||
27 | * tech-transfer@andrew.cmu.edu | ||
28 | * | ||
29 | * 4. Redistributions of any form whatsoever must retain the following | ||
30 | * acknowledgment: | ||
31 | * "This product includes software developed by Computing Services | ||
32 | * at Carnegie Mellon University (http://www.cmu.edu/computing/)." | ||
33 | * | ||
34 | * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
35 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
36 | * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE | ||
37 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
38 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | ||
39 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | ||
40 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
41 | * | ||
42 | * | ||
43 | */ | ||
44 | |||
45 | #ifndef INCLUDED_PARSEADDR_H | ||
46 | #define INCLUDED_PARSEADDR_H | ||
47 | |||
48 | #ifndef P | ||
49 | #ifdef __STDC__ | ||
50 | #define P(x) x | ||
51 | #else | ||
52 | #define P(x) () | ||
53 | #endif | ||
54 | #endif | ||
55 | |||
56 | struct address { | ||
57 | char *name; | ||
58 | char *route; | ||
59 | char *mailbox; | ||
60 | char *domain; | ||
61 | struct address *next; | ||
62 | char *freeme; /* If non-nil, free */ | ||
63 | }; | ||
64 | |||
65 | extern void parseaddr_list P((const char *s, struct address **addrp)); | ||
66 | extern void parseaddr_free P((struct address *addr)); | ||
67 | |||
68 | |||
69 | #endif /* INCLUDED_PARSEADDR_H */ |
sieve/script.c
0 → 100644
1 | /* script.c -- sieve script functions | ||
2 | * Larry Greenfield | ||
3 | * $Id$ | ||
4 | */ | ||
5 | /*********************************************************** | ||
6 | Copyright 1999 by Carnegie Mellon University | ||
7 | |||
8 | All Rights Reserved | ||
9 | |||
10 | Permission to use, copy, modify, and distribute this software and its | ||
11 | documentation for any purpose and without fee is hereby granted, | ||
12 | provided that the above copyright notice appear in all copies and that | ||
13 | both that copyright notice and this permission notice appear in | ||
14 | supporting documentation, and that the name of Carnegie Mellon | ||
15 | University not be used in advertising or publicity pertaining to | ||
16 | distribution of the software without specific, written prior | ||
17 | permission. | ||
18 | |||
19 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
20 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
21 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
22 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
23 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
24 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
25 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
26 | ******************************************************************/ | ||
27 | |||
28 | #ifdef HAVE_CONFIG_H | ||
29 | #include <config.h> | ||
30 | #endif | ||
31 | |||
32 | #include <stdlib.h> | ||
33 | #include <string.h> | ||
34 | #include <md5global.h> | ||
35 | #include <md5.h> | ||
36 | #include <ctype.h> | ||
37 | #ifdef HAVE_STRINGS_H | ||
38 | # include <strings.h> | ||
39 | #endif | ||
40 | |||
41 | #include "xmalloc.h" | ||
42 | |||
43 | #include "sieve_interface.h" | ||
44 | #include "interp.h" | ||
45 | #include "script.h" | ||
46 | #include "tree.h" | ||
47 | #include "sieve-gram.h" | ||
48 | #include "message.h" | ||
49 | |||
50 | /* does this interpretor support this requirement? */ | ||
51 | int script_require(sieve_script_t *s, char *req) | ||
52 | { | ||
53 | if (!strcmp("fileinto", req)) { | ||
54 | if (s->interp.fileinto) { | ||
55 | s->support.fileinto = 1; | ||
56 | return 1; | ||
57 | } else { | ||
58 | return 0; | ||
59 | } | ||
60 | } else if (!strcmp("reject", req)) { | ||
61 | if (s->interp.reject) { | ||
62 | s->support.reject = 1; | ||
63 | return 1; | ||
64 | } else { | ||
65 | return 0; | ||
66 | } | ||
67 | } else if (!strcmp("envelope", req)) { | ||
68 | if (s->interp.getenvelope) { | ||
69 | s->support.envelope = 1; | ||
70 | return 1; | ||
71 | } else { | ||
72 | return 0; | ||
73 | } | ||
74 | } else if (!strcmp("vacation", req)) { | ||
75 | if (s->interp.vacation) { | ||
76 | s->support.vacation = 1; | ||
77 | return 1; | ||
78 | } else { | ||
79 | return 0; | ||
80 | } | ||
81 | } else if (!strcmp("imapflags", req)) { | ||
82 | if (s->interp.markflags->flag) { | ||
83 | s->support.imapflags = 1; | ||
84 | return 1; | ||
85 | } else { | ||
86 | return 0; | ||
87 | } | ||
88 | } else if (!strcmp("notify",req)) { | ||
89 | if (s->interp.notify) { | ||
90 | s->support.notify = 1; | ||
91 | return 1; | ||
92 | } else { | ||
93 | return 0; | ||
94 | } | ||
95 | #ifdef ENABLE_REGEX | ||
96 | } else if (!strcmp("regex", req)) { | ||
97 | s->support.regex = 1; | ||
98 | return 1; | ||
99 | #endif | ||
100 | } else if (!strcmp("subaddress", req)) { | ||
101 | s->support.subaddress = 1; | ||
102 | return 1; | ||
103 | } else if (!strcmp("comparator-i;octet", req)) { | ||
104 | return 1; | ||
105 | } else if (!strcmp("comparator-i;ascii-casemap", req)) { | ||
106 | return 1; | ||
107 | } | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | /* given an interpretor and a script, produce an executable script */ | ||
112 | int sieve_script_parse(sieve_interp_t *interp, FILE *script, | ||
113 | void *script_context, sieve_script_t **ret) | ||
114 | { | ||
115 | sieve_script_t *s; | ||
116 | int res = SIEVE_OK; | ||
117 | extern int yylineno; | ||
118 | |||
119 | res = interp_verify(interp); | ||
120 | if (res != SIEVE_OK) { | ||
121 | return res; | ||
122 | } | ||
123 | |||
124 | s = (sieve_script_t *) xmalloc(sizeof(sieve_script_t)); | ||
125 | s->interp = *interp; | ||
126 | s->script_context = script_context; | ||
127 | /* clear all support bits */ | ||
128 | memset(&s->support, 0, sizeof(struct sieve_support)); | ||
129 | |||
130 | s->err = 0; | ||
131 | |||
132 | yylineno = 1; /* reset line number */ | ||
133 | s->cmds = sieve_parse(s, script); | ||
134 | if (s->err > 0) { | ||
135 | if (s->cmds) { | ||
136 | free_tree(s->cmds); | ||
137 | } | ||
138 | s->cmds = NULL; | ||
139 | res = SIEVE_PARSE_ERROR; | ||
140 | } | ||
141 | |||
142 | *ret = s; | ||
143 | return res; | ||
144 | } | ||
145 | |||
146 | char **stringlist_to_chararray(stringlist_t *list) | ||
147 | { | ||
148 | int size = 0; | ||
149 | stringlist_t *tmp = list; | ||
150 | stringlist_t *tofree; | ||
151 | char **ret; | ||
152 | int lup; | ||
153 | |||
154 | while (tmp!=NULL) | ||
155 | { | ||
156 | size++; | ||
157 | tmp=tmp->next; | ||
158 | } | ||
159 | |||
160 | ret = malloc( sizeof(char *) * (size+1)); | ||
161 | if (ret == NULL) return NULL; | ||
162 | |||
163 | tmp = list; | ||
164 | |||
165 | for (lup = 0;lup<size;lup++) | ||
166 | { | ||
167 | ret[lup] = tmp->s; | ||
168 | tmp=tmp->next; | ||
169 | } | ||
170 | |||
171 | ret[size]=NULL; | ||
172 | |||
173 | /* free element holders */ | ||
174 | tmp = list; | ||
175 | |||
176 | while (tmp!=NULL) | ||
177 | { | ||
178 | tofree = tmp; | ||
179 | tmp=tmp->next; | ||
180 | free(tofree); | ||
181 | } | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | int sieve_script_free(sieve_script_t **s) | ||
187 | { | ||
188 | if (*s) { | ||
189 | if ((*s)->cmds) { | ||
190 | free_tree((*s)->cmds); | ||
191 | } | ||
192 | free(*s); | ||
193 | } | ||
194 | |||
195 | return SIEVE_OK; | ||
196 | } | ||
197 | |||
198 | static int sysaddr(char *addr) | ||
199 | { | ||
200 | if (!strncasecmp(addr, "MAILER-DAEMON", 13)) | ||
201 | return 1; | ||
202 | |||
203 | if (!strncasecmp(addr, "LISTSERV", 8)) | ||
204 | return 1; | ||
205 | |||
206 | if (!strncasecmp(addr, "majordomo", 9)) | ||
207 | return 1; | ||
208 | |||
209 | if (strstr(addr, "-request")) | ||
210 | return 1; | ||
211 | |||
212 | if (!strncmp(addr, "owner-", 6)) | ||
213 | return 1; | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | /* look for myaddr and myaddrs in the body of a header */ | ||
219 | static int look_for_me(char *myaddr, stringlist_t *myaddrs, const char **body) | ||
220 | { | ||
221 | int found = 0; | ||
222 | int l; | ||
223 | stringlist_t *sl; | ||
224 | |||
225 | /* loop through each TO header */ | ||
226 | for (l = 0; body[l] != NULL && !found; l++) { | ||
227 | void *data = NULL, *marker = NULL; | ||
228 | char *addr; | ||
229 | |||
230 | parse_address(body[l], &data, &marker); | ||
231 | /* loop through each address in the header */ | ||
232 | while (!found && ((addr = get_address(ADDRESS_ALL, | ||
233 | &data, &marker, 1)) != NULL)) { | ||
234 | if (!strcmp(addr, myaddr)) { | ||
235 | found = 1; | ||
236 | break; | ||
237 | } | ||
238 | |||
239 | for (sl = myaddrs; sl != NULL && !found; sl = sl->next) { | ||
240 | void *altdata = NULL, *altmarker = NULL; | ||
241 | char *altaddr; | ||
242 | |||
243 | /* is this address one of my addresses? */ | ||
244 | parse_address(sl->s, &altdata, &altmarker); | ||
245 | altaddr = get_address(ADDRESS_ALL, &altdata, &altmarker, 1); | ||
246 | if (!strcmp(addr, altaddr)) | ||
247 | found = 1; | ||
248 | |||
249 | free_address(&altdata, &altmarker); | ||
250 | } | ||
251 | } | ||
252 | free_address(&data, &marker); | ||
253 | } | ||
254 | |||
255 | return found; | ||
256 | } | ||
257 | |||
258 | /* evaluates the test t. returns 1 if true, 0 if false. | ||
259 | */ | ||
260 | static int evaltest(sieve_interp_t *i, test_t *t, void *m) | ||
261 | { | ||
262 | testlist_t *tl; | ||
263 | stringlist_t *sl; | ||
264 | patternlist_t *pl; | ||
265 | int res = 0; | ||
266 | int addrpart = 0; | ||
267 | |||
268 | switch (t->type) { | ||
269 | case ADDRESS: | ||
270 | case ENVELOPE: | ||
271 | res = 0; | ||
272 | switch (t->u.ae.addrpart) { | ||
273 | case ALL: addrpart = ADDRESS_ALL; break; | ||
274 | case LOCALPART: addrpart = ADDRESS_LOCALPART; break; | ||
275 | case DOMAIN: addrpart = ADDRESS_DOMAIN; break; | ||
276 | case USER: addrpart = ADDRESS_USER; break; | ||
277 | case DETAIL: addrpart = ADDRESS_DETAIL; break; | ||
278 | } | ||
279 | for (sl = t->u.ae.sl; sl != NULL && !res; sl = sl->next) { | ||
280 | int l; | ||
281 | const char **body; | ||
282 | |||
283 | /* use getheader for address, getenvelope for envelope */ | ||
284 | if (((t->type == ADDRESS) ? | ||
285 | i->getheader(m, sl->s, &body) : | ||
286 | i->getenvelope(m, sl->s, &body)) != SIEVE_OK) { | ||
287 | continue; /* try next header */ | ||
288 | } | ||
289 | for (pl = t->u.ae.pl; pl != NULL && !res; pl = pl->next) { | ||
290 | for (l = 0; body[l] != NULL && !res; l++) { | ||
291 | /* loop through each header */ | ||
292 | void *data = NULL, *marker = NULL; | ||
293 | char *val; | ||
294 | |||
295 | parse_address(body[l], &data, &marker); | ||
296 | val = get_address(addrpart, &data, &marker, 0); | ||
297 | while (val != NULL && !res) { | ||
298 | /* loop through each address */ | ||
299 | res |= t->u.ae.comp(pl->p, val); | ||
300 | val = get_address(addrpart, &data, &marker, 0); | ||
301 | } | ||
302 | free_address(&data, &marker); | ||
303 | } | ||
304 | } | ||
305 | } | ||
306 | break; | ||
307 | case ANYOF: | ||
308 | res = 0; | ||
309 | for (tl = t->u.tl; tl != NULL && !res; tl = tl->next) { | ||
310 | res |= evaltest(i, tl->t, m); | ||
311 | } | ||
312 | break; | ||
313 | case ALLOF: | ||
314 | res = 1; | ||
315 | for (tl = t->u.tl; tl != NULL && res; tl = tl->next) { | ||
316 | res &= evaltest(i, tl->t, m); | ||
317 | } | ||
318 | break; | ||
319 | case EXISTS: | ||
320 | res = 1; | ||
321 | for (sl = t->u.sl; sl != NULL && res; sl = sl->next) { | ||
322 | const char **headbody = NULL; | ||
323 | res &= (i->getheader(m, sl->s, &headbody) == SIEVE_OK); | ||
324 | } | ||
325 | break; | ||
326 | case SFALSE: | ||
327 | res = 0; | ||
328 | break; | ||
329 | case STRUE: | ||
330 | res = 1; | ||
331 | break; | ||
332 | case HEADER: | ||
333 | res = 0; | ||
334 | for (sl = t->u.h.sl; sl != NULL && !res; sl = sl->next) { | ||
335 | const char **val; | ||
336 | int l; | ||
337 | if (i->getheader(m, sl->s, &val) != SIEVE_OK) | ||
338 | continue; | ||
339 | for (pl = t->u.h.pl; pl != NULL && !res; pl = pl->next) { | ||
340 | for (l = 0; val[l] != NULL && !res; l++) { | ||
341 | res |= t->u.h.comp(pl->p, val[l]); | ||
342 | } | ||
343 | } | ||
344 | } | ||
345 | break; | ||
346 | case NOT: | ||
347 | res = !evaltest(i, t->u.t, m); | ||
348 | break; | ||
349 | case SIZE: | ||
350 | { | ||
351 | int sz; | ||
352 | |||
353 | if (i->getsize(m, &sz) != SIEVE_OK) | ||
354 | break; | ||
355 | |||
356 | if (t->u.sz.t == OVER) { | ||
357 | res = (sz > t->u.sz.n); | ||
358 | } else { /* UNDER */ | ||
359 | res = (sz < t->u.sz.n); | ||
360 | } | ||
361 | break; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | return res; | ||
366 | } | ||
367 | |||
368 | /* evaluate the script c. returns negative if error was encountered, | ||
369 | 0 if it exited off the end, or positive if a stop action was encountered. | ||
370 | |||
371 | note that this is very stack hungry; we just evaluate the AST in | ||
372 | the naivest way. if we implement some sort of depth limit, we'll | ||
373 | be ok here; otherwise we'd want to transform it a little smarter */ | ||
374 | static int eval(sieve_interp_t *i, commandlist_t *c, | ||
375 | void *m, action_list_t *actions, notify_action_t *notify_action, | ||
376 | const char **errmsg) | ||
377 | { | ||
378 | int res = 0; | ||
379 | stringlist_t *sl; | ||
380 | |||
381 | while (c != NULL) { | ||
382 | switch (c->type) { | ||
383 | case IF: | ||
384 | if (evaltest(i, c->u.i.t, m)) | ||
385 | res = eval(i, c->u.i.do_then, m, actions, notify_action, errmsg); | ||
386 | else | ||
387 | res = eval(i, c->u.i.do_else, m, actions, notify_action, errmsg); | ||
388 | break; | ||
389 | case REJCT: | ||
390 | res = do_reject(actions, c->u.str); | ||
391 | if (res == SIEVE_RUN_ERROR) | ||
392 | *errmsg = "Reject can not be used with any other action"; | ||
393 | break; | ||
394 | case FILEINTO: | ||
395 | for (sl = c->u.sl; res == 0 && sl != NULL; sl = sl->next) { | ||
396 | res = do_fileinto(actions, sl->s, &i->curflags); | ||
397 | if (res == SIEVE_RUN_ERROR) | ||
398 | *errmsg = "Fileinto can not be used with Reject"; | ||
399 | |||
400 | } | ||
401 | break; | ||
402 | case FORWARD: | ||
403 | for (sl = c->u.sl; res == 0 && sl != NULL; sl = sl->next) { | ||
404 | res = do_forward(actions, sl->s); | ||
405 | if (res == SIEVE_RUN_ERROR) | ||
406 | *errmsg = "Redirect can not be used with Reject"; | ||
407 | } | ||
408 | break; | ||
409 | case KEEP: | ||
410 | res = do_keep(actions, &i->curflags); | ||
411 | if (res == SIEVE_RUN_ERROR) | ||
412 | *errmsg = "Keep can not be used with Reject"; | ||
413 | |||
414 | break; | ||
415 | case VACATION: | ||
416 | { | ||
417 | const char **body; | ||
418 | char buf[128], *fromaddr; | ||
419 | char *myaddr = NULL; | ||
420 | char *reply_to = NULL; | ||
421 | int l = SIEVE_OK; | ||
422 | void *data = NULL, *marker = NULL; | ||
423 | char *tmp; | ||
424 | |||
425 | /* is there an Auto-Submitted keyword other than "no"? */ | ||
426 | strcpy(buf, "auto-submitted"); | ||
427 | if (i->getheader(m, buf, &body) == SIEVE_OK) { | ||
428 | /* we don't deal with comments, etc. here */ | ||
429 | /* skip leading white-space */ | ||
430 | while (*body[0] && isspace((int) *body[0])) body[0]++; | ||
431 | if (strcasecmp(body[0], "no")) l = SIEVE_DONE; | ||
432 | } | ||
433 | |||
434 | /* Note: the domain-part of all addresses are canonicalized */ | ||
435 | |||
436 | /* grab my address from the envelope */ | ||
437 | if (l == SIEVE_OK) { | ||
438 | strcpy(buf, "to"); | ||
439 | l = i->getenvelope(m, buf, &body); | ||
440 | if (body[0]) { | ||
441 | parse_address(body[0], &data, &marker); | ||
442 | tmp = get_address(ADDRESS_ALL, &data, &marker, 1); | ||
443 | myaddr = (tmp != NULL) ? xstrdup(tmp) : NULL; | ||
444 | free_address(&data, &marker); | ||
445 | } | ||
446 | } | ||
447 | if (l == SIEVE_OK) { | ||
448 | strcpy(buf, "from"); | ||
449 | l = i->getenvelope(m, buf, &body); | ||
450 | } | ||
451 | if (l == SIEVE_OK && body[0]) { | ||
452 | /* we have to parse this address & decide whether we | ||
453 | want to respond to it */ | ||
454 | parse_address(body[0], &data, &marker); | ||
455 | tmp = get_address(ADDRESS_ALL, &data, &marker, 1); | ||
456 | reply_to = (tmp != NULL) ? xstrdup(tmp) : NULL; | ||
457 | free_address(&data, &marker); | ||
458 | |||
459 | /* first, is there a reply-to address? */ | ||
460 | if (reply_to == NULL) { | ||
461 | l = SIEVE_DONE; | ||
462 | } | ||
463 | |||
464 | /* first, is it from me? */ | ||
465 | if (l == SIEVE_OK && !strcmp(myaddr, reply_to)) { | ||
466 | l = SIEVE_DONE; | ||
467 | } | ||
468 | |||
469 | /* ok, is it any of the other addresses i've | ||
470 | specified? */ | ||
471 | if (l == SIEVE_OK) | ||
472 | for (sl = c->u.v.addresses; sl != NULL; sl = sl->next) | ||
473 | if (!strcmp(sl->s, reply_to)) | ||
474 | l = SIEVE_DONE; | ||
475 | |||
476 | /* ok, is it a system address? */ | ||
477 | if (l == SIEVE_OK && sysaddr(reply_to)) { | ||
478 | l = SIEVE_DONE; | ||
479 | } | ||
480 | } | ||
481 | |||
482 | if (l == SIEVE_OK) { | ||
483 | int found = 0; | ||
484 | |||
485 | /* ok, we're willing to respond to the sender. | ||
486 | but is this message to me? that is, is my address | ||
487 | in the TO, CC or BCC fields? */ | ||
488 | if (strcpy(buf, "to"), | ||
489 | i->getheader(m, buf, &body) == SIEVE_OK) | ||
490 | found = look_for_me(myaddr, c->u.v.addresses, body); | ||
491 | |||
492 | if (!found && (strcpy(buf, "cc"), | ||
493 | (i->getheader(m, buf, &body) == SIEVE_OK))) | ||
494 | found = look_for_me(myaddr, c->u.v.addresses, body); | ||
495 | |||
496 | if (!found && (strcpy(buf, "bcc"), | ||
497 | (i->getheader(m, buf, &body) == SIEVE_OK))) | ||
498 | found = look_for_me(myaddr, c->u.v.addresses, body); | ||
499 | |||
500 | if (!found) | ||
501 | l = SIEVE_DONE; | ||
502 | } | ||
503 | |||
504 | if (l == SIEVE_OK) { | ||
505 | /* ok, ok, if we got here maybe we should reply */ | ||
506 | |||
507 | if (c->u.v.subject == NULL) { | ||
508 | /* we have to generate a subject */ | ||
509 | const char **s; | ||
510 | |||
511 | strcpy(buf, "subject"); | ||
512 | if (i->getheader(m, buf, &s) != SIEVE_OK || | ||
513 | s[0] == NULL) { | ||
514 | strcpy(buf, "Automated reply"); | ||
515 | } else { | ||
516 | /* s[0] contains the original subject */ | ||
517 | while (!strncasecmp(s[0], "Re: ", 4)) { | ||
518 | s[0] += 4; | ||
519 | } | ||
520 | snprintf(buf, sizeof(buf), "Re: %s", s[0]); | ||
521 | } | ||
522 | } else { | ||
523 | /* user specified subject */ | ||
524 | strncpy(buf, c->u.v.subject, sizeof(buf)); | ||
525 | } | ||
526 | |||
527 | /* who do we want the message coming from? */ | ||
528 | if (c->u.v.addresses) { | ||
529 | fromaddr = c->u.v.addresses->s; | ||
530 | } else { | ||
531 | fromaddr = myaddr; | ||
532 | } | ||
533 | |||
534 | res = do_vacation(actions, reply_to, strdup(fromaddr), | ||
535 | strdup(buf), | ||
536 | c->u.v.message, c->u.v.days, c->u.v.mime); | ||
537 | |||
538 | if (res == SIEVE_RUN_ERROR) | ||
539 | *errmsg = "Vacation can not be used with Reject or Vacation"; | ||
540 | |||
541 | } else { | ||
542 | if (l != SIEVE_DONE) res = -1; /* something went wrong */ | ||
543 | } | ||
544 | if (myaddr) free(myaddr); | ||
545 | break; | ||
546 | } | ||
547 | case STOP: | ||
548 | res = 1; | ||
549 | break; | ||
550 | case DISCARD: | ||
551 | res = do_discard(actions); | ||
552 | break; | ||
553 | case SETFLAG: | ||
554 | sl = c->u.sl; | ||
555 | res = do_setflag(actions, sl->s); | ||
556 | for (sl = sl->next; res == 0 && sl != NULL; sl = sl->next) { | ||
557 | res = do_addflag(actions, sl->s); | ||
558 | } | ||
559 | if (res == SIEVE_RUN_ERROR) | ||
560 | *errmsg = "Setflag can not be used with Reject"; | ||
561 | break; | ||
562 | case ADDFLAG: | ||
563 | for (sl = c->u.sl; res == 0 && sl != NULL; sl = sl->next) { | ||
564 | res = do_addflag(actions, sl->s); | ||
565 | } | ||
566 | if (res == SIEVE_RUN_ERROR) | ||
567 | *errmsg = "Addflag can not be used with Reject"; | ||
568 | break; | ||
569 | case REMOVEFLAG: | ||
570 | for (sl = c->u.sl; res == 0 && sl != NULL; sl = sl->next) { | ||
571 | res = do_removeflag(actions, sl->s); | ||
572 | } | ||
573 | if (res == SIEVE_RUN_ERROR) | ||
574 | *errmsg = "Removeflag can not be used with Reject"; | ||
575 | break; | ||
576 | case MARK: | ||
577 | res = do_mark(actions); | ||
578 | if (res == SIEVE_RUN_ERROR) | ||
579 | *errmsg = "Mark can not be used with Reject"; | ||
580 | break; | ||
581 | case UNMARK: | ||
582 | res = do_unmark(actions); | ||
583 | if (res == SIEVE_RUN_ERROR) | ||
584 | *errmsg = "Unmark can not be used with Reject"; | ||
585 | break; | ||
586 | case NOTIFY: | ||
587 | res = do_notify(i,m,notify_action, c->u.n.priority, c->u.n.message, | ||
588 | c->u.n.headers_list); | ||
589 | break; | ||
590 | case DENOTIFY: | ||
591 | res = do_denotify(notify_action); | ||
592 | break; | ||
593 | |||
594 | } | ||
595 | |||
596 | if (res) /* we've either encountered an error or a stop */ | ||
597 | break; | ||
598 | |||
599 | /* execute next command */ | ||
600 | c = c->next; | ||
601 | } | ||
602 | |||
603 | return res; | ||
604 | } | ||
605 | |||
606 | #define GROW_AMOUNT 100 | ||
607 | |||
608 | static void add_header(sieve_interp_t *i, char *header, | ||
609 | void *message_context, char **out, | ||
610 | int *outlen, int *outalloc) | ||
611 | { | ||
612 | const char **h; | ||
613 | int addlen; | ||
614 | /* get header value */ | ||
615 | i->getheader(message_context, header, &h); | ||
616 | |||
617 | if (!h || !h[0]) | ||
618 | return; | ||
619 | |||
620 | addlen = strlen(header) + 2 + strlen(h[0]) + 1; | ||
621 | |||
622 | /* realloc if necessary */ | ||
623 | if ( (*outlen) + addlen >= *outalloc) | ||
624 | { | ||
625 | *outalloc = (*outlen) + addlen + GROW_AMOUNT; | ||
626 | *out = xrealloc(*out, *outalloc); | ||
627 | } | ||
628 | |||
629 | /* add header name and value */ | ||
630 | strcat(*out,header); | ||
631 | strcat(*out,": "); | ||
632 | strcat(*out,h[0]); | ||
633 | strcat(*out,"\n"); | ||
634 | |||
635 | *outlen += addlen; | ||
636 | } | ||
637 | |||
638 | static int fillin_headers(sieve_interp_t *i, stringlist_t *sl, | ||
639 | void *message_context, char **out, int *outlen) | ||
640 | { | ||
641 | int allocsize = GROW_AMOUNT; | ||
642 | *out = xmalloc(GROW_AMOUNT); | ||
643 | *outlen = 0; | ||
644 | |||
645 | (*out)[0]='\0'; | ||
646 | |||
647 | if (sl == NULL) | ||
648 | { | ||
649 | add_header(i,"To", message_context, out, outlen, &allocsize); | ||
650 | add_header(i,"From", message_context, out, outlen, &allocsize); | ||
651 | add_header(i,"Subject", message_context, out, outlen, &allocsize); | ||
652 | } else { | ||
653 | |||
654 | while (sl!=NULL) | ||
655 | { | ||
656 | add_header(i,sl->s,message_context, out, outlen, &allocsize); | ||
657 | |||
658 | sl=sl->next; | ||
659 | } | ||
660 | } | ||
661 | |||
662 | return SIEVE_OK; | ||
663 | } | ||
664 | |||
665 | static int sieve_addflag(sieve_imapflags_t *imapflags, char *flag) | ||
666 | { | ||
667 | int n; | ||
668 | |||
669 | /* search for flag already in list */ | ||
670 | for (n = 0; n < imapflags->nflags; n++) { | ||
671 | if (!strcmp(imapflags->flag[n], flag)) | ||
672 | break; | ||
673 | } | ||
674 | |||
675 | /* add flag to list, iff not in list */ | ||
676 | if (n == imapflags->nflags) { | ||
677 | imapflags->nflags++; | ||
678 | imapflags->flag = | ||
679 | (char **) xrealloc((char *)imapflags->flag, | ||
680 | imapflags->nflags*sizeof(char *)); | ||
681 | imapflags->flag[imapflags->nflags-1] = strdup(flag); | ||
682 | } | ||
683 | |||
684 | return SIEVE_OK; | ||
685 | } | ||
686 | |||
687 | static int sieve_removeflag(sieve_imapflags_t *imapflags, char *flag) | ||
688 | { | ||
689 | int n; | ||
690 | |||
691 | /* search for flag already in list */ | ||
692 | for (n = 0; n < imapflags->nflags; n++) { | ||
693 | if (!strcmp(imapflags->flag[n], flag)) | ||
694 | break; | ||
695 | } | ||
696 | |||
697 | /* remove flag from list, iff in list */ | ||
698 | if (n < imapflags->nflags) { | ||
699 | free(imapflags->flag[n]); | ||
700 | imapflags->nflags--; | ||
701 | |||
702 | for (; n < imapflags->nflags; n++) | ||
703 | imapflags->flag[n] = imapflags->flag[n+1]; | ||
704 | |||
705 | imapflags->flag = | ||
706 | (char **) xrealloc((char *)imapflags->flag, | ||
707 | imapflags->nflags*sizeof(char *)); | ||
708 | } | ||
709 | |||
710 | return SIEVE_OK; | ||
711 | } | ||
712 | |||
713 | static int send_notify_callback(sieve_script_t *s, void *message_context, | ||
714 | notify_action_t *notify, char *actions_string, | ||
715 | const char **errmsg) | ||
716 | { | ||
717 | char *headers; | ||
718 | int headerslen; | ||
719 | int ret; | ||
720 | |||
721 | sieve_notify_context_t nc; | ||
722 | |||
723 | fillin_headers(&(s->interp), notify->headers, message_context, | ||
724 | &headers, &headerslen); | ||
725 | |||
726 | nc.message = xmalloc(strlen(notify->message) + headerslen + | ||
727 | strlen(actions_string) + 30); | ||
728 | |||
729 | strcpy(nc.message,notify->message); | ||
730 | strcat(nc.message,"\n\n"); | ||
731 | |||
732 | strcat(nc.message,headers); | ||
733 | strcat(nc.message,"\n"); | ||
734 | free(headers); | ||
735 | |||
736 | strcat(nc.message,actions_string); | ||
737 | nc.priority = notify->priority; | ||
738 | |||
739 | ret = s->interp.notify(&nc, | ||
740 | s->interp.interp_context, | ||
741 | s->script_context, | ||
742 | message_context, | ||
743 | errmsg); | ||
744 | |||
745 | free(nc.message); | ||
746 | |||
747 | return ret; | ||
748 | } | ||
749 | |||
750 | static char *action_to_string(action_t action) | ||
751 | { | ||
752 | switch(action) | ||
753 | { | ||
754 | case ACTION_REJECT: return "Reject"; | ||
755 | case ACTION_FILEINTO: return "Fileinto"; | ||
756 | case ACTION_KEEP: return "Keep"; | ||
757 | case ACTION_REDIRECT: return "Redirect"; | ||
758 | case ACTION_DISCARD: return "Discard"; | ||
759 | case ACTION_VACATION: return "Vacation"; | ||
760 | case ACTION_SETFLAG: return "Setflag"; | ||
761 | case ACTION_ADDFLAG: return "Addflag"; | ||
762 | case ACTION_REMOVEFLAG: return "Removeflag"; | ||
763 | case ACTION_MARK: return "Mark"; | ||
764 | case ACTION_UNMARK: return "Unmark"; | ||
765 | case ACTION_NOTIFY: return "Notify"; | ||
766 | case ACTION_DENOTIFY: return "Denotify"; | ||
767 | default: return "Unknown"; | ||
768 | } | ||
769 | |||
770 | return "Error!"; | ||
771 | } | ||
772 | |||
773 | static char *sieve_errstr(int code) | ||
774 | { | ||
775 | switch (code) | ||
776 | { | ||
777 | case SIEVE_FAIL: return "Generic Error"; | ||
778 | case SIEVE_NOT_FINALIZED: return "Sieve not finalized"; | ||
779 | case SIEVE_PARSE_ERROR: return "Parse error"; | ||
780 | case SIEVE_RUN_ERROR: return "Run error"; | ||
781 | case SIEVE_INTERNAL_ERROR: return "Internal Error"; | ||
782 | case SIEVE_NOMEM: return "No memory"; | ||
783 | default: return "Unknown error"; | ||
784 | } | ||
785 | |||
786 | return "Error!"; | ||
787 | } | ||
788 | |||
789 | #define HASHSIZE 16 | ||
790 | |||
791 | static int makehash(unsigned char hash[HASHSIZE], char *s1, char *s2) | ||
792 | { | ||
793 | MD5_CTX ctx; | ||
794 | |||
795 | MD5Init(&ctx); | ||
796 | MD5Update(&ctx, (unsigned char*) s1, strlen(s1)); | ||
797 | MD5Update(&ctx, (unsigned char*) s2, strlen(s2)); | ||
798 | MD5Final(hash, &ctx); | ||
799 | |||
800 | return SIEVE_OK; | ||
801 | } | ||
802 | |||
803 | /* execute a script on a message, producing side effects via callbacks. | ||
804 | it is the responsibility of the caller to save a message if this | ||
805 | returns anything but SIEVE_OK. */ | ||
806 | int sieve_execute_script(sieve_script_t *s, void *message_context) | ||
807 | { | ||
808 | int ret = 0; | ||
809 | int implicit_keep = 0; | ||
810 | action_list_t *actions = NULL, *a; | ||
811 | action_t lastaction = -1; | ||
812 | notify_action_t *notify_action; | ||
813 | char actions_string[4096] = ""; | ||
814 | const char *errmsg = NULL; | ||
815 | |||
816 | notify_action = default_notify_action(); | ||
817 | if (notify_action == NULL) | ||
818 | return SIEVE_NOMEM; | ||
819 | |||
820 | actions = new_action_list(); | ||
821 | if (actions == NULL) { | ||
822 | ret = SIEVE_NOMEM; | ||
823 | goto error; | ||
824 | } | ||
825 | |||
826 | if (eval(&s->interp, s->cmds, message_context, actions, | ||
827 | notify_action, &errmsg) < 0) | ||
828 | return SIEVE_RUN_ERROR; | ||
829 | |||
830 | strcpy(actions_string,"Action(s) taken:\n"); | ||
831 | |||
832 | /* now perform actions attached to m */ | ||
833 | a = actions; | ||
834 | implicit_keep = 1; | ||
835 | while (a != NULL) { | ||
836 | lastaction = a->a; | ||
837 | errmsg = NULL; | ||
838 | |||
839 | switch (a->a) { | ||
840 | case ACTION_REJECT: | ||
841 | implicit_keep = 0; | ||
842 | if (!s->interp.reject) | ||
843 | return SIEVE_INTERNAL_ERROR; | ||
844 | ret = s->interp.reject(&a->u.rej, | ||
845 | s->interp.interp_context, | ||
846 | s->script_context, | ||
847 | message_context, | ||
848 | &errmsg); | ||
849 | |||
850 | if (ret == SIEVE_OK) | ||
851 | snprintf(actions_string+strlen(actions_string), | ||
852 | sizeof(actions_string)-strlen(actions_string), | ||
853 | "Rejected with: %s\n", a->u.rej.msg); | ||
854 | |||
855 | break; | ||
856 | case ACTION_FILEINTO: | ||
857 | implicit_keep = 0; | ||
858 | if (!s->interp.fileinto) | ||
859 | return SIEVE_INTERNAL_ERROR; | ||
860 | ret = s->interp.fileinto(&a->u.fil, | ||
861 | s->interp.interp_context, | ||
862 | s->script_context, | ||
863 | message_context, | ||
864 | &errmsg); | ||
865 | |||
866 | if (ret == SIEVE_OK) | ||
867 | snprintf(actions_string+strlen(actions_string), | ||
868 | sizeof(actions_string)-strlen(actions_string), | ||
869 | "Filed into: %s\n",a->u.fil.mailbox); | ||
870 | break; | ||
871 | case ACTION_KEEP: | ||
872 | implicit_keep = 0; | ||
873 | if (!s->interp.keep) | ||
874 | return SIEVE_INTERNAL_ERROR; | ||
875 | ret = s->interp.keep(&a->u.keep, | ||
876 | s->interp.interp_context, | ||
877 | s->script_context, | ||
878 | message_context, | ||
879 | &errmsg); | ||
880 | if (ret == SIEVE_OK) | ||
881 | snprintf(actions_string+strlen(actions_string), | ||
882 | sizeof(actions_string)-strlen(actions_string), | ||
883 | "Kept\n"); | ||
884 | break; | ||
885 | case ACTION_REDIRECT: | ||
886 | implicit_keep = 0; | ||
887 | if (!s->interp.redirect) | ||
888 | return SIEVE_INTERNAL_ERROR; | ||
889 | ret = s->interp.redirect(&a->u.red, | ||
890 | s->interp.interp_context, | ||
891 | s->script_context, | ||
892 | message_context, | ||
893 | &errmsg); | ||
894 | if (ret == SIEVE_OK) | ||
895 | snprintf(actions_string+strlen(actions_string), | ||
896 | sizeof(actions_string)-strlen(actions_string), | ||
897 | "Redirected to %s\n", a->u.red.addr); | ||
898 | break; | ||
899 | case ACTION_DISCARD: | ||
900 | implicit_keep = 0; | ||
901 | if (s->interp.discard) /* discard is optional */ | ||
902 | ret = s->interp.discard(NULL, s->interp.interp_context, | ||
903 | s->script_context, | ||
904 | message_context, | ||
905 | &errmsg); | ||
906 | if (ret == SIEVE_OK) | ||
907 | snprintf(actions_string+strlen(actions_string), | ||
908 | sizeof(actions_string)-strlen(actions_string), | ||
909 | "Discarded\n"); | ||
910 | break; | ||
911 | |||
912 | case ACTION_VACATION: | ||
913 | { | ||
914 | unsigned char hash[HASHSIZE]; | ||
915 | |||
916 | if (!s->interp.vacation) | ||
917 | return SIEVE_INTERNAL_ERROR; | ||
918 | |||
919 | /* first, let's figure out if we should respond to this */ | ||
920 | ret = makehash(hash, a->u.vac.send.addr, | ||
921 | a->u.vac.send.msg); | ||
922 | if (ret == SIEVE_OK) { | ||
923 | a->u.vac.autoresp.hash = hash; | ||
924 | a->u.vac.autoresp.len = HASHSIZE; | ||
925 | ret = s->interp.vacation->autorespond(&a->u.vac.autoresp, | ||
926 | s->interp.interp_context, | ||
927 | s->script_context, | ||
928 | message_context, | ||
929 | &errmsg); | ||
930 | } | ||
931 | if (ret == SIEVE_OK) { | ||
932 | /* send the response */ | ||
933 | ret = s->interp.vacation->send_response(&a->u.vac.send, | ||
934 | s->interp.interp_context, | ||
935 | s->script_context, | ||
936 | message_context, | ||
937 | &errmsg); | ||
938 | |||
939 | if (ret == SIEVE_OK) | ||
940 | snprintf(actions_string+strlen(actions_string), | ||
941 | sizeof(actions_string)-strlen(actions_string), | ||
942 | "Sent vacation reply\n"); | ||
943 | |||
944 | } else if (ret == SIEVE_DONE) { | ||
945 | snprintf(actions_string+strlen(actions_string), | ||
946 | sizeof(actions_string)-strlen(actions_string), | ||
947 | "Vacation reply suppressed\n"); | ||
948 | |||
949 | ret = SIEVE_OK; | ||
950 | } | ||
951 | |||
952 | break; | ||
953 | } | ||
954 | |||
955 | |||
956 | case ACTION_SETFLAG: | ||
957 | free_imapflags(&s->interp.curflags); | ||
958 | ret = sieve_addflag(&s->interp.curflags, a->u.fla.flag); | ||
959 | break; | ||
960 | case ACTION_ADDFLAG: | ||
961 | ret = sieve_addflag(&s->interp.curflags, a->u.fla.flag); | ||
962 | break; | ||
963 | case ACTION_REMOVEFLAG: | ||
964 | ret = sieve_removeflag(&s->interp.curflags, a->u.fla.flag); | ||
965 | break; | ||
966 | case ACTION_MARK: | ||
967 | { | ||
968 | int n = s->interp.markflags->nflags; | ||
969 | |||
970 | ret = SIEVE_OK; | ||
971 | while (n && ret == SIEVE_OK) { | ||
972 | ret = sieve_addflag(&s->interp.curflags, | ||
973 | s->interp.markflags->flag[--n]); | ||
974 | } | ||
975 | break; | ||
976 | } | ||
977 | case ACTION_UNMARK: | ||
978 | { | ||
979 | int n = s->interp.markflags->nflags; | ||
980 | |||
981 | ret = SIEVE_OK; | ||
982 | while (n && ret == SIEVE_OK) { | ||
983 | ret = sieve_removeflag(&s->interp.curflags, | ||
984 | s->interp.markflags->flag[--n]); | ||
985 | } | ||
986 | break; | ||
987 | } | ||
988 | |||
989 | case ACTION_NONE: | ||
990 | break; | ||
991 | |||
992 | default: | ||
993 | ret = SIEVE_INTERNAL_ERROR; | ||
994 | break; | ||
995 | } | ||
996 | |||
997 | a = a->next; | ||
998 | |||
999 | if (ret != SIEVE_OK) { | ||
1000 | /* uh oh! better bail! */ | ||
1001 | break; | ||
1002 | } | ||
1003 | } | ||
1004 | |||
1005 | error: /* report run-time errors */ | ||
1006 | |||
1007 | if (ret != SIEVE_OK) { | ||
1008 | if (lastaction == -1) /* we never executed an action */ | ||
1009 | snprintf(actions_string+strlen(actions_string), | ||
1010 | sizeof(actions_string)-strlen(actions_string), | ||
1011 | "script execution failed: %s\n", | ||
1012 | errmsg ? errmsg : sieve_errstr(ret)); | ||
1013 | else | ||
1014 | snprintf(actions_string+strlen(actions_string), | ||
1015 | sizeof(actions_string)-strlen(actions_string), | ||
1016 | "%s action failed: %s\n", | ||
1017 | action_to_string(lastaction), | ||
1018 | errmsg ? errmsg : sieve_errstr(ret)); | ||
1019 | } | ||
1020 | |||
1021 | /* Process notify action if there is one */ | ||
1022 | if (s->interp.notify && notify_action->exists) { | ||
1023 | ret |= send_notify_callback(s, message_context, notify_action, | ||
1024 | actions_string, &errmsg); | ||
1025 | } | ||
1026 | |||
1027 | if ((ret != SIEVE_OK) && s->interp.err) { | ||
1028 | char buf[1024]; | ||
1029 | if (lastaction == -1) /* we never executed an action */ | ||
1030 | sprintf(buf, "%s", errmsg ? errmsg : sieve_errstr(ret)); | ||
1031 | else | ||
1032 | sprintf(buf, "%s: %s", action_to_string(lastaction), | ||
1033 | errmsg ? errmsg : sieve_errstr(ret)); | ||
1034 | |||
1035 | ret |= s->interp.execute_err(buf, s->interp.interp_context, | ||
1036 | s->script_context, message_context); | ||
1037 | } | ||
1038 | |||
1039 | if (implicit_keep) { | ||
1040 | sieve_keep_context_t keep_context; | ||
1041 | int keep_ret; | ||
1042 | |||
1043 | keep_context.imapflags = &s->interp.curflags; | ||
1044 | |||
1045 | lastaction = ACTION_KEEP; | ||
1046 | keep_ret = s->interp.keep(&keep_context, s->interp.interp_context, | ||
1047 | s->script_context, message_context, &errmsg); | ||
1048 | ret |= keep_ret; | ||
1049 | if (keep_ret == SIEVE_OK) | ||
1050 | snprintf(actions_string+strlen(actions_string), | ||
1051 | sizeof(actions_string)-strlen(actions_string), | ||
1052 | "Kept\n"); | ||
1053 | else { | ||
1054 | implicit_keep = 0; /* don't try an implicit keep again */ | ||
1055 | goto error; /* process the implicit keep error */ | ||
1056 | } | ||
1057 | } | ||
1058 | |||
1059 | if (actions) | ||
1060 | free_action_list(actions); | ||
1061 | |||
1062 | if(s->interp.summary) | ||
1063 | s->interp.summary( | ||
1064 | actions_string, | ||
1065 | s->interp.interp_context, | ||
1066 | s->script_context, | ||
1067 | message_context | ||
1068 | ); | ||
1069 | |||
1070 | return ret; | ||
1071 | } | ||
1072 |
sieve/script.h
0 → 100644
1 | /* script.h -- script definition | ||
2 | * Larry Greenfield | ||
3 | * $Id$ | ||
4 | */ | ||
5 | /*********************************************************** | ||
6 | Copyright 1999 by Carnegie Mellon University | ||
7 | |||
8 | All Rights Reserved | ||
9 | |||
10 | Permission to use, copy, modify, and distribute this software and its | ||
11 | documentation for any purpose and without fee is hereby granted, | ||
12 | provided that the above copyright notice appear in all copies and that | ||
13 | both that copyright notice and this permission notice appear in | ||
14 | supporting documentation, and that the name of Carnegie Mellon | ||
15 | University not be used in advertising or publicity pertaining to | ||
16 | distribution of the software without specific, written prior | ||
17 | permission. | ||
18 | |||
19 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
20 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
21 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
22 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
23 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
24 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
25 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
26 | ******************************************************************/ | ||
27 | |||
28 | #ifndef SIEVE_SCRIPT_H | ||
29 | #define SIEVE_SCRIPT_H | ||
30 | |||
31 | #include "sieve_interface.h" | ||
32 | #include "interp.h" | ||
33 | #include "tree.h" | ||
34 | |||
35 | struct sieve_script { | ||
36 | sieve_interp_t interp; | ||
37 | |||
38 | /* was a "require" done for these? */ | ||
39 | struct sieve_support { | ||
40 | int fileinto : 1; | ||
41 | int reject : 1; | ||
42 | int envelope : 1; | ||
43 | int vacation : 1; | ||
44 | int imapflags : 1; | ||
45 | int notify : 1; | ||
46 | int regex : 1; | ||
47 | int subaddress: 1; | ||
48 | } support; | ||
49 | |||
50 | void *script_context; | ||
51 | commandlist_t *cmds; | ||
52 | |||
53 | int err; | ||
54 | }; | ||
55 | |||
56 | /* generated by the yacc script */ | ||
57 | commandlist_t *sieve_parse(sieve_script_t *interp, FILE *f); | ||
58 | int script_require(sieve_script_t *s, char *req); | ||
59 | |||
60 | #endif |
sieve/sieve-gram.y
0 → 100644
1 | %{ | ||
2 | /* sieve.y -- sieve parser | ||
3 | * Larry Greenfield | ||
4 | * $Id$ | ||
5 | */ | ||
6 | /*********************************************************** | ||
7 | Copyright 1999 by Carnegie Mellon University | ||
8 | |||
9 | All Rights Reserved | ||
10 | |||
11 | Permission to use, copy, modify, and distribute this software and its | ||
12 | documentation for any purpose and without fee is hereby granted, | ||
13 | provided that the above copyright notice appear in all copies and that | ||
14 | both that copyright notice and this permission notice appear in | ||
15 | supporting documentation, and that the name of Carnegie Mellon | ||
16 | University not be used in advertising or publicity pertaining to | ||
17 | distribution of the software without specific, written prior | ||
18 | permission. | ||
19 | |||
20 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
21 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
22 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
23 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
24 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
25 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
26 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
27 | ******************************************************************/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include <config.h> | ||
31 | #endif | ||
32 | |||
33 | #include <stdlib.h> | ||
34 | #include <assert.h> | ||
35 | #include <string.h> | ||
36 | #include "xmalloc.h" | ||
37 | #include "comparator.h" | ||
38 | #include "interp.h" | ||
39 | #include "script.h" | ||
40 | #include "tree.h" | ||
41 | |||
42 | #include "util.h" | ||
43 | #include "imparse.h" | ||
44 | |||
45 | /* definitions */ | ||
46 | extern int addrparse(void); | ||
47 | |||
48 | struct vtags { | ||
49 | int days; | ||
50 | stringlist_t *addresses; | ||
51 | char *subject; | ||
52 | int mime; | ||
53 | }; | ||
54 | |||
55 | struct htags { | ||
56 | char *comparator; | ||
57 | int comptag; | ||
58 | }; | ||
59 | |||
60 | struct aetags { | ||
61 | int addrtag; | ||
62 | char *comparator; | ||
63 | int comptag; | ||
64 | }; | ||
65 | |||
66 | static commandlist_t *ret; | ||
67 | static sieve_script_t *parse_script; | ||
68 | static int check_reqs(stringlist_t *sl); | ||
69 | static test_t *build_address(int t, struct aetags *ae, | ||
70 | stringlist_t *sl, patternlist_t *pl); | ||
71 | static test_t *build_header(int t, struct htags *h, | ||
72 | stringlist_t *sl, patternlist_t *pl); | ||
73 | static commandlist_t *build_vacation(int t, struct vtags *h, char *s); | ||
74 | static struct aetags *new_aetags(void); | ||
75 | static struct aetags *canon_aetags(struct aetags *ae); | ||
76 | static void free_aetags(struct aetags *ae); | ||
77 | static struct htags *new_htags(void); | ||
78 | static struct htags *canon_htags(struct htags *h); | ||
79 | static void free_htags(struct htags *h); | ||
80 | static struct vtags *new_vtags(void); | ||
81 | static struct vtags *canon_vtags(struct vtags *v); | ||
82 | static void free_vtags(struct vtags *v); | ||
83 | |||
84 | static int verify_mailboxes(stringlist_t *sl); | ||
85 | static int verify_addresses(stringlist_t *sl); | ||
86 | static int verify_flags(stringlist_t *sl); | ||
87 | #ifdef ENABLE_REGEX | ||
88 | static patternlist_t *verify_regexs(stringlist_t *sl, char *comp); | ||
89 | #endif | ||
90 | static int ok_header(char *s); | ||
91 | |||
92 | int yyerror(char *msg); | ||
93 | extern int yylex(void); | ||
94 | |||
95 | #define YYERROR_VERBOSE /* i want better error messages! */ | ||
96 | %} | ||
97 | |||
98 | %union { | ||
99 | int nval; | ||
100 | char *sval; | ||
101 | stringlist_t *sl; | ||
102 | test_t *test; | ||
103 | testlist_t *testl; | ||
104 | commandlist_t *cl; | ||
105 | struct vtags *vtag; | ||
106 | struct aetags *aetag; | ||
107 | struct htags *htag; | ||
108 | } | ||
109 | |||
110 | %token <nval> NUMBER | ||
111 | %token <sval> STRING | ||
112 | %token IF ELSIF ELSE | ||
113 | %token REJCT FILEINTO FORWARD KEEP STOP DISCARD VACATION REQUIRE | ||
114 | %token SETFLAG ADDFLAG REMOVEFLAG MARK UNMARK | ||
115 | %token NOTIFY DENOTIFY | ||
116 | %token ANYOF ALLOF EXISTS SFALSE STRUE HEADER NOT SIZE ADDRESS ENVELOPE | ||
117 | %token COMPARATOR IS CONTAINS MATCHES REGEX OVER UNDER | ||
118 | %token ALL LOCALPART DOMAIN USER DETAIL | ||
119 | %token DAYS ADDRESSES SUBJECT MIME | ||
120 | %token LOW MEDIUM HIGH | ||
121 | |||
122 | %type <cl> commands command action elsif block | ||
123 | %type <sl> stringlist strings | ||
124 | %type <test> test | ||
125 | %type <nval> comptag sizetag addrparttag addrorenv | ||
126 | %type <testl> testlist tests | ||
127 | %type <htag> htags | ||
128 | %type <aetag> aetags | ||
129 | %type <vtag> vtags | ||
130 | %type <sl> optional_headers | ||
131 | %type <sval> priority | ||
132 | |||
133 | %% | ||
134 | |||
135 | start: /* empty */ { ret = NULL; } | ||
136 | | reqs { ret = NULL; } | ||
137 | | reqs commands { ret = $2; } | ||
138 | ; | ||
139 | |||
140 | reqs: /* empty */ | ||
141 | | require reqs | ||
142 | ; | ||
143 | |||
144 | require: REQUIRE stringlist ';' { if (!check_reqs($2)) { | ||
145 | yyerror("unsupported feature"); | ||
146 | YYERROR; | ||
147 | } } | ||
148 | ; | ||
149 | |||
150 | commands: command { $$ = $1; } | ||
151 | | command commands { $1->next = $2; $$ = $1; } | ||
152 | ; | ||
153 | |||
154 | command: action ';' { $$ = $1; } | ||
155 | | IF test block elsif { $$ = new_if($2, $3, $4); } | ||
156 | | error ';' { $$ = new_command(STOP); } | ||
157 | ; | ||
158 | |||
159 | elsif: /* empty */ { $$ = NULL; } | ||
160 | | ELSIF test block elsif { $$ = new_if($2, $3, $4); } | ||
161 | | ELSE block { $$ = $2; } | ||
162 | ; | ||
163 | |||
164 | action: REJCT STRING { if (!parse_script->support.reject) { | ||
165 | yyerror("reject not required"); | ||
166 | YYERROR; | ||
167 | } | ||
168 | $$ = new_command(REJCT); $$->u.str = $2; } | ||
169 | | FILEINTO stringlist { if (!parse_script->support.fileinto) { | ||
170 | yyerror("fileinto not required"); | ||
171 | YYERROR; | ||
172 | } | ||
173 | if (!verify_mailboxes($2)) { | ||
174 | YYERROR; /* vm should call yyerror() */ | ||
175 | } | ||
176 | $$ = new_command(FILEINTO); | ||
177 | $$->u.sl = $2; } | ||
178 | | FORWARD stringlist { $$ = new_command(FORWARD); | ||
179 | if (!verify_addresses($2)) { | ||
180 | YYERROR; /* va should call yyerror() */ | ||
181 | } | ||
182 | $$->u.sl = $2; } | ||
183 | | KEEP { $$ = new_command(KEEP); } | ||
184 | | STOP { $$ = new_command(STOP); } | ||
185 | | DISCARD { $$ = new_command(DISCARD); } | ||
186 | | VACATION vtags STRING { if (!parse_script->support.vacation) { | ||
187 | yyerror("vacation not required"); | ||
188 | $$ = new_command(VACATION); | ||
189 | YYERROR; | ||
190 | } else { | ||
191 | $$ = build_vacation(VACATION, | ||
192 | canon_vtags($2), $3); | ||
193 | } } | ||
194 | | SETFLAG stringlist { if (!parse_script->support.imapflags) { | ||
195 | yyerror("imapflags not required"); | ||
196 | YYERROR; | ||
197 | } | ||
198 | if (!verify_flags($2)) { | ||
199 | YYERROR; /* vf should call yyerror() */ | ||
200 | } | ||
201 | $$ = new_command(SETFLAG); | ||
202 | $$->u.sl = $2; } | ||
203 | | ADDFLAG stringlist { if (!parse_script->support.imapflags) { | ||
204 | yyerror("imapflags not required"); | ||
205 | YYERROR; | ||
206 | } | ||
207 | if (!verify_flags($2)) { | ||
208 | YYERROR; /* vf should call yyerror() */ | ||
209 | } | ||
210 | $$ = new_command(ADDFLAG); | ||
211 | $$->u.sl = $2; } | ||
212 | | REMOVEFLAG stringlist { if (!parse_script->support.imapflags) { | ||
213 | yyerror("imapflags not required"); | ||
214 | YYERROR; | ||
215 | } | ||
216 | if (!verify_flags($2)) { | ||
217 | YYERROR; /* vf should call yyerror() */ | ||
218 | } | ||
219 | $$ = new_command(REMOVEFLAG); | ||
220 | $$->u.sl = $2; } | ||
221 | | MARK { if (!parse_script->support.imapflags) { | ||
222 | yyerror("imapflags not required"); | ||
223 | YYERROR; | ||
224 | } | ||
225 | $$ = new_command(MARK); } | ||
226 | | UNMARK { if (!parse_script->support.imapflags) { | ||
227 | yyerror("imapflags not required"); | ||
228 | YYERROR; | ||
229 | } | ||
230 | $$ = new_command(UNMARK); } | ||
231 | |||
232 | | NOTIFY priority STRING optional_headers | ||
233 | { | ||
234 | if (!parse_script->support.notify) { | ||
235 | yyerror("notify not required"); | ||
236 | YYERROR; | ||
237 | } | ||
238 | |||
239 | $$ = new_command(NOTIFY); | ||
240 | $$->u.n.priority = $2; | ||
241 | $$->u.n.message = $3; | ||
242 | $$->u.n.headers_list = $4; | ||
243 | } | ||
244 | | DENOTIFY { if (!parse_script->support.notify) { | ||
245 | yyerror("notify not required"); | ||
246 | YYERROR; | ||
247 | } | ||
248 | $$ = new_command(DENOTIFY); } | ||
249 | |||
250 | ; | ||
251 | |||
252 | priority: /* nothing */ { $$ = "medium"; } | ||
253 | | LOW { $$ = "low"; } | ||
254 | | MEDIUM { $$ = "medium"; } | ||
255 | | HIGH { $$ = "high"; } | ||
256 | ; | ||
257 | |||
258 | optional_headers: /* empty */ { | ||
259 | $$ = NULL; | ||
260 | } | ||
261 | | stringlist { $$ = $1; } | ||
262 | ; | ||
263 | |||
264 | vtags: /* empty */ { $$ = new_vtags(); } | ||
265 | | vtags DAYS NUMBER { if ($$->days != -1) { | ||
266 | yyerror("duplicate :days"); YYERROR; } | ||
267 | else { $$->days = $3; } } | ||
268 | | vtags ADDRESSES stringlist { if ($$->addresses != NULL) { | ||
269 | yyerror("duplicate :addresses"); | ||
270 | YYERROR; | ||
271 | } else if (!verify_addresses($3)) { | ||
272 | YYERROR; | ||
273 | } else { | ||
274 | $$->addresses = $3; } } | ||
275 | | vtags SUBJECT STRING { if ($$->subject != NULL) { | ||
276 | yyerror("duplicate :subject"); | ||
277 | YYERROR; | ||
278 | } else if (!ok_header($3)) { | ||
279 | YYERROR; | ||
280 | } else { $$->subject = $3; } } | ||
281 | | vtags MIME { if ($$->mime != -1) { | ||
282 | yyerror("duplicate :mime"); | ||
283 | YYERROR; } | ||
284 | else { $$->mime = MIME; } } | ||
285 | ; | ||
286 | |||
287 | stringlist: '[' strings ']' { $$ = $2; } | ||
288 | | STRING { $$ = new_sl($1, NULL); } | ||
289 | ; | ||
290 | |||
291 | strings: STRING { $$ = new_sl($1, NULL); } | ||
292 | | STRING ',' strings { $$ = new_sl($1, $3); } | ||
293 | ; | ||
294 | |||
295 | block: '{' commands '}' { $$ = $2; } | ||
296 | | '{' '}' { $$ = NULL; } | ||
297 | ; | ||
298 | |||
299 | test: ANYOF testlist { $$ = new_test(ANYOF); $$->u.tl = $2; } | ||
300 | | ALLOF testlist { $$ = new_test(ALLOF); $$->u.tl = $2; } | ||
301 | | EXISTS stringlist { $$ = new_test(EXISTS); $$->u.sl = $2; } | ||
302 | | SFALSE { $$ = new_test(SFALSE); } | ||
303 | | STRUE { $$ = new_test(STRUE); } | ||
304 | | HEADER htags stringlist stringlist | ||
305 | { patternlist_t *pl; | ||
306 | $2 = canon_htags($2); | ||
307 | #ifdef ENABLE_REGEX | ||
308 | if ($2->comptag == REGEX) { | ||
309 | pl = verify_regexs($4, $2->comparator); | ||
310 | if (!pl) { YYERROR; } | ||
311 | } | ||
312 | else | ||
313 | #endif | ||
314 | pl = (patternlist_t *) $4; | ||
315 | |||
316 | $$ = build_header(HEADER, $2, $3, pl); | ||
317 | if ($$ == NULL) { YYERROR; } } | ||
318 | | addrorenv aetags stringlist stringlist | ||
319 | { patternlist_t *pl; | ||
320 | $2 = canon_aetags($2); | ||
321 | #ifdef ENABLE_REGEX | ||
322 | if ($2->comptag == REGEX) { | ||
323 | pl = verify_regexs($4, $2->comparator); | ||
324 | if (!pl) { YYERROR; } | ||
325 | } | ||
326 | else | ||
327 | #endif | ||
328 | pl = (patternlist_t *) $4; | ||
329 | |||
330 | $$ = build_address($1, $2, $3, pl); | ||
331 | if ($$ == NULL) { YYERROR; } } | ||
332 | | NOT test { $$ = new_test(NOT); $$->u.t = $2; } | ||
333 | | SIZE sizetag NUMBER { $$ = new_test(SIZE); $$->u.sz.t = $2; | ||
334 | $$->u.sz.n = $3; } | ||
335 | | error { $$ = NULL; } | ||
336 | ; | ||
337 | |||
338 | addrorenv: ADDRESS { $$ = ADDRESS; } | ||
339 | | ENVELOPE { $$ = ENVELOPE; } | ||
340 | ; | ||
341 | |||
342 | aetags: /* empty */ { $$ = new_aetags(); } | ||
343 | | aetags addrparttag { $$ = $1; | ||
344 | if ($$->addrtag != -1) { | ||
345 | yyerror("duplicate or conflicting address part tag"); | ||
346 | YYERROR; } | ||
347 | else { $$->addrtag = $2; } } | ||
348 | | aetags comptag { $$ = $1; | ||
349 | if ($$->comptag != -1) { | ||
350 | yyerror("duplicate comparator type tag"); YYERROR; } | ||
351 | else { $$->comptag = $2; } } | ||
352 | | aetags COMPARATOR STRING { $$ = $1; | ||
353 | if ($$->comparator != NULL) { | ||
354 | yyerror("duplicate comparator tag"); YYERROR; } | ||
355 | else { $$->comparator = $3; } } | ||
356 | ; | ||
357 | |||
358 | htags: /* empty */ { $$ = new_htags(); } | ||
359 | | htags comptag { $$ = $1; | ||
360 | if ($$->comptag != -1) { | ||
361 | yyerror("duplicate comparator type tag"); YYERROR; } | ||
362 | else { $$->comptag = $2; } } | ||
363 | | htags COMPARATOR STRING { $$ = $1; | ||
364 | if ($$->comparator != NULL) { | ||
365 | yyerror("duplicate comparator tag"); | ||
366 | YYERROR; } | ||
367 | else { $$->comparator = $3; } } | ||
368 | ; | ||
369 | |||
370 | addrparttag: ALL { $$ = ALL; } | ||
371 | | LOCALPART { $$ = LOCALPART; } | ||
372 | | DOMAIN { $$ = DOMAIN; } | ||
373 | | USER { if (!parse_script->support.subaddress) { | ||
374 | yyerror("subaddress not required"); | ||
375 | YYERROR; | ||
376 | } | ||
377 | $$ = USER; } | ||
378 | | DETAIL { if (!parse_script->support.subaddress) { | ||
379 | yyerror("subaddress not required"); | ||
380 | YYERROR; | ||
381 | } | ||
382 | $$ = DETAIL; } | ||
383 | ; | ||
384 | |||
385 | comptag: IS { $$ = IS; } | ||
386 | | CONTAINS { $$ = CONTAINS; } | ||
387 | | MATCHES { $$ = MATCHES; } | ||
388 | | REGEX { if (!parse_script->support.regex) { | ||
389 | yyerror("regex not required"); | ||
390 | YYERROR; | ||
391 | } | ||
392 | $$ = REGEX; } | ||
393 | ; | ||
394 | |||
395 | sizetag: OVER { $$ = OVER; } | ||
396 | | UNDER { $$ = UNDER; } | ||
397 | |||
398 | testlist: '(' tests ')' { $$ = $2; } | ||
399 | ; | ||
400 | |||
401 | tests: test { $$ = new_testlist($1, NULL); } | ||
402 | | test ',' tests { $$ = new_testlist($1, $3); } | ||
403 | ; | ||
404 | |||
405 | %% | ||
406 | commandlist_t *sieve_parse(sieve_script_t *script, FILE *f) | ||
407 | { | ||
408 | commandlist_t *t; | ||
409 | extern FILE *yyin; | ||
410 | |||
411 | yyin = f; | ||
412 | parse_script = script; | ||
413 | if (yyparse()) { | ||
414 | t = NULL; | ||
415 | } else { | ||
416 | t = ret; | ||
417 | } | ||
418 | ret = NULL; | ||
419 | return t; | ||
420 | } | ||
421 | |||
422 | int yyerror(char *msg) | ||
423 | { | ||
424 | extern int yylineno; | ||
425 | int ret; | ||
426 | |||
427 | parse_script->err++; | ||
428 | if (parse_script->interp.err) { | ||
429 | ret = parse_script->interp.err(yylineno, msg, | ||
430 | parse_script->interp.interp_context, | ||
431 | parse_script->script_context); | ||
432 | } | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static int check_reqs(stringlist_t *sl) | ||
438 | { | ||
439 | int i = 1; | ||
440 | stringlist_t *s; | ||
441 | |||
442 | while (sl != NULL) { | ||
443 | s = sl; | ||
444 | sl = sl->next; | ||
445 | |||
446 | i &= script_require(parse_script, s->s); | ||
447 | |||
448 | if (s->s) free(s->s); | ||
449 | free(s); | ||
450 | } | ||
451 | return i; | ||
452 | } | ||
453 | |||
454 | static test_t *build_address(int t, struct aetags *ae, | ||
455 | stringlist_t *sl, patternlist_t *pl) | ||
456 | { | ||
457 | test_t *ret = new_test(t); /* can be either ADDRESS or ENVELOPE */ | ||
458 | |||
459 | assert((t == ADDRESS) || (t == ENVELOPE)); | ||
460 | |||
461 | if (ret) { | ||
462 | ret->u.ae.comptag = ae->comptag; | ||
463 | ret->u.ae.comp = lookup_comp(ae->comparator, ae->comptag); | ||
464 | ret->u.ae.sl = sl; | ||
465 | ret->u.ae.pl = pl; | ||
466 | ret->u.ae.addrpart = ae->addrtag; | ||
467 | free_aetags(ae); | ||
468 | if (ret->u.ae.comp == NULL) { | ||
469 | free_test(ret); | ||
470 | ret = NULL; | ||
471 | } | ||
472 | } | ||
473 | return ret; | ||
474 | } | ||
475 | |||
476 | static test_t *build_header(int t, struct htags *h, | ||
477 | stringlist_t *sl, patternlist_t *pl) | ||
478 | { | ||
479 | test_t *ret = new_test(t); /* can be HEADER */ | ||
480 | |||
481 | assert(t == HEADER); | ||
482 | |||
483 | if (ret) { | ||
484 | ret->u.h.comptag = h->comptag; | ||
485 | ret->u.h.comp = lookup_comp(h->comparator, h->comptag); | ||
486 | ret->u.h.sl = sl; | ||
487 | ret->u.h.pl = pl; | ||
488 | free_htags(h); | ||
489 | if (ret->u.h.comp == NULL) { | ||
490 | free_test(ret); | ||
491 | ret = NULL; | ||
492 | } | ||
493 | } | ||
494 | return ret; | ||
495 | } | ||
496 | |||
497 | static commandlist_t *build_vacation(int t, struct vtags *v, char *reason) | ||
498 | { | ||
499 | commandlist_t *ret = new_command(t); | ||
500 | |||
501 | assert(t == VACATION); | ||
502 | |||
503 | if (ret) { | ||
504 | ret->u.v.subject = v->subject; v->subject = NULL; | ||
505 | ret->u.v.days = v->days; | ||
506 | ret->u.v.mime = v->mime; | ||
507 | ret->u.v.addresses = v->addresses; v->addresses = NULL; | ||
508 | free_vtags(v); | ||
509 | ret->u.v.message = reason; | ||
510 | } | ||
511 | return ret; | ||
512 | } | ||
513 | |||
514 | static struct aetags *new_aetags(void) | ||
515 | { | ||
516 | struct aetags *r = (struct aetags *) xmalloc(sizeof(struct aetags)); | ||
517 | |||
518 | r->addrtag = r->comptag = -1; | ||
519 | r->comparator = NULL; | ||
520 | |||
521 | return r; | ||
522 | } | ||
523 | |||
524 | static struct aetags *canon_aetags(struct aetags *ae) | ||
525 | { | ||
526 | if (ae->addrtag == -1) { ae->addrtag = ALL; } | ||
527 | if (ae->comparator == NULL) { ae->comparator = strdup("i;ascii-casemap"); } | ||
528 | if (ae->comptag == -1) { ae->comptag = IS; } | ||
529 | return ae; | ||
530 | } | ||
531 | |||
532 | static void free_aetags(struct aetags *ae) | ||
533 | { | ||
534 | free(ae->comparator); | ||
535 | free(ae); | ||
536 | } | ||
537 | |||
538 | static struct htags *new_htags(void) | ||
539 | { | ||
540 | struct htags *r = (struct htags *) xmalloc(sizeof(struct htags)); | ||
541 | |||
542 | r->comptag = -1; | ||
543 | r->comparator = NULL; | ||
544 | |||
545 | return r; | ||
546 | } | ||
547 | |||
548 | static struct htags *canon_htags(struct htags *h) | ||
549 | { | ||
550 | if (h->comparator == NULL) { h->comparator = strdup("i;ascii-casemap"); } | ||
551 | if (h->comptag == -1) { h->comptag = IS; } | ||
552 | return h; | ||
553 | } | ||
554 | |||
555 | static void free_htags(struct htags *h) | ||
556 | { | ||
557 | free(h->comparator); | ||
558 | free(h); | ||
559 | } | ||
560 | |||
561 | static struct vtags *new_vtags(void) | ||
562 | { | ||
563 | struct vtags *r = (struct vtags *) xmalloc(sizeof(struct vtags)); | ||
564 | |||
565 | r->days = -1; | ||
566 | r->addresses = NULL; | ||
567 | r->subject = NULL; | ||
568 | r->mime = -1; | ||
569 | |||
570 | return r; | ||
571 | } | ||
572 | |||
573 | static struct vtags *canon_vtags(struct vtags *v) | ||
574 | { | ||
575 | assert(parse_script->interp.vacation != NULL); | ||
576 | |||
577 | if (v->days == -1) { v->days = 7; } | ||
578 | if (v->days < parse_script->interp.vacation->min_response) | ||
579 | { v->days = parse_script->interp.vacation->min_response; } | ||
580 | if (v->days > parse_script->interp.vacation->max_response) | ||
581 | { v->days = parse_script->interp.vacation->max_response; } | ||
582 | if (v->mime == -1) { v->mime = 0; } | ||
583 | |||
584 | return v; | ||
585 | } | ||
586 | |||
587 | static void free_vtags(struct vtags *v) | ||
588 | { | ||
589 | if (v->addresses) { free_sl(v->addresses); } | ||
590 | if (v->subject) { free(v->subject); } | ||
591 | free(v); | ||
592 | } | ||
593 | |||
594 | char *addrptr; /* pointer to address string for address lexer */ | ||
595 | char addrerr[500]; /* buffer for address parser error messages */ | ||
596 | |||
597 | static int verify_address(char *s) | ||
598 | { | ||
599 | char errbuf[500]; | ||
600 | |||
601 | addrptr = s; | ||
602 | if (addrparse()) { | ||
603 | sprintf(errbuf, "address '%s': %s", s, addrerr); | ||
604 | yyerror(errbuf); | ||
605 | return 0; | ||
606 | } | ||
607 | return 1; | ||
608 | } | ||
609 | |||
610 | static int verify_addresses(stringlist_t *sl) | ||
611 | { | ||
612 | for (; sl != NULL && verify_address(sl->s); sl = sl->next) ; | ||
613 | return (sl == NULL); | ||
614 | } | ||
615 | |||
616 | static int verify_mailbox(char *s) | ||
617 | { | ||
618 | /* if not a mailbox, call yyerror */ | ||
619 | return 1; | ||
620 | } | ||
621 | |||
622 | static int verify_mailboxes(stringlist_t *sl) | ||
623 | { | ||
624 | for (; sl != NULL && verify_mailbox(sl->s); sl = sl->next) ; | ||
625 | return (sl == NULL); | ||
626 | } | ||
627 | |||
628 | static int verify_flag(char *f) | ||
629 | { | ||
630 | char errbuf[100]; | ||
631 | |||
632 | if (f[0] == '\\') { | ||
633 | lcase(f); | ||
634 | if (strcmp(f, "\\seen") && strcmp(f, "\\answered") && | ||
635 | strcmp(f, "\\flagged") && strcmp(f, "\\draft") && | ||
636 | strcmp(f, "\\deleted")) { | ||
637 | sprintf(errbuf, "flag '%s': not a system flag", f); | ||
638 | yyerror(errbuf); | ||
639 | return 0; | ||
640 | } | ||
641 | return 1; | ||
642 | } | ||
643 | if (!imparse_isatom(f)) { | ||
644 | sprintf(errbuf, "flag '%s': not a valid keyword", f); | ||
645 | yyerror(errbuf); | ||
646 | return 0; | ||
647 | } | ||
648 | return 1; | ||
649 | } | ||
650 | |||
651 | static int verify_flags(stringlist_t *sl) | ||
652 | { | ||
653 | for (; sl != NULL && verify_flag(sl->s); sl = sl->next) ; | ||
654 | return (sl == NULL); | ||
655 | } | ||
656 | |||
657 | |||
658 | #ifdef ENABLE_REGEX | ||
659 | static regex_t *verify_regex(char *s, int cflags) | ||
660 | { | ||
661 | int ret; | ||
662 | char errbuf[100]; | ||
663 | regex_t *reg = (regex_t *) xmalloc(sizeof(regex_t)); | ||
664 | |||
665 | if ((ret = regcomp(reg, s, cflags)) != 0) { | ||
666 | (void) regerror(ret, reg, errbuf, sizeof(errbuf)); | ||
667 | yyerror(errbuf); | ||
668 | free(reg); | ||
669 | return NULL; | ||
670 | } | ||
671 | return reg; | ||
672 | } | ||
673 | |||
674 | static patternlist_t *verify_regexs(stringlist_t *sl, char *comp) | ||
675 | { | ||
676 | stringlist_t *sl2; | ||
677 | patternlist_t *pl = NULL; | ||
678 | int cflags = REG_EXTENDED | REG_NOSUB; | ||
679 | regex_t *reg; | ||
680 | |||
681 | if (!strcmp(comp, "i;ascii-casemap")) { | ||
682 | cflags |= REG_ICASE; | ||
683 | } | ||
684 | |||
685 | for (sl2 = sl; sl2 != NULL; sl2 = sl2->next) { | ||
686 | if ((reg = verify_regex(sl2->s, cflags)) == NULL) { | ||
687 | free_pl(pl, REGEX); | ||
688 | break; | ||
689 | } | ||
690 | pl = (patternlist_t *) new_pl(reg, pl); | ||
691 | } | ||
692 | if (sl2 == NULL) { | ||
693 | free_sl(sl); | ||
694 | return pl; | ||
695 | } | ||
696 | return NULL; | ||
697 | } | ||
698 | #endif | ||
699 | |||
700 | /* is it ok to put this in an RFC822 header body? */ | ||
701 | static int ok_header(char *s) | ||
702 | { | ||
703 | return 1; | ||
704 | } |
sieve/sieve-lex.l
0 → 100644
1 | %{ | ||
2 | /* sieve.l -- sieve lexer | ||
3 | * Larry Greenfield | ||
4 | */ | ||
5 | /*********************************************************** | ||
6 | Copyright 1999 by Carnegie Mellon University | ||
7 | |||
8 | All Rights Reserved | ||
9 | |||
10 | Permission to use, copy, modify, and distribute this software and its | ||
11 | documentation for any purpose and without fee is hereby granted, | ||
12 | provided that the above copyright notice appear in all copies and that | ||
13 | both that copyright notice and this permission notice appear in | ||
14 | supporting documentation, and that the name of Carnegie Mellon | ||
15 | University not be used in advertising or publicity pertaining to | ||
16 | distribution of the software without specific, written prior | ||
17 | permission. | ||
18 | |||
19 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
20 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
21 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
22 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
23 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
24 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
25 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
26 | ******************************************************************/ | ||
27 | |||
28 | #ifdef HAVE_CONFIG_H | ||
29 | #include <config.h> | ||
30 | #endif | ||
31 | |||
32 | #include <string.h> /* for strdup */ | ||
33 | #include "xmalloc.h" | ||
34 | |||
35 | #include "tree.h" | ||
36 | #include "sieve-gram.h" | ||
37 | |||
38 | static int tonum(char *c); | ||
39 | static char *fixstr(char *); | ||
40 | static char *mlbuf; | ||
41 | static int mlbufsz, mlcur; | ||
42 | extern int yyerror(char *); | ||
43 | %} | ||
44 | |||
45 | %option yylineno | ||
46 | %option noyywrap | ||
47 | |||
48 | ws [ \t]+ | ||
49 | ident [a-zA-Z_][a-zA-Z_0-9]* | ||
50 | CRLF (\r\n|\r|\n) | ||
51 | |||
52 | %state MULTILINE | ||
53 | |||
54 | %% | ||
55 | <MULTILINE>^\.{CRLF} { BEGIN INITIAL; | ||
56 | mlbuf[mlcur] = '\0'; | ||
57 | yylval.sval = mlbuf; return STRING; } | ||
58 | <MULTILINE>^\.\. { /* dot stuffing! we want one . */ yyless(1); } | ||
59 | <MULTILINE>(.|\n) { if (mlcur == mlbufsz) | ||
60 | mlbuf = xrealloc(mlbuf, 1 + (mlbufsz+=1024)); | ||
61 | mlbuf[mlcur++] = yytext[0]; } | ||
62 | <MULTILINE><<EOF>> { yyerror("unexpected end of file in string"); | ||
63 | yyterminate(); } | ||
64 | <INITIAL>text:{ws}?(#.*)?{CRLF} { BEGIN MULTILINE; | ||
65 | mlcur = 0; mlbufsz = 0; mlbuf = NULL; } | ||
66 | <INITIAL>[0-9]+[KMG]? { yylval.nval = tonum(yytext); return NUMBER; } | ||
67 | <INITIAL>if return IF; | ||
68 | <INITIAL>elsif return ELSIF; | ||
69 | <INITIAL>else return ELSE; | ||
70 | <INITIAL>anyof return ANYOF; | ||
71 | <INITIAL>allof return ALLOF; | ||
72 | <INITIAL>exists return EXISTS; | ||
73 | <INITIAL>false return SFALSE; | ||
74 | <INITIAL>true return STRUE; | ||
75 | <INITIAL>address return ADDRESS; | ||
76 | <INITIAL>envelope return ENVELOPE; | ||
77 | <INITIAL>header return HEADER; | ||
78 | <INITIAL>not return NOT; | ||
79 | <INITIAL>size return SIZE; | ||
80 | <INITIAL>reject return REJCT; | ||
81 | <INITIAL>fileinto return FILEINTO; | ||
82 | <INITIAL>redirect return FORWARD; | ||
83 | <INITIAL>keep return KEEP; | ||
84 | <INITIAL>require return REQUIRE; | ||
85 | <INITIAL>stop return STOP; | ||
86 | <INITIAL>discard return DISCARD; | ||
87 | <INITIAL>setflag return SETFLAG; | ||
88 | <INITIAL>addflag return ADDFLAG; | ||
89 | <INITIAL>removeflag return REMOVEFLAG; | ||
90 | <INITIAL>mark return MARK; | ||
91 | <INITIAL>unmark return UNMARK; | ||
92 | <INITIAL>notify return NOTIFY; | ||
93 | <INITIAL>denotify return DENOTIFY; | ||
94 | <INITIAL>:low return LOW; | ||
95 | <INITIAL>:medium return MEDIUM; | ||
96 | <INITIAL>:high return HIGH; | ||
97 | <INITIAL>vacation return VACATION; | ||
98 | <INITIAL>:days return DAYS; | ||
99 | <INITIAL>:addresses return ADDRESSES; | ||
100 | <INITIAL>:subject return SUBJECT; | ||
101 | <INITIAL>:mime return MIME; | ||
102 | <INITIAL>:comparator return COMPARATOR; | ||
103 | <INITIAL>:is return IS; | ||
104 | <INITIAL>:contains return CONTAINS; | ||
105 | <INITIAL>:matches return MATCHES; | ||
106 | <INITIAL>:regex return REGEX; | ||
107 | <INITIAL>:over return OVER; | ||
108 | <INITIAL>:under return UNDER; | ||
109 | <INITIAL>:all return ALL; | ||
110 | <INITIAL>:localpart return LOCALPART; | ||
111 | <INITIAL>:domain return DOMAIN; | ||
112 | <INITIAL>:user return USER; | ||
113 | <INITIAL>:detail return DETAIL; | ||
114 | <INITIAL>\"([^"]|\\.)*\" { yylval.sval = fixstr(yytext); return STRING; } | ||
115 | <INITIAL>[ \t\n\r] ; /* ignore whitespace */ | ||
116 | <INITIAL>#.* ; /* ignore comments */ | ||
117 | . return yytext[0]; | ||
118 | |||
119 | %% | ||
120 | static int tonum(char *c) | ||
121 | { | ||
122 | int val = atoi(c); | ||
123 | switch (c[strlen(c)-1]) { | ||
124 | case 'K': val *= (1 << 10); break; | ||
125 | case 'M': val *= (1 << 20); break; | ||
126 | case 'G': val *= (1 << 30); break; | ||
127 | default: break; | ||
128 | } | ||
129 | return val; | ||
130 | } | ||
131 | |||
132 | static char *fixstr(char *str) | ||
133 | { | ||
134 | char *r, *s = (char *) xmalloc(sizeof(char) * strlen(str)); | ||
135 | |||
136 | r = s; | ||
137 | str++; /* skip open " */ | ||
138 | while (*str != '"') { | ||
139 | if (*str == '\\') | ||
140 | str++; | ||
141 | *s++ = *str++; | ||
142 | } | ||
143 | *s = '\0'; | ||
144 | return r; | ||
145 | } |
sieve/sieve.c
0 → 100644
1 | /* | ||
2 | * sieve interpreter | ||
3 | */ | ||
4 | |||
5 | #ifdef HAVE_CONFIG_H | ||
6 | #include <config.h> | ||
7 | #endif | ||
8 | |||
9 | #include <assert.h> | ||
10 | #include <errno.h> | ||
11 | #include <fcntl.h> | ||
12 | #include <stdio.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <string.h> | ||
15 | #include <sys/stat.h> | ||
16 | #include <sys/types.h> | ||
17 | #include <unistd.h> | ||
18 | #include <stdarg.h> | ||
19 | #ifdef HAVE_STRINGS_H | ||
20 | #include <strings.h> | ||
21 | #endif | ||
22 | |||
23 | #include <mailutils/mailbox.h> | ||
24 | #include <mailutils/address.h> | ||
25 | #include <mailutils/registrar.h> | ||
26 | |||
27 | #include "sieve_interface.h" | ||
28 | #include "message.h" | ||
29 | |||
30 | #include "svfield.h" | ||
31 | |||
32 | /** utility wrappers around mailutils functionality **/ | ||
33 | |||
34 | int | ||
35 | mu_copy_debug_level (const mailbox_t from, mailbox_t to) | ||
36 | { | ||
37 | debug_t d = 0; | ||
38 | size_t level; | ||
39 | int rc; | ||
40 | |||
41 | if (!from || !to) | ||
42 | return EINVAL; | ||
43 | |||
44 | rc = mailbox_get_debug (from, &d); | ||
45 | |||
46 | if (!rc) | ||
47 | debug_get_level (d, &level); | ||
48 | |||
49 | if (!rc) | ||
50 | rc = mailbox_get_debug (to, &d); | ||
51 | |||
52 | if (!rc) | ||
53 | debug_set_level (d, level); | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | int | ||
59 | mu_save_to (const char *toname, message_t mesg, const char **errmsg) | ||
60 | { | ||
61 | int res = 0; | ||
62 | mailbox_t to = 0; | ||
63 | mailbox_t from = 0; | ||
64 | |||
65 | res = mailbox_create_default (&to, toname); | ||
66 | |||
67 | if (res == ENOENT) | ||
68 | *errmsg = "no handler for this type of mailbox"; | ||
69 | |||
70 | if (!res) | ||
71 | { | ||
72 | if (message_get_mailbox (mesg, &from) == 0) | ||
73 | mu_copy_debug_level (from, to); | ||
74 | } | ||
75 | if (!res) | ||
76 | { | ||
77 | *errmsg = "mailbox_open"; | ||
78 | res = mailbox_open (to, MU_STREAM_WRITE | MU_STREAM_CREAT); | ||
79 | } | ||
80 | if (!res) | ||
81 | { | ||
82 | *errmsg = "mailbox_open"; | ||
83 | res = mailbox_append_message (to, mesg); | ||
84 | |||
85 | if (!res) | ||
86 | { | ||
87 | *errmsg = "mailbox_close"; | ||
88 | res = mailbox_close (to); | ||
89 | } | ||
90 | else | ||
91 | { | ||
92 | mailbox_close (to); | ||
93 | } | ||
94 | } | ||
95 | mailbox_destroy (&to); | ||
96 | |||
97 | return res; | ||
98 | } | ||
99 | |||
100 | int | ||
101 | mu_mark_deleted (message_t msg) | ||
102 | { | ||
103 | attribute_t attr = 0; | ||
104 | int res; | ||
105 | |||
106 | res = message_get_attribute (msg, &attr); | ||
107 | |||
108 | if (!res) | ||
109 | attribute_set_deleted (attr); | ||
110 | |||
111 | return res; | ||
112 | } | ||
113 | |||
114 | static int | ||
115 | sv_errno (int rc) | ||
116 | { | ||
117 | switch (rc) | ||
118 | { | ||
119 | case ENOMEM: | ||
120 | return SIEVE_NOMEM; | ||
121 | case ENOENT: | ||
122 | return SIEVE_FAIL; | ||
123 | case EOK: | ||
124 | return SIEVE_OK; | ||
125 | } | ||
126 | return SIEVE_INTERNAL_ERROR; | ||
127 | } | ||
128 | |||
129 | /** sieve context structures | ||
130 | |||
131 | The object relationship diagram is this, with the names in [] | ||
132 | being the argument name when the context's are provided as | ||
133 | arguments to callback functions. | ||
134 | |||
135 | sieve_execute_script() --> sv_msg_ctx_t, "mc" | ||
136 | |||
137 | | | ||
138 | | | ||
139 | V | ||
140 | |||
141 | sieve_script_t ---> sv_script_ctx_t, "sc" | ||
142 | |||
143 | | | ||
144 | | | ||
145 | V | ||
146 | |||
147 | sieve_interp_t ---> sv_interp_ctx_t, "ic" | ||
148 | |||
149 | |||
150 | */ | ||
151 | |||
152 | typedef struct sv_interp_ctx_t | ||
153 | { | ||
154 | /* cmd line options */ | ||
155 | int opt_no_actions; | ||
156 | int opt_verbose; | ||
157 | int opt_no_run; | ||
158 | int opt_watch; | ||
159 | char*opt_mbox; | ||
160 | char*opt_script; | ||
161 | |||
162 | int print_mask; | ||
163 | FILE*print_stream; | ||
164 | |||
165 | /* mailutils debug handle, we need to destroy it */ | ||
166 | debug_t debug; | ||
167 | } sv_interp_ctx_t; | ||
168 | |||
169 | typedef struct sv_script_ctx_t | ||
170 | { | ||
171 | sv_interp_ctx_t* ic; | ||
172 | } sv_script_ctx_t; | ||
173 | |||
174 | typedef struct sv_msg_ctx_t | ||
175 | { | ||
176 | int rc; /* the mailutils return code */ | ||
177 | int cache_filled; | ||
178 | sv_field_cache_t cache; | ||
179 | message_t msg; | ||
180 | mailbox_t mbox; | ||
181 | char *summary; | ||
182 | |||
183 | sv_interp_ctx_t* ic; | ||
184 | } sv_msg_ctx_t; | ||
185 | |||
186 | enum /* print level masks */ | ||
187 | { | ||
188 | SV_PRN_MU = 0x1, | ||
189 | SV_PRN_ACT = 0x2, | ||
190 | SV_PRN_QRY = 0x4, | ||
191 | SV_PRN_PRS = 0x6, | ||
192 | SV_PRN_NOOP | ||
193 | }; | ||
194 | |||
195 | void | ||
196 | sv_printv (sv_interp_ctx_t* ic, int level, const char *fmt, va_list ap) | ||
197 | { | ||
198 | if(level & ic->print_mask) | ||
199 | vfprintf(ic->print_stream, fmt, ap); | ||
200 | } | ||
201 | void sv_print (sv_interp_ctx_t* ic, int level, const char* fmt, ...) | ||
202 | { | ||
203 | va_list ap; | ||
204 | va_start(fmt, ap); | ||
205 | sv_printv(ic, level, fmt, ap); | ||
206 | va_end(ap); | ||
207 | } | ||
208 | |||
209 | /* we hook mailutils debug output into our diagnostics using this */ | ||
210 | int | ||
211 | sv_mu_debug_print (debug_t d, const char *fmt, va_list ap) | ||
212 | { | ||
213 | sv_printv(debug_get_owner(d), SV_PRN_MU, fmt, ap); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | /** message query callbacks **/ | ||
219 | |||
220 | int | ||
221 | sv_getsize (void *mc, int *size) | ||
222 | { | ||
223 | sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc; | ||
224 | size_t sz = 0; | ||
225 | |||
226 | message_size (m->msg, &sz); | ||
227 | |||
228 | *size = sz; | ||
229 | |||
230 | sv_print (m->ic, SV_PRN_QRY, "getsize -> %d\n", *size); | ||
231 | |||
232 | return SIEVE_OK; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | A given header can occur multiple times, so we return a pointer | ||
237 | to a null terminated array of pointers to the values found for | ||
238 | the named header. | ||
239 | */ | ||
240 | int | ||
241 | sv_getheader (void *mc, const char *name, const char ***body) | ||
242 | { | ||
243 | sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc; | ||
244 | |||
245 | m->rc = 0; | ||
246 | |||
247 | if (!m->cache_filled) | ||
248 | { | ||
249 | header_t h = 0; | ||
250 | size_t i = 0; | ||
251 | char *fn = 0; | ||
252 | char *fv = 0; | ||
253 | |||
254 | m->cache_filled = 1; | ||
255 | |||
256 | message_get_header (m->msg, &h); | ||
257 | |||
258 | header_get_field_count (h, &i); | ||
259 | |||
260 | sv_print (m->ic, SV_PRN_QRY, "getheader, filling cache with %d fields\n", i); | ||
261 | |||
262 | for (; i > 0; i--) | ||
263 | { | ||
264 | m->rc = header_aget_field_name (h, i, &fn); | ||
265 | if (m->rc) | ||
266 | break; | ||
267 | m->rc = header_aget_field_value (h, i, &fv); | ||
268 | if (m->rc) | ||
269 | break; | ||
270 | |||
271 | sv_print (m->ic, SV_PRN_QRY, "getheader, cacheing %s=%s\n", fn, fv); | ||
272 | |||
273 | m->rc = sv_field_cache_add (&m->cache, fn, fv); | ||
274 | |||
275 | if (m->rc == 0) | ||
276 | { | ||
277 | fv = 0; /* owned by the cache */ | ||
278 | } | ||
279 | if (m->rc) | ||
280 | break; | ||
281 | |||
282 | /* the cache doesn't want it, and we don't need it */ | ||
283 | free (fn); | ||
284 | fn = 0; | ||
285 | } | ||
286 | free (fn); | ||
287 | free (fv); | ||
288 | } | ||
289 | if (!m->rc) | ||
290 | { | ||
291 | m->rc = sv_field_cache_get (&m->cache, name, body); | ||
292 | } | ||
293 | if (m->rc) | ||
294 | { | ||
295 | sv_print (m->ic, SV_PRN_QRY, "getheader %s, failed %s\n", name, strerror (m->rc)); | ||
296 | } | ||
297 | else | ||
298 | { | ||
299 | const char **b = *body; | ||
300 | int i = 1; | ||
301 | sv_print (m->ic, SV_PRN_QRY, "getheader, %s=%s", name, b[0]); | ||
302 | while (b[0] && b[i]) | ||
303 | { | ||
304 | sv_print (m->ic, SV_PRN_QRY, ", %s", b[i]); | ||
305 | i++; | ||
306 | } | ||
307 | sv_print (m->ic, SV_PRN_QRY, "\n"); | ||
308 | } | ||
309 | return sv_errno (m->rc); | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | name will always be "to" or "from" | ||
314 | |||
315 | envelope_t doesn't seem to allow "to" to be gotten, just "from". | ||
316 | What's up? | ||
317 | |||
318 | int getenvelope(void *mc, const char *name, const char ***body) | ||
319 | { | ||
320 | static const char *buf[2]; | ||
321 | |||
322 | if (buf[0] == NULL) { buf[0] = malloc(sizeof(char) * 256); buf[1] = NULL; } | ||
323 | printf("Envelope body of '%s'? ", head); | ||
324 | scanf("%s", buf[0]); | ||
325 | *body = buf; | ||
326 | |||
327 | return SIEVE_OK; | ||
328 | } | ||
329 | */ | ||
330 | |||
331 | /* message action callbacks */ | ||
332 | |||
333 | /* | ||
334 | The actions arguments are mostly callback data provided during the | ||
335 | setup of the intepreter object, script object, and the execution of | ||
336 | a script. | ||
337 | |||
338 | The args are: | ||
339 | |||
340 | void* ac; // action context, the member of the union Action.u associated | ||
341 | // with this kind of action. | ||
342 | void* ic, // from sieve_interp_alloc(, ic); | ||
343 | void* sc, // from sieve_script_parse(, , sc, ); | ||
344 | void* mc, // from sieve_execute_script(, mc); | ||
345 | const char** errmsg // fill it in if you return failure | ||
346 | */ | ||
347 | |||
348 | const char * | ||
349 | str_action (action_t a) | ||
350 | { | ||
351 | switch (a) | ||
352 | { | ||
353 | case ACTION_NONE: | ||
354 | return "NONE"; | ||
355 | case ACTION_REJECT: | ||
356 | return "REJECT"; | ||
357 | case ACTION_FILEINTO: | ||
358 | return "FILEINTO"; | ||
359 | case ACTION_KEEP: | ||
360 | return "KEEP"; | ||
361 | case ACTION_REDIRECT: | ||
362 | return "REDIRECT"; | ||
363 | case ACTION_DISCARD: | ||
364 | return "DISCARD"; | ||
365 | case ACTION_VACATION: | ||
366 | return "VACATION"; | ||
367 | case ACTION_SETFLAG: | ||
368 | return "SETFLAG"; | ||
369 | case ACTION_ADDFLAG: | ||
370 | return "ADDFLAG"; | ||
371 | case ACTION_REMOVEFLAG: | ||
372 | return "REMOVEFLAG"; | ||
373 | case ACTION_MARK: | ||
374 | return "MARK"; | ||
375 | case ACTION_UNMARK: | ||
376 | return "UNMARK"; | ||
377 | case ACTION_NOTIFY: | ||
378 | return "NOTIFY"; | ||
379 | case ACTION_DENOTIFY: | ||
380 | return "DENOTIFY"; | ||
381 | } | ||
382 | return "UNKNOWN"; | ||
383 | } | ||
384 | const char * | ||
385 | str_sieve_error (int e) | ||
386 | { | ||
387 | switch (e) | ||
388 | { | ||
389 | case SIEVE_FAIL: | ||
390 | return "SIEVE_FAIL"; | ||
391 | case SIEVE_NOT_FINALIZED: | ||
392 | return "SIEVE_NOT_FINALIZED"; | ||
393 | case SIEVE_PARSE_ERROR: | ||
394 | return "SIEVE_PARSE_ERROR"; | ||
395 | case SIEVE_RUN_ERROR: | ||
396 | return "SIEVE_RUN_ERROR"; | ||
397 | case SIEVE_INTERNAL_ERROR: | ||
398 | return "SIEVE_INTERNAL_ERROR"; | ||
399 | case SIEVE_NOMEM: | ||
400 | return "SIEVE_NOMEM"; | ||
401 | case SIEVE_DONE: | ||
402 | return "SIEVE_DONE"; | ||
403 | } | ||
404 | return "UNKNOWN"; | ||
405 | } | ||
406 | |||
407 | |||
408 | void | ||
409 | sv_print_action (action_t a, void *ac, void *ic, void *sc, void *mc) | ||
410 | { | ||
411 | //sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc; | ||
412 | |||
413 | sv_print (ic, SV_PRN_ACT, "action => %s\n", str_action (a)); | ||
414 | } | ||
415 | |||
416 | int | ||
417 | sv_keep (void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
418 | { | ||
419 | //sv_msg_ctx_t * m = (sv_msg_ctx_t *) mc; | ||
420 | //sieve_keep_context_t * a = (sieve_keep_context_t *) ac; | ||
421 | |||
422 | sv_print_action (ACTION_KEEP, ac, ic, sc, mc); | ||
423 | |||
424 | return SIEVE_OK; | ||
425 | } | ||
426 | |||
427 | int | ||
428 | sv_fileinto (void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
429 | { | ||
430 | sieve_fileinto_context_t *a = (sieve_fileinto_context_t *) ac; | ||
431 | sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc; | ||
432 | sv_interp_ctx_t *i = (sv_interp_ctx_t *) ic; | ||
433 | int res = 0; | ||
434 | |||
435 | sv_print_action (ACTION_FILEINTO, ac, ic, sc, mc); | ||
436 | sv_print (i, SV_PRN_ACT, " into <%s>\n", a->mailbox); | ||
437 | |||
438 | if (!i->opt_no_actions) | ||
439 | { | ||
440 | res = mu_save_to (a->mailbox, m->msg, errmsg); | ||
441 | |||
442 | if (!res) | ||
443 | { | ||
444 | res = mu_mark_deleted (m->msg); | ||
445 | } | ||
446 | } | ||
447 | if (res && !errmsg) | ||
448 | *errmsg = strerror (res); | ||
449 | |||
450 | if (res) | ||
451 | sv_print (i, SV_PRN_ACT, " fail with [%d] %s\n", res, *errmsg); | ||
452 | |||
453 | return res ? SIEVE_FAIL : SIEVE_OK; | ||
454 | } | ||
455 | |||
456 | int | ||
457 | sv_redirect (void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
458 | { | ||
459 | sv_print_action (ACTION_REDIRECT, ac, ic, sc, mc); | ||
460 | |||
461 | return SIEVE_OK; | ||
462 | } | ||
463 | |||
464 | int | ||
465 | sv_discard (void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
466 | { | ||
467 | sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc; | ||
468 | sv_interp_ctx_t *i = (sv_interp_ctx_t *) ic; | ||
469 | int res = 0; | ||
470 | |||
471 | sv_print_action (ACTION_DISCARD, ac, ic, sc, mc); | ||
472 | |||
473 | if (!i->opt_no_actions) | ||
474 | { | ||
475 | res = mu_mark_deleted (m->msg); | ||
476 | } | ||
477 | if (res) | ||
478 | *errmsg = strerror (res); | ||
479 | |||
480 | return SIEVE_OK; | ||
481 | } | ||
482 | |||
483 | int | ||
484 | sv_reject (void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
485 | { | ||
486 | sv_print_action (ACTION_REJECT, ac, ic, sc, mc); | ||
487 | |||
488 | return SIEVE_OK; | ||
489 | } | ||
490 | |||
491 | /* | ||
492 | int sv_notify(void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
493 | { | ||
494 | sv_print_action(ACTION_NOTIFY, ac, ic, sc, mc); | ||
495 | |||
496 | return SIEVE_OK; | ||
497 | } | ||
498 | */ | ||
499 | |||
500 | int | ||
501 | sv_autorespond (void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
502 | { | ||
503 | return SIEVE_FAIL; | ||
504 | } | ||
505 | |||
506 | int | ||
507 | sv_send_response (void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
508 | { | ||
509 | return SIEVE_FAIL; | ||
510 | } | ||
511 | |||
512 | #if 0 | ||
513 | sieve_vacation_t vacation = { | ||
514 | 0, /* min response */ | ||
515 | 0, /* max response */ | ||
516 | &sv_autorespond, /* autorespond() */ | ||
517 | &sv_send_response /* send_response() */ | ||
518 | }; | ||
519 | |||
520 | char *markflags[] = { "\\flagged" }; | ||
521 | sieve_imapflags_t mark = { markflags, 1 }; | ||
522 | #endif | ||
523 | |||
524 | int | ||
525 | sv_parse_error (int lineno, const char *msg, void *ic, void *sc) | ||
526 | { | ||
527 | sv_interp_ctx_t* i = (sv_interp_ctx_t*) ic; | ||
528 | |||
529 | sv_print (i, SV_PRN_PRS, "%s:%d: %s\n", i->opt_script, lineno, msg); | ||
530 | |||
531 | return SIEVE_OK; | ||
532 | } | ||
533 | |||
534 | int | ||
535 | sv_execute_error (const char *msg, void *ic, void *sc, void *mc) | ||
536 | { | ||
537 | fprintf (stderr, "runtime error: %s\n", msg); | ||
538 | |||
539 | return SIEVE_OK; | ||
540 | } | ||
541 | |||
542 | int | ||
543 | sv_summary (const char *msg, void *ic, void *sc, void *mc) | ||
544 | { | ||
545 | sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc; | ||
546 | |||
547 | m->summary = strdup (msg); | ||
548 | |||
549 | return SIEVE_OK; | ||
550 | } | ||
551 | |||
552 | int | ||
553 | sieve_register_mailutils (sieve_interp_t * i) | ||
554 | { | ||
555 | int res; | ||
556 | |||
557 | res = sieve_register_size (i, &sv_getsize); | ||
558 | if (res != SIEVE_OK) | ||
559 | { | ||
560 | printf ("sieve_register_size() returns %d\n", res); | ||
561 | exit (1); | ||
562 | } | ||
563 | res = sieve_register_header (i, &sv_getheader); | ||
564 | if (res != SIEVE_OK) | ||
565 | { | ||
566 | printf ("sieve_register_header() returns %d\n", res); | ||
567 | exit (1); | ||
568 | } | ||
569 | res = sieve_register_redirect (i, &sv_redirect); | ||
570 | if (res != SIEVE_OK) | ||
571 | { | ||
572 | printf ("sieve_register_redirect() returns %d\n", res); | ||
573 | exit (1); | ||
574 | } | ||
575 | res = sieve_register_keep (i, &sv_keep); | ||
576 | if (res != SIEVE_OK) | ||
577 | { | ||
578 | printf ("sieve_register_keep() returns %d\n", res); | ||
579 | exit (1); | ||
580 | } | ||
581 | #if 0 | ||
582 | res = sieve_register_envelope (i, &sv_getenvelope); | ||
583 | if (res != SIEVE_OK) | ||
584 | { | ||
585 | printf ("sieve_register_envelope() returns %d\n", res); | ||
586 | exit (1); | ||
587 | } | ||
588 | #endif | ||
589 | res = sieve_register_discard (i, &sv_discard); | ||
590 | if (res != SIEVE_OK) | ||
591 | { | ||
592 | printf ("sieve_register_discard() returns %d\n", res); | ||
593 | exit (1); | ||
594 | } | ||
595 | res = sieve_register_reject (i, &sv_reject); | ||
596 | if (res != SIEVE_OK) | ||
597 | { | ||
598 | printf ("sieve_register_reject() returns %d\n", res); | ||
599 | exit (1); | ||
600 | } | ||
601 | res = sieve_register_fileinto (i, &sv_fileinto); | ||
602 | if (res != SIEVE_OK) | ||
603 | { | ||
604 | printf ("sieve_register_fileinto() returns %d\n", res); | ||
605 | exit (1); | ||
606 | } | ||
607 | #if 0 | ||
608 | res = sieve_register_vacation (i, &sv_vacation); | ||
609 | if (res != SIEVE_OK) | ||
610 | { | ||
611 | printf ("sieve_register_vacation() returns %d\n", res); | ||
612 | exit (1); | ||
613 | } | ||
614 | res = sieve_register_imapflags (i, &mark); | ||
615 | if (res != SIEVE_OK) | ||
616 | { | ||
617 | printf ("sieve_register_imapflags() returns %d\n", res); | ||
618 | exit (1); | ||
619 | } | ||
620 | #endif | ||
621 | |||
622 | #if 0 | ||
623 | res = sieve_register_notify (i, &sv_notify); | ||
624 | if (res != SIEVE_OK) | ||
625 | { | ||
626 | printf ("sieve_register_notify() returns %d\n", res); | ||
627 | exit (1); | ||
628 | } | ||
629 | #endif | ||
630 | res = sieve_register_parse_error (i, &sv_parse_error); | ||
631 | if (res != SIEVE_OK) | ||
632 | { | ||
633 | printf ("sieve_register_parse_error() returns %d\n", res); | ||
634 | exit (1); | ||
635 | } | ||
636 | res = sieve_register_execute_error (i, &sv_execute_error); | ||
637 | if (res != SIEVE_OK) | ||
638 | { | ||
639 | printf ("sieve_register_execute_error() returns %d\n", res); | ||
640 | exit (1); | ||
641 | } | ||
642 | res = sieve_register_summary (i, &sv_summary); | ||
643 | if (res != SIEVE_OK) | ||
644 | { | ||
645 | printf ("sieve_register_summary() returns %d\n", res); | ||
646 | exit (1); | ||
647 | } | ||
648 | return res; | ||
649 | } | ||
650 | |||
651 | const char USAGE[] = "usage: sieve [-hnvcd] [-f mbox] script\n"; | ||
652 | |||
653 | const char HELP[] = | ||
654 | " -h print this helpful message and exit.\n" | ||
655 | " -n no actions taken, implies -v.\n" | ||
656 | " -v verbose, print actions to be taken.\n" | ||
657 | " -c compile script but don't run it against an mbox.\n" | ||
658 | " -d daemon mode, sieve mbox, then go into background and sieve.\n" | ||
659 | " new message as they are delivered to mbox.\n" | ||
660 | " -f the mbox to sieve, defaults to the users spool file.\n"; | ||
661 | |||
662 | int | ||
663 | main (int argc, char *argv[]) | ||
664 | { | ||
665 | list_t bookie = 0; | ||
666 | mailbox_t mbox = 0; | ||
667 | |||
668 | sieve_interp_t *interp; | ||
669 | sieve_script_t *script; | ||
670 | |||
671 | sv_interp_ctx_t ic = { 0, }; | ||
672 | sv_script_ctx_t sc = { 0, }; | ||
673 | |||
674 | size_t count = 0; | ||
675 | int i = 0; | ||
676 | |||
677 | int res; | ||
678 | FILE *f = 0; | ||
679 | |||
680 | int opt; | ||
681 | |||
682 | while ((opt = getopt (argc, argv, "hnvcdf:")) != -1) | ||
683 | { | ||
684 | switch (opt) | ||
685 | { | ||
686 | case 'h': | ||
687 | printf ("%s\n%s", USAGE, HELP); | ||
688 | return 0; | ||
689 | case 'n': | ||
690 | ic.opt_no_actions = 1; | ||
691 | case 'v': | ||
692 | ic.opt_verbose++; | ||
693 | break; | ||
694 | case 'c': | ||
695 | ic.opt_no_run = 1; | ||
696 | break; | ||
697 | case 'f': | ||
698 | ic.opt_mbox = optarg; | ||
699 | break; | ||
700 | case 'd': | ||
701 | ic.opt_watch = 1; | ||
702 | break; | ||
703 | default: | ||
704 | fprintf (stderr, "%s", USAGE); | ||
705 | return 1; | ||
706 | } | ||
707 | } | ||
708 | if (!argv[optind]) | ||
709 | { | ||
710 | fprintf (stderr, "%s", USAGE); | ||
711 | return 1; | ||
712 | } | ||
713 | ic.opt_script = argv[optind]; | ||
714 | |||
715 | registrar_get_list (&bookie); | ||
716 | list_append (bookie, path_record); | ||
717 | list_append (bookie, file_record); | ||
718 | list_append (bookie, mbox_record); | ||
719 | list_append (bookie, pop_record); | ||
720 | list_append (bookie, imap_record); | ||
721 | |||
722 | if (!ic.opt_no_run && (res = mailbox_create_default (&mbox, ic.opt_mbox)) != 0) | ||
723 | { | ||
724 | fprintf (stderr, "mailbox create <%s> failed: %s\n", | ||
725 | ic.opt_mbox ? ic.opt_mbox : "default", strerror (res)); | ||
726 | return 1; | ||
727 | } | ||
728 | if (ic.opt_verbose > 2) | ||
729 | { | ||
730 | if ((res = debug_create(&ic.debug, &ic))) | ||
731 | { | ||
732 | fprintf (stderr, "debug_create failed: %s\n", strerror(res)); | ||
733 | return 1; | ||
734 | } | ||
735 | if ((res = debug_set_level (ic.debug, MU_DEBUG_TRACE | MU_DEBUG_PROT))) | ||
736 | { | ||
737 | fprintf (stderr, "debug_set_level failed: %s\n", strerror(res)); | ||
738 | return 1; | ||
739 | } | ||
740 | if ((res = debug_set_print (ic.debug, sv_mu_debug_print, &ic))) | ||
741 | { | ||
742 | fprintf (stderr, "debug_set_print failed: %s\n", strerror(res)); | ||
743 | return 1; | ||
744 | } | ||
745 | mailbox_set_debug (mbox, ic.debug); | ||
746 | } | ||
747 | if (ic.opt_no_actions) | ||
748 | res = mailbox_open (mbox, MU_STREAM_READ); | ||
749 | else | ||
750 | res = mailbox_open (mbox, MU_STREAM_RDWR); | ||
751 | |||
752 | if (res != 0) | ||
753 | { | ||
754 | fprintf (stderr, "mailbox open <%s> failed: %s\n", | ||
755 | ic.opt_mbox ? ic.opt_mbox : "default", strerror (res)); | ||
756 | exit (1); | ||
757 | } | ||
758 | res = sieve_interp_alloc (&interp, &ic); | ||
759 | |||
760 | if (res != SIEVE_OK) | ||
761 | { | ||
762 | fprintf (stderr, "sieve_interp_alloc() returns %d\n", res); | ||
763 | return 1; | ||
764 | } | ||
765 | res = sieve_register_mailutils (interp); | ||
766 | |||
767 | f = fopen (ic.opt_script, "r"); | ||
768 | |||
769 | if (!f) | ||
770 | { | ||
771 | printf ("fopen %s failed: %s\n", argv[2], strerror (errno)); | ||
772 | return 1; | ||
773 | } | ||
774 | res = sieve_script_parse (interp, f, &sc, &script); | ||
775 | if (res != SIEVE_OK) | ||
776 | { | ||
777 | printf ("script parse failed: %s\n", str_sieve_error (res)); | ||
778 | return 1; | ||
779 | } | ||
780 | fclose (f); | ||
781 | |||
782 | if (ic.opt_no_run) | ||
783 | return 0; | ||
784 | |||
785 | mailbox_messages_count (mbox, &count); | ||
786 | if (ic.opt_verbose) | ||
787 | { | ||
788 | fprintf (stderr, "mbox has %d messages...\n", count); | ||
789 | } | ||
790 | for (i = 1; i <= count; ++i) | ||
791 | { | ||
792 | sv_msg_ctx_t mc = { 0, }; | ||
793 | |||
794 | mc.mbox = mbox; | ||
795 | |||
796 | if ((res = mailbox_get_message (mbox, i, &mc.msg)) != 0) | ||
797 | { | ||
798 | fprintf (stderr, "mailbox_get_message(%d): %s\n", i, | ||
799 | strerror (res)); | ||
800 | exit (1); | ||
801 | } | ||
802 | res = sieve_execute_script (script, &mc); | ||
803 | |||
804 | if (ic.opt_verbose) | ||
805 | fprintf (stderr, "%s\n", mc.summary); | ||
806 | |||
807 | if (res != SIEVE_OK) | ||
808 | { | ||
809 | printf ("sieve_execute_script(%d): sieve %d rc %s\n", | ||
810 | i, res, strerror (mc.rc)); | ||
811 | exit (1); | ||
812 | } | ||
813 | sv_field_cache_release (&mc.cache); | ||
814 | free (mc.summary); | ||
815 | } | ||
816 | res = sieve_script_free (&script); | ||
817 | |||
818 | if (res != SIEVE_OK) | ||
819 | { | ||
820 | printf ("sieve_script_free() returns %d\n", res); | ||
821 | exit (1); | ||
822 | } | ||
823 | res = sieve_interp_free (&interp); | ||
824 | |||
825 | if (res != SIEVE_OK) | ||
826 | { | ||
827 | printf ("sieve_interp_free() returns %d\n", res); | ||
828 | exit (1); | ||
829 | } | ||
830 | if (!ic.opt_no_actions) | ||
831 | res = mailbox_expunge (mbox); | ||
832 | |||
833 | if (res != 0) | ||
834 | { | ||
835 | printf ("mailbox_expunge failed: %s\n", strerror (res)); | ||
836 | exit (1); | ||
837 | } | ||
838 | if (res == 0) | ||
839 | mailbox_close (mbox); | ||
840 | |||
841 | mailbox_destroy (&mbox); | ||
842 | |||
843 | return 0; | ||
844 | } | ||
845 | |||
846 | void | ||
847 | fatal (char *message, int rc) | ||
848 | { | ||
849 | fprintf (stderr, "fatal error: %s\n", message); | ||
850 | exit (rc); | ||
851 | } | ||
852 |
sieve/sieve_err.c
0 → 100644
1 | /* | ||
2 | * sieve_err.c: | ||
3 | * This file is automatically generated; please do not edit it. | ||
4 | */ | ||
5 | #if 0 | ||
6 | |||
7 | #ifdef __STDC__ | ||
8 | #define NOARGS void | ||
9 | #else | ||
10 | #define NOARGS | ||
11 | #define const | ||
12 | #endif | ||
13 | |||
14 | static const char * const text[] = { | ||
15 | "Generic Sieve error", | ||
16 | "Sieve interpretor not finalized", | ||
17 | "Parse error in Sieve script", | ||
18 | "Run-time error during Sieve execution", | ||
19 | "Internal error in Sieve subsystem", | ||
20 | "Memory exhausted in Sieve subsystem", | ||
21 | "Sieve action already taken", | ||
22 | 0 | ||
23 | }; | ||
24 | |||
25 | struct error_table { | ||
26 | char const * const * msgs; | ||
27 | long base; | ||
28 | int n_msgs; | ||
29 | }; | ||
30 | struct et_list { | ||
31 | struct et_list *next; | ||
32 | const struct error_table * table; | ||
33 | }; | ||
34 | extern struct et_list *_et_list; | ||
35 | |||
36 | static const struct error_table et = { text, -1237848064L, 7 }; | ||
37 | |||
38 | static struct et_list link = { 0, 0 }; | ||
39 | #endif | ||
40 | |||
41 | void initialize_siev_error_table (NOARGS) { | ||
42 | #if 0 | ||
43 | if (!link.table) { | ||
44 | link.next = _et_list; | ||
45 | link.table = &et; | ||
46 | _et_list = &link; | ||
47 | } | ||
48 | #endif | ||
49 | } | ||
50 |
sieve/sieve_err.h
0 → 100644
1 | /* | ||
2 | * sieve_err.h: | ||
3 | * This file is automatically generated; please do not edit it. | ||
4 | */ | ||
5 | #define SIEVE_FAIL (-1237848064L) | ||
6 | #define SIEVE_NOT_FINALIZED (-1237848063L) | ||
7 | #define SIEVE_PARSE_ERROR (-1237848062L) | ||
8 | #define SIEVE_RUN_ERROR (-1237848061L) | ||
9 | #define SIEVE_INTERNAL_ERROR (-1237848060L) | ||
10 | #define SIEVE_NOMEM (-1237848059L) | ||
11 | #define SIEVE_DONE (-1237848058L) | ||
12 | extern void initialize_siev_error_table (); | ||
13 | #define ERROR_TABLE_BASE_siev (-1237848064L) | ||
14 | |||
15 | /* for compatibility with older versions... */ | ||
16 | #define init_siev_err_tbl initialize_siev_error_table | ||
17 | #define siev_err_base ERROR_TABLE_BASE_siev |
sieve/sieve_interface.h
0 → 100644
1 | /* sieve_interface.h -- interface for deliver | ||
2 | * $Id$ | ||
3 | */ | ||
4 | /*********************************************************** | ||
5 | Copyright 1999 by Carnegie Mellon University | ||
6 | |||
7 | All Rights Reserved | ||
8 | |||
9 | Permission to use, copy, modify, and distribute this software and its | ||
10 | documentation for any purpose and without fee is hereby granted, | ||
11 | provided that the above copyright notice appear in all copies and that | ||
12 | both that copyright notice and this permission notice appear in | ||
13 | supporting documentation, and that the name of Carnegie Mellon | ||
14 | University not be used in advertising or publicity pertaining to | ||
15 | distribution of the software without specific, written prior | ||
16 | permission. | ||
17 | |||
18 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
19 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
20 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
21 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
22 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
23 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
24 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
25 | ******************************************************************/ | ||
26 | |||
27 | #ifndef SIEVE_H | ||
28 | #define SIEVE_H | ||
29 | |||
30 | #include <stdio.h> | ||
31 | |||
32 | extern const char *sieve_version; | ||
33 | |||
34 | /* error codes */ | ||
35 | #define SIEVE_OK (0) | ||
36 | |||
37 | #include <sieve_err.h> | ||
38 | |||
39 | /* external sieve types */ | ||
40 | typedef struct sieve_interp sieve_interp_t; | ||
41 | typedef struct sieve_script sieve_script_t; | ||
42 | |||
43 | typedef int sieve_callback(void *action_context, void *interp_context, | ||
44 | void *script_context, | ||
45 | void *message_context, const char **errmsg); | ||
46 | typedef int sieve_get_size(void *message_context, int *size); | ||
47 | typedef int sieve_get_header(void *message_context, | ||
48 | const char *header, | ||
49 | const char ***contents); | ||
50 | typedef int sieve_get_envelope(void *message_context, | ||
51 | const char *field, | ||
52 | const char ***contents); | ||
53 | |||
54 | typedef struct sieve_vacation { | ||
55 | int min_response; /* 0 -> defaults to 3 */ | ||
56 | int max_response; /* 0 -> defaults to 90 */ | ||
57 | |||
58 | /* given a hash, say whether we've already responded to it in the last | ||
59 | days days. return SIEVE_OK if we SHOULD autorespond (have not already) | ||
60 | or SIEVE_DONE if we SHOULD NOT. */ | ||
61 | sieve_callback *autorespond; | ||
62 | |||
63 | /* mail the response */ | ||
64 | sieve_callback *send_response; | ||
65 | } sieve_vacation_t; | ||
66 | |||
67 | typedef struct sieve_imapflags { | ||
68 | char **flag; /* NULL -> defaults to \flagged */ | ||
69 | int nflags; | ||
70 | } sieve_imapflags_t; | ||
71 | |||
72 | typedef struct sieve_redirect_context { | ||
73 | char *addr; | ||
74 | } sieve_redirect_context_t; | ||
75 | |||
76 | typedef struct sieve_reject_context { | ||
77 | char *msg; | ||
78 | } sieve_reject_context_t; | ||
79 | |||
80 | typedef struct sieve_fileinto_context { | ||
81 | char *mailbox; | ||
82 | sieve_imapflags_t *imapflags; | ||
83 | } sieve_fileinto_context_t; | ||
84 | |||
85 | typedef struct sieve_keep_context { | ||
86 | sieve_imapflags_t *imapflags; | ||
87 | } sieve_keep_context_t; | ||
88 | |||
89 | typedef struct sieve_notify_context { | ||
90 | const char *priority; | ||
91 | char *message; | ||
92 | } sieve_notify_context_t; | ||
93 | |||
94 | typedef struct sieve_autorespond_context { | ||
95 | unsigned char *hash; | ||
96 | int len; | ||
97 | int days; | ||
98 | } sieve_autorespond_context_t; | ||
99 | |||
100 | typedef struct sieve_send_response_context { | ||
101 | char *addr; | ||
102 | char *fromaddr; | ||
103 | char *subj; | ||
104 | char *msg; | ||
105 | int mime; | ||
106 | } sieve_send_response_context_t; | ||
107 | |||
108 | /* build a sieve interpretor */ | ||
109 | int sieve_interp_alloc(sieve_interp_t **interp, void *interp_context); | ||
110 | int sieve_interp_free(sieve_interp_t **interp); | ||
111 | |||
112 | /* add the callbacks for actions. undefined behavior results if these | ||
113 | are called after sieve_script_parse is called! */ | ||
114 | int sieve_register_redirect(sieve_interp_t *interp, sieve_callback *f); | ||
115 | int sieve_register_discard(sieve_interp_t *interp, sieve_callback *f); | ||
116 | int sieve_register_reject(sieve_interp_t *interp, sieve_callback *f); | ||
117 | int sieve_register_fileinto(sieve_interp_t *interp, sieve_callback *f); | ||
118 | int sieve_register_keep(sieve_interp_t *interp, sieve_callback *f); | ||
119 | int sieve_register_vacation(sieve_interp_t *interp, sieve_vacation_t *v); | ||
120 | int sieve_register_imapflags(sieve_interp_t *interp, sieve_imapflags_t *mark); | ||
121 | int sieve_register_notify(sieve_interp_t *interp, sieve_callback *f); | ||
122 | |||
123 | /* add the callbacks for messages. again, undefined if used after | ||
124 | sieve_script_parse */ | ||
125 | int sieve_register_size(sieve_interp_t *interp, sieve_get_size *f); | ||
126 | int sieve_register_header(sieve_interp_t *interp, sieve_get_header *f); | ||
127 | int sieve_register_envelope(sieve_interp_t *interp, sieve_get_envelope *f); | ||
128 | |||
129 | typedef int sieve_parse_error(int lineno, const char *msg, | ||
130 | void *interp_context, | ||
131 | void *script_context); | ||
132 | int sieve_register_parse_error(sieve_interp_t *interp, sieve_parse_error *f); | ||
133 | |||
134 | typedef int sieve_execute_error(const char *msg, void *interp_context, | ||
135 | void *script_context, void *message_context); | ||
136 | int sieve_register_execute_error(sieve_interp_t *interp, | ||
137 | sieve_execute_error *f); | ||
138 | int sieve_register_summary(sieve_interp_t *interp, | ||
139 | sieve_execute_error *f); | ||
140 | |||
141 | /* given an interpretor and a script, produce an executable script */ | ||
142 | int sieve_script_parse(sieve_interp_t *interp, FILE *script, | ||
143 | void *script_context, sieve_script_t **ret); | ||
144 | |||
145 | int sieve_script_free(sieve_script_t **s); | ||
146 | |||
147 | /* execute a script on a message, producing side effects via callbacks */ | ||
148 | int sieve_execute_script(sieve_script_t *script, | ||
149 | void *message_context); | ||
150 | |||
151 | /* Get space separated list of extensions supported by the implementation */ | ||
152 | const char *sieve_listextensions(void); | ||
153 | |||
154 | #endif |
sieve/svfield.c
0 → 100644
1 | /* | ||
2 | * sieve header field cache. | ||
3 | */ | ||
4 | |||
5 | #ifdef HAVE_CONFIG_H | ||
6 | #include <config.h> | ||
7 | #endif | ||
8 | |||
9 | #include <ctype.h> | ||
10 | #include <errno.h> | ||
11 | #include <stdlib.h> | ||
12 | #include <string.h> | ||
13 | |||
14 | #ifdef HAVE_STRINGS_H | ||
15 | #include <strings.h> | ||
16 | #endif | ||
17 | |||
18 | #include "svfield.h" | ||
19 | |||
20 | static int | ||
21 | sv_hash_field_name (const char *name) | ||
22 | { | ||
23 | int x = 0; | ||
24 | /* all CHAR up to the first that is ' ', :, or a ctrl char */ | ||
25 | for (; !iscntrl (*name) && (*name != ' ') && (*name != ':'); name++) | ||
26 | { | ||
27 | x *= 256; | ||
28 | x += tolower (*name); | ||
29 | x %= SV_FIELD_CACHE_SIZE; | ||
30 | } | ||
31 | return x; | ||
32 | } | ||
33 | |||
34 | /* | ||
35 | The body is kept, the name is still the caller's. | ||
36 | */ | ||
37 | int | ||
38 | sv_field_cache_add (sv_field_cache_t * m, const char *name, char *body) | ||
39 | { | ||
40 | int cl, clinit; | ||
41 | |||
42 | /* put it in the hash table */ | ||
43 | clinit = cl = sv_hash_field_name (name); | ||
44 | |||
45 | while (m->cache[cl] != NULL && strcasecmp (name, m->cache[cl]->name)) | ||
46 | { | ||
47 | cl++; /* resolve collisions linearly */ | ||
48 | cl %= SV_FIELD_CACHE_SIZE; | ||
49 | if (cl == clinit) | ||
50 | break; /* gone all the way around, so bail */ | ||
51 | } | ||
52 | |||
53 | /* found where to put it, so insert it into a list */ | ||
54 | if (m->cache[cl]) | ||
55 | { | ||
56 | /* add this body on */ | ||
57 | |||
58 | m->cache[cl]->contents[m->cache[cl]->ncontents++] = body; | ||
59 | |||
60 | /* whoops, won't have room for the null at the end! */ | ||
61 | if (!(m->cache[cl]->ncontents % 8)) | ||
62 | { | ||
63 | /* increase the size */ | ||
64 | sv_field_t* field = (sv_field_t *) realloc ( | ||
65 | m->cache[cl], | ||
66 | sizeof(sv_field_t) + | ||
67 | ((8 + m->cache[cl]->ncontents) * sizeof(char *)) | ||
68 | ); | ||
69 | if (field == NULL) | ||
70 | { | ||
71 | return ENOMEM; | ||
72 | } | ||
73 | m->cache[cl] = field; | ||
74 | } | ||
75 | } | ||
76 | else | ||
77 | { | ||
78 | /* create a new entry in the hash table */ | ||
79 | sv_field_t* field = (sv_field_t *) malloc (sizeof (sv_field_t) + | ||
80 | 8 * sizeof (char *)); | ||
81 | if (field) | ||
82 | { | ||
83 | return ENOMEM; | ||
84 | } | ||
85 | m->cache[cl] = field; | ||
86 | m->cache[cl]->name = strdup (name); | ||
87 | m->cache[cl]->contents[0] = body; | ||
88 | m->cache[cl]->ncontents = 1; | ||
89 | } | ||
90 | |||
91 | /* we always want a NULL at the end */ | ||
92 | m->cache[cl]->contents[m->cache[cl]->ncontents] = NULL; | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | int | ||
98 | sv_field_cache_get (sv_field_cache_t * m, | ||
99 | const char *name, const char ***body) | ||
100 | { | ||
101 | int rc = ENOENT; | ||
102 | int clinit, cl; | ||
103 | |||
104 | clinit = cl = sv_hash_field_name (name); | ||
105 | |||
106 | while (m->cache[cl] != NULL) | ||
107 | { | ||
108 | if (strcasecmp (name, m->cache[cl]->name) == 0) | ||
109 | { | ||
110 | *body = (const char **) m->cache[cl]->contents; | ||
111 | rc = 0; | ||
112 | break; | ||
113 | } | ||
114 | cl++; /* try next hash bin */ | ||
115 | cl %= SV_FIELD_CACHE_SIZE; | ||
116 | if (cl == clinit) | ||
117 | break; /* gone all the way around */ | ||
118 | } | ||
119 | |||
120 | return rc; | ||
121 | } | ||
122 | |||
123 | void | ||
124 | sv_field_cache_release (sv_field_cache_t * m) | ||
125 | { | ||
126 | int i; | ||
127 | for (i = 0; i < SV_FIELD_CACHE_SIZE; i++) | ||
128 | { | ||
129 | if (m->cache[i]) | ||
130 | { | ||
131 | int j; | ||
132 | for (j = 0; m->cache[i]->contents[j]; j++) | ||
133 | { | ||
134 | free (m->cache[i]->contents[j]); | ||
135 | } | ||
136 | free (m->cache[i]); | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 |
sieve/svfield.h
0 → 100644
1 | /* | ||
2 | * sieve field cache. | ||
3 | */ | ||
4 | |||
5 | #ifndef SVFIELD_H | ||
6 | #define SVFIELD_H | ||
7 | |||
8 | #define SV_FIELD_CACHE_SIZE 1019 | ||
9 | |||
10 | typedef struct sv_field_t | ||
11 | { | ||
12 | char *name; | ||
13 | int ncontents; | ||
14 | char *contents[1]; | ||
15 | } | ||
16 | sv_field_t; | ||
17 | |||
18 | typedef struct sv_field_cache_t | ||
19 | { | ||
20 | sv_field_t *cache[SV_FIELD_CACHE_SIZE]; | ||
21 | } | ||
22 | sv_field_cache_t; | ||
23 | |||
24 | extern int sv_field_cache_add (sv_field_cache_t* m, const char *name, char *body); | ||
25 | extern int sv_field_cache_get (sv_field_cache_t* m, const char *name, const char ***body); | ||
26 | extern void sv_field_cache_release (sv_field_cache_t* m); | ||
27 | |||
28 | #endif | ||
29 |
sieve/sysexits.h
0 → 100644
1 | /* | ||
2 | * Copyright (c) 2000 Carnegie Mellon University. All rights reserved. | ||
3 | * | ||
4 | * Redistribution and use in source and binary forms, with or without | ||
5 | * modification, are permitted provided that the following conditions | ||
6 | * are met: | ||
7 | * | ||
8 | * 1. Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in | ||
13 | * the documentation and/or other materials provided with the | ||
14 | * distribution. | ||
15 | * | ||
16 | * 3. The name "Carnegie Mellon University" must not be used to | ||
17 | * endorse or promote products derived from this software without | ||
18 | * prior written permission. For permission or any other legal | ||
19 | * details, please contact | ||
20 | * Office of Technology Transfer | ||
21 | * Carnegie Mellon University | ||
22 | * 5000 Forbes Avenue | ||
23 | * Pittsburgh, PA 15213-3890 | ||
24 | * (412) 268-4387, fax: (412) 268-7395 | ||
25 | * tech-transfer@andrew.cmu.edu | ||
26 | * | ||
27 | * 4. Redistributions of any form whatsoever must retain the following | ||
28 | * acknowledgment: | ||
29 | * "This product includes software developed by Computing Services | ||
30 | * at Carnegie Mellon University (http://www.cmu.edu/computing/)." | ||
31 | * | ||
32 | * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
33 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
34 | * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE | ||
35 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
36 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | ||
37 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | ||
38 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
39 | * | ||
40 | */ | ||
41 | |||
42 | |||
43 | |||
44 | /* | ||
45 | * Copyright (c) 1987, 1993 | ||
46 | * The Regents of the University of California. All rights reserved. | ||
47 | * | ||
48 | * Redistribution and use in source and binary forms, with or without | ||
49 | * modification, are permitted provided that the following conditions | ||
50 | * are met: | ||
51 | * 1. Redistributions of source code must retain the above copyright | ||
52 | * notice, this list of conditions and the following disclaimer. | ||
53 | * 2. Redistributions in binary form must reproduce the above copyright | ||
54 | * notice, this list of conditions and the following disclaimer in the | ||
55 | * documentation and/or other materials provided with the distribution. | ||
56 | * 3. All advertising materials mentioning features or use of this software | ||
57 | * must display the following acknowledgement: | ||
58 | * This product includes software developed by the University of | ||
59 | * California, Berkeley and its contributors. | ||
60 | * 4. Neither the name of the University nor the names of its contributors | ||
61 | * may be used to endorse or promote products derived from this software | ||
62 | * without specific prior written permission. | ||
63 | * | ||
64 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
65 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
66 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
67 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
68 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
69 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
70 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
71 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
72 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
73 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
74 | * SUCH DAMAGE. | ||
75 | * | ||
76 | * @(#)sysexits.h 8.1 (Berkeley) 6/2/93 | ||
77 | */ | ||
78 | |||
79 | #ifndef _SYSEXITS_H_ | ||
80 | #define _SYSEXITS_H_ | ||
81 | |||
82 | /* | ||
83 | * SYSEXITS.H -- Exit status codes for system programs. | ||
84 | * | ||
85 | * This include file attempts to categorize possible error | ||
86 | * exit statuses for system programs, notably delivermail | ||
87 | * and the Berkeley network. | ||
88 | * | ||
89 | * Error numbers begin at EX__BASE to reduce the possibility of | ||
90 | * clashing with other exit statuses that random programs may | ||
91 | * already return. The meaning of the codes is approximately | ||
92 | * as follows: | ||
93 | * | ||
94 | * EX_USAGE -- The command was used incorrectly, e.g., with | ||
95 | * the wrong number of arguments, a bad flag, a bad | ||
96 | * syntax in a parameter, or whatever. | ||
97 | * EX_DATAERR -- The input data was incorrect in some way. | ||
98 | * This should only be used for user's data & not | ||
99 | * system files. | ||
100 | * EX_NOINPUT -- An input file (not a system file) did not | ||
101 | * exist or was not readable. This could also include | ||
102 | * errors like "No message" to a mailer (if it cared | ||
103 | * to catch it). | ||
104 | * EX_NOUSER -- The user specified did not exist. This might | ||
105 | * be used for mail addresses or remote logins. | ||
106 | * EX_NOHOST -- The host specified did not exist. This is used | ||
107 | * in mail addresses or network requests. | ||
108 | * EX_UNAVAILABLE -- A service is unavailable. This can occur | ||
109 | * if a support program or file does not exist. This | ||
110 | * can also be used as a catchall message when something | ||
111 | * you wanted to do doesn't work, but you don't know | ||
112 | * why. | ||
113 | * EX_SOFTWARE -- An internal software error has been detected. | ||
114 | * This should be limited to non-operating system related | ||
115 | * errors as possible. | ||
116 | * EX_OSERR -- An operating system error has been detected. | ||
117 | * This is intended to be used for such things as "cannot | ||
118 | * fork", "cannot create pipe", or the like. It includes | ||
119 | * things like getuid returning a user that does not | ||
120 | * exist in the passwd file. | ||
121 | * EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp, | ||
122 | * etc.) does not exist, cannot be opened, or has some | ||
123 | * sort of error (e.g., syntax error). | ||
124 | * EX_CANTCREAT -- A (user specified) output file cannot be | ||
125 | * created. | ||
126 | * EX_IOERR -- An error occurred while doing I/O on some file. | ||
127 | * EX_TEMPFAIL -- temporary failure, indicating something that | ||
128 | * is not really an error. In sendmail, this means | ||
129 | * that a mailer (e.g.) could not create a connection, | ||
130 | * and the request should be reattempted later. | ||
131 | * EX_PROTOCOL -- the remote system returned something that | ||
132 | * was "not possible" during a protocol exchange. | ||
133 | * EX_NOPERM -- You did not have sufficient permission to | ||
134 | * perform the operation. This is not intended for | ||
135 | * file system problems, which should use NOINPUT or | ||
136 | * CANTCREAT, but rather for higher level permissions. | ||
137 | */ | ||
138 | |||
139 | #define EX_OK 0 /* successful termination */ | ||
140 | |||
141 | #define EX__BASE 64 /* base value for error messages */ | ||
142 | |||
143 | #define EX_USAGE 64 /* command line usage error */ | ||
144 | #define EX_DATAERR 65 /* data format error */ | ||
145 | #define EX_NOINPUT 66 /* cannot open input */ | ||
146 | #define EX_NOUSER 67 /* addressee unknown */ | ||
147 | #define EX_NOHOST 68 /* host name unknown */ | ||
148 | #define EX_UNAVAILABLE 69 /* service unavailable */ | ||
149 | #define EX_SOFTWARE 70 /* internal software error */ | ||
150 | #define EX_OSERR 71 /* system error (e.g., can't fork) */ | ||
151 | #define EX_OSFILE 72 /* critical OS file missing */ | ||
152 | #define EX_CANTCREAT 73 /* can't create (user) output file */ | ||
153 | #define EX_IOERR 74 /* input/output error */ | ||
154 | #define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */ | ||
155 | #define EX_PROTOCOL 76 /* remote error in protocol */ | ||
156 | #define EX_NOPERM 77 /* permission denied */ | ||
157 | #define EX_CONFIG 78 /* configuration error */ | ||
158 | |||
159 | #define EX__MAX 78 /* maximum listed value */ | ||
160 | |||
161 | #endif /* !_SYSEXITS_H_ */ |
sieve/test.c
0 → 100644
1 | /* test.c -- tester for libsieve | ||
2 | * Larry Greenfield | ||
3 | * $Id$ | ||
4 | * | ||
5 | * usage: "test message script" | ||
6 | */ | ||
7 | /*********************************************************** | ||
8 | Copyright 1999 by Carnegie Mellon University | ||
9 | |||
10 | All Rights Reserved | ||
11 | |||
12 | Permission to use, copy, modify, and distribute this software and its | ||
13 | documentation for any purpose and without fee is hereby granted, | ||
14 | provided that the above copyright notice appear in all copies and that | ||
15 | both that copyright notice and this permission notice appear in | ||
16 | supporting documentation, and that the name of Carnegie Mellon | ||
17 | University not be used in advertising or publicity pertaining to | ||
18 | distribution of the software without specific, written prior | ||
19 | permission. | ||
20 | |||
21 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
22 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
23 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
24 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
25 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
26 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
27 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
28 | ******************************************************************/ | ||
29 | |||
30 | #ifdef HAVE_CONFIG_H | ||
31 | #include <config.h> | ||
32 | #endif | ||
33 | |||
34 | #include <stdio.h> | ||
35 | #include <sys/stat.h> | ||
36 | #include <unistd.h> | ||
37 | #include <sys/types.h> | ||
38 | #include <sys/stat.h> | ||
39 | #include <fcntl.h> | ||
40 | #include <ctype.h> | ||
41 | #include <string.h> | ||
42 | #include <stdlib.h> | ||
43 | |||
44 | #include "sieve_interface.h" | ||
45 | |||
46 | #define HEADERCACHESIZE 1019 | ||
47 | |||
48 | typedef struct Header { | ||
49 | char *name; | ||
50 | int ncontents; | ||
51 | char *contents[1]; | ||
52 | } header_t; | ||
53 | |||
54 | typedef struct message_data { | ||
55 | char *name; | ||
56 | FILE *data; | ||
57 | int size; | ||
58 | |||
59 | int cache_full; | ||
60 | header_t *cache[HEADERCACHESIZE]; | ||
61 | } message_data_t; | ||
62 | |||
63 | int hashheader(char *header) | ||
64 | { | ||
65 | int x = 0; | ||
66 | /* any CHAR except ' ', :, or a ctrl char */ | ||
67 | for (; !iscntrl(*header) && (*header != ' ') && (*header != ':'); | ||
68 | header++) { | ||
69 | x *= 256; | ||
70 | x += *header; | ||
71 | x %= HEADERCACHESIZE; | ||
72 | } | ||
73 | return x; | ||
74 | } | ||
75 | |||
76 | /* take a list of headers, pull the first one out and return it in | ||
77 | name and contents. | ||
78 | |||
79 | returns 0 on success, negative on failure */ | ||
80 | typedef enum { | ||
81 | NAME_START, | ||
82 | NAME, | ||
83 | COLON, | ||
84 | BODY_START, | ||
85 | BODY | ||
86 | } state; | ||
87 | |||
88 | int parseheader(FILE *f, char **headname, char **contents) { | ||
89 | char c; | ||
90 | char name[80], body[1024]; | ||
91 | int off = 0; | ||
92 | state s = NAME_START; | ||
93 | |||
94 | |||
95 | /* there are two ways out of this loop, both via gotos: | ||
96 | either we successfully read a character (got_header) | ||
97 | or we hit an error (ph_error) */ | ||
98 | while ((c = getc(f))) { /* examine each character */ | ||
99 | switch (s) { | ||
100 | case NAME_START: | ||
101 | if (c == '\r' || c == '\n') { | ||
102 | /* no header here! */ | ||
103 | goto ph_error; | ||
104 | } | ||
105 | if (!isalpha(c)) | ||
106 | goto ph_error; | ||
107 | name[0] = tolower(c); | ||
108 | off = 1; | ||
109 | s = NAME; | ||
110 | break; | ||
111 | |||
112 | case NAME: | ||
113 | if (c == ' ' || c == '\t' || c == ':') { | ||
114 | name[off] = '\0'; | ||
115 | s = (c == ':' ? BODY_START : COLON); | ||
116 | break; | ||
117 | } | ||
118 | if (iscntrl(c)) { | ||
119 | goto ph_error; | ||
120 | } | ||
121 | name[off++] = tolower(c); | ||
122 | break; | ||
123 | |||
124 | case COLON: | ||
125 | if (c == ':') { | ||
126 | s = BODY_START; | ||
127 | } else if (c != ' ' && c != '\t') { | ||
128 | goto ph_error; | ||
129 | } | ||
130 | break; | ||
131 | |||
132 | case BODY_START: | ||
133 | if (c == ' ' || c == '\t') /* eat the whitespace */ | ||
134 | break; | ||
135 | off = 0; | ||
136 | s = BODY; | ||
137 | /* falls through! */ | ||
138 | case BODY: | ||
139 | if (c == '\r' || c == '\n') { | ||
140 | int peek = getc(f); | ||
141 | |||
142 | /* we should peek ahead to see if it's folded whitespace */ | ||
143 | if (c == '\r' && peek == '\n') { | ||
144 | c = getc(f); | ||
145 | } else { | ||
146 | c = peek; /* single newline seperator */ | ||
147 | } | ||
148 | if (c != ' ' && c != '\t') { | ||
149 | /* this is the end of the header */ | ||
150 | body[off] = '\0'; | ||
151 | ungetc(c, f); | ||
152 | goto got_header; | ||
153 | } | ||
154 | /* ignore this whitespace, but we'll copy all the rest in */ | ||
155 | break; | ||
156 | } else { | ||
157 | /* just an ordinary character */ | ||
158 | body[off++] = c; | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | |||
163 | /* if we fall off the end of the loop, we hit some sort of error | ||
164 | condition */ | ||
165 | |||
166 | ph_error: | ||
167 | if (headname != NULL) *headname = NULL; | ||
168 | if (contents != NULL) *contents = NULL; | ||
169 | return -1; | ||
170 | |||
171 | got_header: | ||
172 | if (headname != NULL) *headname = strdup(name); | ||
173 | if (contents != NULL) *contents = strdup(body); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | void fill_cache(message_data_t *m) | ||
179 | { | ||
180 | rewind(m->data); | ||
181 | |||
182 | /* let's fill that header cache */ | ||
183 | for (;;) { | ||
184 | char *name, *body; | ||
185 | int cl, clinit; | ||
186 | |||
187 | if (parseheader(m->data, &name, &body) < 0) { | ||
188 | break; | ||
189 | } | ||
190 | |||
191 | /* put it in the hash table */ | ||
192 | clinit = cl = hashheader(name); | ||
193 | while (m->cache[cl] != NULL && strcmp(name, m->cache[cl]->name)) { | ||
194 | cl++; /* resolve collisions linearly */ | ||
195 | cl %= HEADERCACHESIZE; | ||
196 | if (cl == clinit) break; /* gone all the way around, so bail */ | ||
197 | } | ||
198 | |||
199 | /* found where to put it, so insert it into a list */ | ||
200 | if (m->cache[cl]) { | ||
201 | /* add this body on */ | ||
202 | |||
203 | m->cache[cl]->contents[m->cache[cl]->ncontents++] = body; | ||
204 | |||
205 | /* whoops, won't have room for the null at the end! */ | ||
206 | if (!(m->cache[cl]->ncontents % 8)) { | ||
207 | /* increase the size */ | ||
208 | m->cache[cl] = (header_t *) | ||
209 | realloc(m->cache[cl],sizeof(header_t) + | ||
210 | ((8 + m->cache[cl]->ncontents) * sizeof(char *))); | ||
211 | if (m->cache[cl] == NULL) { | ||
212 | fprintf(stderr, "realloc() returned NULL\n"); | ||
213 | exit(1); | ||
214 | } | ||
215 | } | ||
216 | |||
217 | } else { | ||
218 | /* create a new entry in the hash table */ | ||
219 | m->cache[cl] = (header_t *) malloc(sizeof(header_t) + | ||
220 | 8 * sizeof(char*)); | ||
221 | if (m->cache[cl] == NULL) { | ||
222 | fprintf(stderr, "malloc() returned NULL\n"); | ||
223 | exit(1); | ||
224 | } | ||
225 | m->cache[cl]->name = name; | ||
226 | m->cache[cl]->contents[0] = body; | ||
227 | m->cache[cl]->ncontents = 1; | ||
228 | } | ||
229 | |||
230 | /* we always want a NULL at the end */ | ||
231 | m->cache[cl]->contents[m->cache[cl]->ncontents] = NULL; | ||
232 | } | ||
233 | |||
234 | m->cache_full = 1; | ||
235 | } | ||
236 | |||
237 | /* gets the header "head" from msg. */ | ||
238 | int getheader(void *v, const char *phead, const char ***body) | ||
239 | { | ||
240 | message_data_t *m = (message_data_t *) v; | ||
241 | int cl, clinit; | ||
242 | char *h; | ||
243 | char *head; | ||
244 | |||
245 | *body = NULL; | ||
246 | |||
247 | if (!m->cache_full) { | ||
248 | fill_cache(m); | ||
249 | } | ||
250 | |||
251 | /* copy header parameter so we can mangle it */ | ||
252 | head = malloc(strlen(phead)+1); | ||
253 | if (!head) return SIEVE_FAIL; | ||
254 | strcpy(head, phead); | ||
255 | |||
256 | h = head; | ||
257 | while (*h != '\0') { | ||
258 | *h = tolower(*h); | ||
259 | h++; | ||
260 | } | ||
261 | |||
262 | /* check the cache */ | ||
263 | clinit = cl = hashheader(head); | ||
264 | while (m->cache[cl] != NULL) { | ||
265 | if (!strcmp(head, m->cache[cl]->name)) { | ||
266 | *body = (const char **) m->cache[cl]->contents; | ||
267 | break; | ||
268 | } | ||
269 | cl++; /* try next hash bin */ | ||
270 | cl %= HEADERCACHESIZE; | ||
271 | if (cl == clinit) break; /* gone all the way around */ | ||
272 | } | ||
273 | |||
274 | free(head); | ||
275 | |||
276 | if (*body) { | ||
277 | return SIEVE_OK; | ||
278 | } else { | ||
279 | return SIEVE_FAIL; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | message_data_t *new_msg(FILE *msg, int size, char *name) | ||
284 | { | ||
285 | int i; | ||
286 | message_data_t *m; | ||
287 | |||
288 | m = (message_data_t *) malloc(sizeof(message_data_t)); | ||
289 | if (m == NULL) { | ||
290 | fprintf(stderr, "malloc() returned NULL\n"); | ||
291 | exit(1); | ||
292 | } | ||
293 | m->data = msg; | ||
294 | m->size = size; | ||
295 | m->name = name; | ||
296 | for (i = 0; i < HEADERCACHESIZE; i++) { | ||
297 | m->cache[i] = NULL; | ||
298 | } | ||
299 | m->cache_full = 0; | ||
300 | |||
301 | return m; | ||
302 | } | ||
303 | |||
304 | int getsize(void *mc, int *size) | ||
305 | { | ||
306 | message_data_t *m = (message_data_t *) mc; | ||
307 | |||
308 | *size = m->size; | ||
309 | return SIEVE_OK; | ||
310 | } | ||
311 | |||
312 | int getenvelope(void *v, const char *head, const char ***body) | ||
313 | { | ||
314 | static char *buf[2]; | ||
315 | |||
316 | if (buf[0] == NULL) { buf[0] = malloc(sizeof(char) * 256); buf[1] = NULL; } | ||
317 | printf("Envelope body of '%s'? ", head); | ||
318 | scanf("%s", buf[0]); | ||
319 | *body = (const char**)buf; | ||
320 | |||
321 | return SIEVE_OK; | ||
322 | } | ||
323 | |||
324 | int redirect(void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
325 | { | ||
326 | sieve_redirect_context_t *rc = (sieve_redirect_context_t *) ac; | ||
327 | message_data_t *m = (message_data_t *) mc; | ||
328 | printf("redirecting message '%s' to '%s'\n", m->name, rc->addr); | ||
329 | return SIEVE_OK; | ||
330 | } | ||
331 | |||
332 | int discard(void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
333 | { | ||
334 | message_data_t *m = (message_data_t *) mc; | ||
335 | printf("discarding message '%s'\n", m->name); | ||
336 | return SIEVE_OK; | ||
337 | } | ||
338 | |||
339 | int reject(void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
340 | { | ||
341 | sieve_reject_context_t *rc = (sieve_reject_context_t *) ac; | ||
342 | message_data_t *m = (message_data_t *) mc; | ||
343 | printf("rejecting message '%s' with '%s'\n", m->name, rc->msg); | ||
344 | return SIEVE_OK; | ||
345 | } | ||
346 | |||
347 | int fileinto(void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
348 | { | ||
349 | sieve_fileinto_context_t *fc = (sieve_fileinto_context_t *) ac; | ||
350 | message_data_t *m = (message_data_t *) mc; | ||
351 | |||
352 | printf("filing message '%s' into '%s'\n", m->name, fc->mailbox); | ||
353 | |||
354 | if (fc->imapflags->flag) { | ||
355 | int n; | ||
356 | printf("\twith flags"); | ||
357 | for (n = 0; n < fc->imapflags->nflags; n++) | ||
358 | printf(" '%s'", fc->imapflags->flag[n]); | ||
359 | printf("\n"); | ||
360 | } | ||
361 | |||
362 | return SIEVE_OK; | ||
363 | } | ||
364 | |||
365 | int keep(void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
366 | { | ||
367 | sieve_keep_context_t *kc = (sieve_keep_context_t *) ac; | ||
368 | message_data_t *m = (message_data_t *) mc; | ||
369 | |||
370 | printf("keeping message '%s'\n", m->name); | ||
371 | |||
372 | if (kc->imapflags->flag) { | ||
373 | int n; | ||
374 | printf("\twith flags"); | ||
375 | for (n = 0; n < kc->imapflags->nflags; n++) | ||
376 | printf(" '%s'", kc->imapflags->flag[n]); | ||
377 | printf("\n"); | ||
378 | } | ||
379 | |||
380 | return SIEVE_OK; | ||
381 | } | ||
382 | |||
383 | int notify(void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
384 | { | ||
385 | sieve_notify_context_t *nc = (sieve_notify_context_t *) ac; | ||
386 | |||
387 | printf("notify msg = '%s' with priority = %s\n",nc->message, nc->priority); | ||
388 | |||
389 | return SIEVE_OK; | ||
390 | } | ||
391 | |||
392 | int mysieve_error(int lineno, const char *msg, void *i, void *s) | ||
393 | { | ||
394 | fprintf(stderr, "line %d: %s\r\n", lineno, msg); | ||
395 | |||
396 | return SIEVE_OK; | ||
397 | } | ||
398 | |||
399 | int mysieve_execute_error(const char *msg, void *i, void *s, void *m) | ||
400 | { | ||
401 | fprintf(stderr, "%s\r\n", msg); | ||
402 | |||
403 | return SIEVE_OK; | ||
404 | } | ||
405 | |||
406 | |||
407 | int autorespond(void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
408 | { | ||
409 | sieve_autorespond_context_t *arc = (sieve_autorespond_context_t *) ac; | ||
410 | char yn; | ||
411 | int i; | ||
412 | |||
413 | printf("Have I already responded to '"); | ||
414 | for (i = 0; i < arc->len; i++) { | ||
415 | printf("%x", arc->hash[i]); | ||
416 | } | ||
417 | printf("' in %d days? ", arc->days); | ||
418 | scanf(" %c", &yn); | ||
419 | |||
420 | if (tolower(yn) == 'y') return SIEVE_DONE; | ||
421 | if (tolower(yn) == 'n') return SIEVE_OK; | ||
422 | |||
423 | return SIEVE_FAIL; | ||
424 | } | ||
425 | |||
426 | int send_response(void *ac, void *ic, void *sc, void *mc, const char **errmsg) | ||
427 | { | ||
428 | sieve_send_response_context_t *src = (sieve_send_response_context_t *) ac; | ||
429 | message_data_t *m = (message_data_t *) mc; | ||
430 | printf("echo '%s' | mail -s '%s' '%s' for message '%s'\n", | ||
431 | src->msg, src->subj, src->addr, m->name); | ||
432 | return SIEVE_OK; | ||
433 | } | ||
434 | |||
435 | sieve_vacation_t vacation = { | ||
436 | 0, /* min response */ | ||
437 | 0, /* max response */ | ||
438 | &autorespond, /* autorespond() */ | ||
439 | &send_response /* send_response() */ | ||
440 | }; | ||
441 | |||
442 | char *markflags[] = { "\\flagged" }; | ||
443 | sieve_imapflags_t mark = { markflags, 1 }; | ||
444 | |||
445 | int main(int argc, char *argv[]) | ||
446 | { | ||
447 | sieve_interp_t *i; | ||
448 | sieve_script_t *s; | ||
449 | message_data_t *m; | ||
450 | FILE *f; | ||
451 | int fd, res; | ||
452 | struct stat sbuf; | ||
453 | |||
454 | if (argc != 3) { | ||
455 | fprintf(stderr, "usage:\n"); | ||
456 | fprintf(stderr, "%s message script\n", argv[0]); | ||
457 | fprintf(stderr, "%s -v script\n", argv[0]); | ||
458 | exit(1); | ||
459 | } | ||
460 | |||
461 | res = sieve_interp_alloc(&i, NULL); | ||
462 | if (res != SIEVE_OK) { | ||
463 | printf("sieve_interp_alloc() returns %d\n", res); | ||
464 | exit(1); | ||
465 | } | ||
466 | |||
467 | res = sieve_register_redirect(i, &redirect); | ||
468 | if (res != SIEVE_OK) { | ||
469 | printf("sieve_register_redirect() returns %d\n", res); | ||
470 | exit(1); | ||
471 | } | ||
472 | res = sieve_register_discard(i, &discard); | ||
473 | if (res != SIEVE_OK) { | ||
474 | printf("sieve_register_discard() returns %d\n", res); | ||
475 | exit(1); | ||
476 | } | ||
477 | res = sieve_register_reject(i, &reject); | ||
478 | if (res != SIEVE_OK) { | ||
479 | printf("sieve_register_reject() returns %d\n", res); | ||
480 | exit(1); | ||
481 | } | ||
482 | res = sieve_register_fileinto(i, &fileinto); | ||
483 | if (res != SIEVE_OK) { | ||
484 | printf("sieve_register_fileinto() returns %d\n", res); | ||
485 | exit(1); | ||
486 | } | ||
487 | res = sieve_register_keep(i, &keep); | ||
488 | if (res != SIEVE_OK) { | ||
489 | printf("sieve_register_keep() returns %d\n", res); | ||
490 | exit(1); | ||
491 | } | ||
492 | |||
493 | res = sieve_register_size(i, &getsize); | ||
494 | if (res != SIEVE_OK) { | ||
495 | printf("sieve_register_size() returns %d\n", res); | ||
496 | exit(1); | ||
497 | } | ||
498 | |||
499 | res = sieve_register_header(i, &getheader); | ||
500 | if (res != SIEVE_OK) { | ||
501 | printf("sieve_register_header() returns %d\n", res); | ||
502 | exit(1); | ||
503 | } | ||
504 | |||
505 | res = sieve_register_envelope(i, &getenvelope); | ||
506 | if (res != SIEVE_OK) { | ||
507 | printf("sieve_register_envelope() returns %d\n", res); | ||
508 | exit(1); | ||
509 | } | ||
510 | |||
511 | res = sieve_register_vacation(i, &vacation); | ||
512 | if (res != SIEVE_OK) { | ||
513 | printf("sieve_register_vacation() returns %d\n", res); | ||
514 | exit(1); | ||
515 | } | ||
516 | |||
517 | res = sieve_register_imapflags(i, &mark); | ||
518 | |||
519 | if (res != SIEVE_OK) { | ||
520 | printf("sieve_register_imapflags() returns %d\n", res); | ||
521 | exit(1); | ||
522 | } | ||
523 | |||
524 | res = sieve_register_notify(i, ¬ify); | ||
525 | if (res != SIEVE_OK) { | ||
526 | printf("sieve_register_notify() returns %d\n", res); | ||
527 | exit(1); | ||
528 | } | ||
529 | |||
530 | res = sieve_register_parse_error(i, &mysieve_error); | ||
531 | if (res != SIEVE_OK) { | ||
532 | printf("sieve_register_parse_error() returns %d\n", res); | ||
533 | exit(1); | ||
534 | } | ||
535 | |||
536 | res = sieve_register_execute_error(i, &mysieve_execute_error); | ||
537 | if (res != SIEVE_OK) { | ||
538 | printf("sieve_register_execute_error() returns %d\n", res); | ||
539 | exit(1); | ||
540 | } | ||
541 | |||
542 | |||
543 | f = fopen(argv[2], "r"); | ||
544 | if (!f) { | ||
545 | printf("can not open script '%s'\n", argv[2]); | ||
546 | exit(1); | ||
547 | } | ||
548 | |||
549 | res = sieve_script_parse(i, f, NULL, &s); | ||
550 | if (res != SIEVE_OK) { | ||
551 | exit(1); | ||
552 | } | ||
553 | |||
554 | fclose(f); | ||
555 | |||
556 | if (strcmp(argv[1], "-v") != 0) { | ||
557 | fd = open(argv[1], O_RDONLY); | ||
558 | res = fstat(fd, &sbuf); | ||
559 | if (res != 0) { | ||
560 | perror("fstat"); | ||
561 | } | ||
562 | |||
563 | m = new_msg(fdopen(fd, "r"), sbuf.st_size, argv[1]); | ||
564 | if (res != SIEVE_OK) { | ||
565 | printf("sieve_msg_parse() returns %d\n", res); | ||
566 | exit(1); | ||
567 | } | ||
568 | |||
569 | res = sieve_execute_script(s, m); | ||
570 | if (res != SIEVE_OK) { | ||
571 | printf("sieve_execute_script() returns %d\n", res); | ||
572 | exit(1); | ||
573 | } | ||
574 | |||
575 | close(fd); | ||
576 | } | ||
577 | |||
578 | res = sieve_script_free(&s); | ||
579 | if (res != SIEVE_OK) { | ||
580 | printf("sieve_script_free() returns %d\n", res); | ||
581 | exit(1); | ||
582 | } | ||
583 | res = sieve_interp_free(&i); | ||
584 | if (res != SIEVE_OK) { | ||
585 | printf("sieve_interp_free() returns %d\n", res); | ||
586 | exit(1); | ||
587 | } | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | void fatal(char* message, int rc) { | ||
593 | fprintf(stderr, "fatal error: %s\n", message); | ||
594 | exit(rc); | ||
595 | } |
sieve/tree.c
0 → 100644
1 | /* tree.c -- abstract syntax tree handling | ||
2 | * Larry Greenfield | ||
3 | * $Id$ | ||
4 | */ | ||
5 | /*********************************************************** | ||
6 | Copyright 1999 by Carnegie Mellon University | ||
7 | |||
8 | All Rights Reserved | ||
9 | |||
10 | Permission to use, copy, modify, and distribute this software and its | ||
11 | documentation for any purpose and without fee is hereby granted, | ||
12 | provided that the above copyright notice appear in all copies and that | ||
13 | both that copyright notice and this permission notice appear in | ||
14 | supporting documentation, and that the name of Carnegie Mellon | ||
15 | University not be used in advertising or publicity pertaining to | ||
16 | distribution of the software without specific, written prior | ||
17 | permission. | ||
18 | |||
19 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
20 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
21 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
22 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
23 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
24 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
25 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
26 | ******************************************************************/ | ||
27 | |||
28 | #ifdef HAVE_CONFIG_H | ||
29 | #include <config.h> | ||
30 | #endif | ||
31 | |||
32 | #include <stdlib.h> | ||
33 | #include "xmalloc.h" | ||
34 | |||
35 | #include "tree.h" | ||
36 | #include "sieve-gram.h" | ||
37 | |||
38 | stringlist_t *new_sl(char *s, stringlist_t *n) | ||
39 | { | ||
40 | stringlist_t *p = (stringlist_t *) xmalloc(sizeof(stringlist_t)); | ||
41 | p->s = s; | ||
42 | p->next = n; | ||
43 | return p; | ||
44 | } | ||
45 | |||
46 | patternlist_t *new_pl(void *pat, patternlist_t *n) | ||
47 | { | ||
48 | patternlist_t *p = (patternlist_t *) xmalloc(sizeof(patternlist_t)); | ||
49 | p->p = pat; | ||
50 | p->next = n; | ||
51 | return p; | ||
52 | } | ||
53 | |||
54 | tag_t *new_tag(int type, char *s) | ||
55 | { | ||
56 | tag_t *p = (tag_t *) xmalloc(sizeof(tag_t)); | ||
57 | p->type = type; | ||
58 | p->arg = s; | ||
59 | return p; | ||
60 | } | ||
61 | |||
62 | taglist_t *new_taglist(tag_t *t, taglist_t *n) | ||
63 | { | ||
64 | taglist_t *p = (taglist_t *) xmalloc(sizeof(taglist_t)); | ||
65 | p->t = t; | ||
66 | p->next = n; | ||
67 | return p; | ||
68 | } | ||
69 | |||
70 | test_t *new_test(int type) | ||
71 | { | ||
72 | test_t *p = (test_t *) xmalloc(sizeof(test_t)); | ||
73 | p->type = type; | ||
74 | return p; | ||
75 | } | ||
76 | |||
77 | testlist_t *new_testlist(test_t *t, testlist_t *n) | ||
78 | { | ||
79 | testlist_t *p = (testlist_t *) xmalloc(sizeof(testlist_t)); | ||
80 | p->t = t; | ||
81 | p->next = n; | ||
82 | return p; | ||
83 | } | ||
84 | |||
85 | commandlist_t *new_command(int type) | ||
86 | { | ||
87 | commandlist_t *p = (commandlist_t *) xmalloc(sizeof(commandlist_t)); | ||
88 | p->type = type; | ||
89 | p->next = NULL; | ||
90 | return p; | ||
91 | } | ||
92 | |||
93 | commandlist_t *new_if(test_t *t, commandlist_t *y, commandlist_t *n) | ||
94 | { | ||
95 | commandlist_t *p = (commandlist_t *) xmalloc(sizeof(commandlist_t)); | ||
96 | p->type = IF; | ||
97 | p->u.i.t = t; | ||
98 | p->u.i.do_then = y; | ||
99 | p->u.i.do_else = n; | ||
100 | p->next = NULL; | ||
101 | return p; | ||
102 | } | ||
103 | |||
104 | void free_sl(stringlist_t *sl) | ||
105 | { | ||
106 | stringlist_t *sl2; | ||
107 | |||
108 | while (sl != NULL) { | ||
109 | sl2 = sl->next; | ||
110 | |||
111 | if (sl->s) free(sl->s); | ||
112 | |||
113 | free(sl); | ||
114 | sl = sl2; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | void free_pl(patternlist_t *pl, int comptag) | ||
119 | { | ||
120 | patternlist_t *pl2; | ||
121 | |||
122 | while (pl != NULL) { | ||
123 | pl2 = pl->next; | ||
124 | |||
125 | if (pl->p) { | ||
126 | #ifdef ENABLE_REGEX | ||
127 | if (comptag == REGEX) { | ||
128 | regfree((regex_t *) pl->p); | ||
129 | } | ||
130 | #endif | ||
131 | free(pl->p); | ||
132 | } | ||
133 | |||
134 | free(pl); | ||
135 | pl = pl2; | ||
136 | } | ||
137 | } | ||
138 | |||
139 | void free_test(test_t *t); | ||
140 | |||
141 | void free_tl(testlist_t *tl) | ||
142 | { | ||
143 | testlist_t *tl2; | ||
144 | |||
145 | while (tl) { | ||
146 | tl2 = tl->next; | ||
147 | |||
148 | if (tl->t) free_test(tl->t); | ||
149 | |||
150 | free(tl); | ||
151 | tl = tl2; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | void free_test(test_t *t) | ||
156 | { | ||
157 | if (t == NULL) return; | ||
158 | |||
159 | switch (t->type) { | ||
160 | case ANYOF: | ||
161 | case ALLOF: | ||
162 | free_tl(t->u.tl); | ||
163 | break; | ||
164 | |||
165 | case EXISTS: | ||
166 | free_sl(t->u.sl); | ||
167 | break; | ||
168 | |||
169 | case SIZE: | ||
170 | case SFALSE: | ||
171 | case STRUE: | ||
172 | break; | ||
173 | |||
174 | case HEADER: | ||
175 | free_sl(t->u.h.sl); | ||
176 | free_pl(t->u.h.pl, t->u.h.comptag); | ||
177 | break; | ||
178 | |||
179 | case ADDRESS: | ||
180 | free_sl(t->u.ae.sl); | ||
181 | free_pl(t->u.ae.pl, t->u.ae.comptag); | ||
182 | break; | ||
183 | |||
184 | case NOT: | ||
185 | free_test(t->u.t); | ||
186 | break; | ||
187 | } | ||
188 | |||
189 | free(t); | ||
190 | } | ||
191 | |||
192 | void free_tree(commandlist_t *cl) | ||
193 | { | ||
194 | commandlist_t *cl2; | ||
195 | |||
196 | while (cl != NULL) { | ||
197 | cl2 = cl->next; | ||
198 | switch (cl->type) { | ||
199 | case IF: | ||
200 | free_test(cl->u.i.t); | ||
201 | free_tree(cl->u.i.do_then); | ||
202 | free_tree(cl->u.i.do_else); | ||
203 | break; | ||
204 | |||
205 | case REJCT: | ||
206 | if (cl->u.str) free(cl->u.str); | ||
207 | break; | ||
208 | |||
209 | case VACATION: | ||
210 | if (cl->u.v.subject) free(cl->u.v.subject); | ||
211 | if (cl->u.v.addresses) free_sl(cl->u.v.addresses); | ||
212 | if (cl->u.v.message) free(cl->u.v.message); | ||
213 | break; | ||
214 | |||
215 | case FILEINTO: | ||
216 | case FORWARD: | ||
217 | case SETFLAG: | ||
218 | case ADDFLAG: | ||
219 | case REMOVEFLAG: | ||
220 | free_sl(cl->u.sl); | ||
221 | break; | ||
222 | |||
223 | case KEEP: | ||
224 | case STOP: | ||
225 | case DISCARD: | ||
226 | break; | ||
227 | } | ||
228 | |||
229 | free(cl); | ||
230 | cl = cl2; | ||
231 | } | ||
232 | } |
sieve/tree.h
0 → 100644
1 | /* tree.h -- abstract syntax tree | ||
2 | * Larry Greenfield | ||
3 | * $Id$ | ||
4 | */ | ||
5 | /*********************************************************** | ||
6 | Copyright 1999 by Carnegie Mellon University | ||
7 | |||
8 | All Rights Reserved | ||
9 | |||
10 | Permission to use, copy, modify, and distribute this software and its | ||
11 | documentation for any purpose and without fee is hereby granted, | ||
12 | provided that the above copyright notice appear in all copies and that | ||
13 | both that copyright notice and this permission notice appear in | ||
14 | supporting documentation, and that the name of Carnegie Mellon | ||
15 | University not be used in advertising or publicity pertaining to | ||
16 | distribution of the software without specific, written prior | ||
17 | permission. | ||
18 | |||
19 | CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
20 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
21 | FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR | ||
22 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
23 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
24 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | ||
25 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
26 | ******************************************************************/ | ||
27 | |||
28 | #ifndef TREE_H | ||
29 | #define TREE_H | ||
30 | |||
31 | #include "comparator.h" | ||
32 | |||
33 | /* abstract syntax tree for sieve */ | ||
34 | typedef struct Stringlist stringlist_t; | ||
35 | typedef struct Patternlist patternlist_t; | ||
36 | typedef struct Commandlist commandlist_t; | ||
37 | typedef struct Test test_t; | ||
38 | typedef struct Testlist testlist_t; | ||
39 | typedef struct Tag tag_t; | ||
40 | typedef struct Taglist taglist_t; | ||
41 | |||
42 | struct Stringlist { | ||
43 | char *s; | ||
44 | stringlist_t *next; | ||
45 | }; | ||
46 | |||
47 | struct Patternlist { | ||
48 | void *p; | ||
49 | patternlist_t *next; | ||
50 | }; | ||
51 | |||
52 | struct Tag { | ||
53 | int type; | ||
54 | char *arg; | ||
55 | }; | ||
56 | |||
57 | struct Taglist { | ||
58 | tag_t *t; | ||
59 | taglist_t *next; | ||
60 | }; | ||
61 | |||
62 | struct Test { | ||
63 | int type; | ||
64 | union { | ||
65 | testlist_t *tl; /* anyof, allof */ | ||
66 | stringlist_t *sl; /* exists */ | ||
67 | struct { /* it's a header test */ | ||
68 | int comptag; | ||
69 | comparator_t *comp; | ||
70 | stringlist_t *sl; | ||
71 | patternlist_t *pl; | ||
72 | } h; | ||
73 | struct { /* it's an address or envelope test */ | ||
74 | int comptag; | ||
75 | comparator_t *comp; | ||
76 | stringlist_t *sl; | ||
77 | patternlist_t *pl; | ||
78 | int addrpart; | ||
79 | } ae; | ||
80 | test_t *t; /* not */ | ||
81 | struct { /* size */ | ||
82 | int t; /* tag */ | ||
83 | int n; /* param */ | ||
84 | } sz; | ||
85 | } u; | ||
86 | }; | ||
87 | |||
88 | struct Testlist { | ||
89 | test_t *t; | ||
90 | testlist_t *next; | ||
91 | }; | ||
92 | |||
93 | struct Commandlist { | ||
94 | int type; | ||
95 | union { | ||
96 | char *str; | ||
97 | stringlist_t *sl; /* the parameters */ | ||
98 | struct { /* it's an if statement */ | ||
99 | test_t *t; | ||
100 | commandlist_t *do_then; | ||
101 | commandlist_t *do_else; | ||
102 | } i; | ||
103 | struct { /* it's a vacation action */ | ||
104 | char *subject; | ||
105 | int days; | ||
106 | stringlist_t *addresses; | ||
107 | char *message; | ||
108 | int mime; | ||
109 | } v; | ||
110 | struct { /* it's a notify action */ | ||
111 | char *priority; | ||
112 | char *message; | ||
113 | stringlist_t *headers_list; | ||
114 | } n; | ||
115 | } u; | ||
116 | struct Commandlist *next; | ||
117 | }; | ||
118 | |||
119 | stringlist_t *new_sl(char *s, stringlist_t *n); | ||
120 | tag_t *new_tag(int type, char *s); | ||
121 | taglist_t *new_taglist(tag_t *t, taglist_t *n); | ||
122 | test_t *new_test(int type); | ||
123 | testlist_t *new_testlist(test_t *t, testlist_t *n); | ||
124 | commandlist_t *new_command(int type); | ||
125 | commandlist_t *new_if(test_t *t, commandlist_t *y, commandlist_t *n); | ||
126 | |||
127 | void free_sl(stringlist_t *sl); | ||
128 | void free_test(test_t *t); | ||
129 | void free_tree(commandlist_t *cl); | ||
130 | |||
131 | #endif |
sieve/util.c
0 → 100644
1 | /* util.c -- general utility functions | ||
2 | * | ||
3 | * Copyright (c) 1998-2000 Carnegie Mellon University. All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions | ||
7 | * are met: | ||
8 | * | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * | ||
12 | * 2. Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * | ||
17 | * 3. The name "Carnegie Mellon University" must not be used to | ||
18 | * endorse or promote products derived from this software without | ||
19 | * prior written permission. For permission or any other legal | ||
20 | * details, please contact | ||
21 | * Office of Technology Transfer | ||
22 | * Carnegie Mellon University | ||
23 | * 5000 Forbes Avenue | ||
24 | * Pittsburgh, PA 15213-3890 | ||
25 | * (412) 268-4387, fax: (412) 268-7395 | ||
26 | * tech-transfer@andrew.cmu.edu | ||
27 | * | ||
28 | * 4. Redistributions of any form whatsoever must retain the following | ||
29 | * acknowledgment: | ||
30 | * "This product includes software developed by Computing Services | ||
31 | * at Carnegie Mellon University (http://www.cmu.edu/computing/)." | ||
32 | * | ||
33 | * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
34 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
35 | * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE | ||
36 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
37 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | ||
38 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | ||
39 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
40 | * | ||
41 | * Author: Chris Newman | ||
42 | * Start Date: 4/6/93 | ||
43 | */ | ||
44 | /* $Id$ | ||
45 | */ | ||
46 | |||
47 | #include <config.h> | ||
48 | #include <stdio.h> | ||
49 | #include <ctype.h> | ||
50 | #include <string.h> | ||
51 | #include "util.h" | ||
52 | |||
53 | /* from OS: */ | ||
54 | extern char *malloc(), *realloc(); | ||
55 | |||
56 | #define BEAUTYBUFSIZE 4096 | ||
57 | |||
58 | const unsigned char convert_to_lowercase[256] = { | ||
59 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | ||
60 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | ||
61 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | ||
62 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, | ||
63 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, | ||
64 | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, | ||
65 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, | ||
66 | 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, | ||
67 | 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g', | ||
68 | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', | ||
69 | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', | ||
70 | 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, | ||
71 | 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g', | ||
72 | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', | ||
73 | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', | ||
74 | 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, | ||
75 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, | ||
76 | 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, | ||
77 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, | ||
78 | 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, | ||
79 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, | ||
80 | 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, | ||
81 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, | ||
82 | 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, | ||
83 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, | ||
84 | 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, | ||
85 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, | ||
86 | 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, | ||
87 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, | ||
88 | 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, | ||
89 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, | ||
90 | 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff | ||
91 | }; | ||
92 | |||
93 | const unsigned char convert_to_uppercase[256] = { | ||
94 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | ||
95 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | ||
96 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | ||
97 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, | ||
98 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, | ||
99 | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, | ||
100 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, | ||
101 | 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, | ||
102 | 0x40, 'A', 'B', 'C', 'D', 'E', 'F', 'G', | ||
103 | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', | ||
104 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', | ||
105 | 'X', 'Y', 'Z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, | ||
106 | 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G', | ||
107 | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', | ||
108 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', | ||
109 | 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, | ||
110 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, | ||
111 | 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, | ||
112 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, | ||
113 | 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, | ||
114 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, | ||
115 | 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, | ||
116 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, | ||
117 | 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, | ||
118 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, | ||
119 | 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, | ||
120 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, | ||
121 | 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, | ||
122 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, | ||
123 | 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, | ||
124 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, | ||
125 | 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff | ||
126 | }; | ||
127 | |||
128 | /* convert string to all lower case | ||
129 | */ | ||
130 | char *lcase(char* str) | ||
131 | { | ||
132 | char *scan = str; | ||
133 | |||
134 | while (*scan) { | ||
135 | *scan = TOLOWER(*scan); | ||
136 | scan++; | ||
137 | } | ||
138 | |||
139 | return (str); | ||
140 | } | ||
141 | |||
142 | /* convert string to all upper case | ||
143 | */ | ||
144 | char *ucase(char* str) | ||
145 | { | ||
146 | char *scan = str; | ||
147 | |||
148 | while (*scan) { | ||
149 | *scan = convert_to_uppercase[(unsigned char)(*scan)]; | ||
150 | scan++; | ||
151 | } | ||
152 | |||
153 | return (str); | ||
154 | } | ||
155 | |||
156 | /* clean up control characters in a string while copying it | ||
157 | * returns pointer to end of dst string. | ||
158 | * dst must have twice the length of source | ||
159 | */ | ||
160 | char *beautify_copy(char* dst, const char* src) | ||
161 | { | ||
162 | unsigned char c; | ||
163 | |||
164 | while (*src) { | ||
165 | c = *src++ & 0x7F; | ||
166 | if (!isprint(c)) { | ||
167 | *dst++ = '^'; | ||
168 | if (c > ' ') { | ||
169 | c = '?'; | ||
170 | } else { | ||
171 | c += '@'; | ||
172 | } | ||
173 | } | ||
174 | *dst++ = c; | ||
175 | } | ||
176 | *dst = '\0'; | ||
177 | |||
178 | return (dst); | ||
179 | } | ||
180 | |||
181 | |||
182 | /* clean up control characters in a string while copying it | ||
183 | * returns pointer to a static buffer containing the cleaned-up version | ||
184 | * returns NULL on malloc() error | ||
185 | */ | ||
186 | char *beautify_string(const char* src) | ||
187 | { | ||
188 | static char *beautybuf = NULL; | ||
189 | static int beautysize = 0; | ||
190 | int len; | ||
191 | |||
192 | len = strlen(src) * 2 + 1; | ||
193 | if (beautysize < len) { | ||
194 | if (!beautysize) { | ||
195 | beautysize = len > BEAUTYBUFSIZE ? len : BEAUTYBUFSIZE; | ||
196 | beautybuf = malloc(beautysize); | ||
197 | } else { | ||
198 | beautysize *= 2; | ||
199 | if (len > beautysize) beautysize = len; | ||
200 | beautybuf = realloc(beautybuf, beautysize); | ||
201 | } | ||
202 | if (!beautybuf) { | ||
203 | beautysize = 0; | ||
204 | return ""; | ||
205 | } | ||
206 | } | ||
207 | (void) beautify_copy(beautybuf, src); | ||
208 | |||
209 | return (beautybuf); | ||
210 | } | ||
211 | |||
212 | /* do a binary search in a keyvalue array | ||
213 | * nelem is the number of keyvalue elements in the kv array | ||
214 | * cmpf is the comparison function (strcmp, strcasecmp, etc). | ||
215 | * returns NULL if not found, or key/value pair if found. | ||
216 | */ | ||
217 | keyvalue *kv_bsearch(const char* key, keyvalue* kv, int nelem, | ||
218 | int (*cmpf) (const char *s1, const char *s2)) | ||
219 | { | ||
220 | int top, mid = 0, bot, cmp = 0; | ||
221 | |||
222 | cmp = 1; | ||
223 | bot = 0; | ||
224 | top = nelem - 1; | ||
225 | while (top >= bot && (cmp = (*cmpf)(key, kv[mid = (bot + top) >> 1].key))) | ||
226 | if (cmp < 0) { | ||
227 | top = mid - 1; | ||
228 | } else { | ||
229 | bot = mid + 1; | ||
230 | } | ||
231 | |||
232 | return (cmp ? NULL : kv + mid); | ||
233 | } |
sieve/util.h
0 → 100644
1 | /* util.h -- general utility functions | ||
2 | * $Id$ | ||
3 | * | ||
4 | * Copyright (c) 1999-2000 Carnegie Mellon University. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in | ||
15 | * the documentation and/or other materials provided with the | ||
16 | * distribution. | ||
17 | * | ||
18 | * 3. The name "Carnegie Mellon University" must not be used to | ||
19 | * endorse or promote products derived from this software without | ||
20 | * prior written permission. For permission or any other legal | ||
21 | * details, please contact | ||
22 | * Office of Technology Transfer | ||
23 | * Carnegie Mellon University | ||
24 | * 5000 Forbes Avenue | ||
25 | * Pittsburgh, PA 15213-3890 | ||
26 | * (412) 268-4387, fax: (412) 268-7395 | ||
27 | * tech-transfer@andrew.cmu.edu | ||
28 | * | ||
29 | * 4. Redistributions of any form whatsoever must retain the following | ||
30 | * acknowledgment: | ||
31 | * "This product includes software developed by Computing Services | ||
32 | * at Carnegie Mellon University (http://www.cmu.edu/computing/)." | ||
33 | * | ||
34 | * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
35 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
36 | * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE | ||
37 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
38 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | ||
39 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | ||
40 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
41 | * | ||
42 | * Author: Chris Newman | ||
43 | * Start Date: 4/6/93 | ||
44 | */ | ||
45 | |||
46 | #ifndef INCLUDED_UTIL_H | ||
47 | #define INCLUDED_UTIL_H | ||
48 | |||
49 | extern const unsigned char convert_to_lowercase[256]; | ||
50 | extern const unsigned char convert_to_uppercase[256]; | ||
51 | |||
52 | #define TOUPPER(c) (convert_to_uppercase[(unsigned char)(c)]) | ||
53 | #define TOLOWER(c) (convert_to_lowercase[(unsigned char)(c)]) | ||
54 | |||
55 | typedef struct keyvalue { | ||
56 | char *key, *value; | ||
57 | } keyvalue; | ||
58 | |||
59 | /* convert string to all lower case | ||
60 | */ | ||
61 | extern char *lcase (char *str); | ||
62 | |||
63 | /* convert string to all upper case | ||
64 | */ | ||
65 | extern char *ucase (char *str); | ||
66 | |||
67 | /* clean up control characters in a string while copying it | ||
68 | * returns pointer to end of dst string. | ||
69 | * dst must have twice the length of source | ||
70 | */ | ||
71 | extern char *beautify_copy (char *dst, const char *src); | ||
72 | |||
73 | /* clean up control characters in a string while copying it | ||
74 | * returns pointer to a static buffer containing the cleaned-up version | ||
75 | * returns NULL on malloc() error | ||
76 | */ | ||
77 | extern char *beautify_string (const char *src); | ||
78 | |||
79 | /* do a binary search in a keyvalue array | ||
80 | * nelem is the number of keyvalue elements in the kv array | ||
81 | * cmpf is the comparison function (strcmp, stricmp, etc). | ||
82 | * returns NULL if not found, or key/value pair if found. | ||
83 | */ | ||
84 | extern keyvalue *kv_bsearch (const char *key, keyvalue *kv, int nelem, | ||
85 | int (*cmpf)(const char *s1, const char *s2)); | ||
86 | |||
87 | #endif /* INCLUDED_UTIL_H */ |
sieve/xmalloc.c
0 → 100644
1 | /* xmalloc.c -- Allocation package that calls fatal() when out of memory | ||
2 | * | ||
3 | * Copyright (c) 1998-2000 Carnegie Mellon University. All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions | ||
7 | * are met: | ||
8 | * | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * | ||
12 | * 2. Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * | ||
17 | * 3. The name "Carnegie Mellon University" must not be used to | ||
18 | * endorse or promote products derived from this software without | ||
19 | * prior written permission. For permission or any other legal | ||
20 | * details, please contact | ||
21 | * Office of Technology Transfer | ||
22 | * Carnegie Mellon University | ||
23 | * 5000 Forbes Avenue | ||
24 | * Pittsburgh, PA 15213-3890 | ||
25 | * (412) 268-4387, fax: (412) 268-7395 | ||
26 | * tech-transfer@andrew.cmu.edu | ||
27 | * | ||
28 | * 4. Redistributions of any form whatsoever must retain the following | ||
29 | * acknowledgment: | ||
30 | * "This product includes software developed by Computing Services | ||
31 | * at Carnegie Mellon University (http://www.cmu.edu/computing/)." | ||
32 | * | ||
33 | * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
34 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
35 | * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE | ||
36 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
37 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | ||
38 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | ||
39 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
40 | */ | ||
41 | /* | ||
42 | * $Id$ | ||
43 | */ | ||
44 | #include <config.h> | ||
45 | #include <stdio.h> | ||
46 | #include <stdlib.h> | ||
47 | #include <string.h> | ||
48 | #include "xmalloc.h" | ||
49 | |||
50 | #include "exitcodes.h" | ||
51 | |||
52 | void* xmalloc(unsigned size) | ||
53 | { | ||
54 | void *ret; | ||
55 | |||
56 | ret = malloc(size); | ||
57 | if (ret != NULL) return ret; | ||
58 | |||
59 | fatal("Virtual memory exhausted", EC_TEMPFAIL); | ||
60 | return 0; /*NOTREACHED*/ | ||
61 | } | ||
62 | |||
63 | void* xzmalloc(unsigned size) | ||
64 | { | ||
65 | void *ret; | ||
66 | |||
67 | ret = malloc(size); | ||
68 | if (ret != NULL) { | ||
69 | memset(ret, 0, size); | ||
70 | return ret; | ||
71 | } | ||
72 | |||
73 | fatal("Virtual memory exhausted", EC_TEMPFAIL); | ||
74 | return 0; /*NOTREACHED*/ | ||
75 | } | ||
76 | |||
77 | void *xrealloc (void* ptr, unsigned size) | ||
78 | { | ||
79 | void *ret; | ||
80 | |||
81 | /* xrealloc (NULL, size) behaves like xmalloc (size), as in ANSI C */ | ||
82 | ret = (!ptr ? malloc (size) : realloc (ptr, size)); | ||
83 | if (ret != NULL) return ret; | ||
84 | |||
85 | fatal("Virtual memory exhausted", EC_TEMPFAIL); | ||
86 | return 0; /*NOTREACHED*/ | ||
87 | } | ||
88 | |||
89 | char *xstrdup(const char* str) | ||
90 | { | ||
91 | char *p = xmalloc(strlen(str)+1); | ||
92 | strcpy(p, str); | ||
93 | return p; | ||
94 | } | ||
95 | |||
96 | char *xstrndup(const char* str, unsigned len) | ||
97 | { | ||
98 | char *p = xmalloc(len+1); | ||
99 | strncpy(p, str, len); | ||
100 | p[len] = '\0'; | ||
101 | return p; | ||
102 | } | ||
103 | |||
104 | /* Same as xmalloc() */ | ||
105 | void *fs_get(unsigned size) | ||
106 | { | ||
107 | void *ret; | ||
108 | |||
109 | if ((ret = malloc(size)) != NULL) | ||
110 | return (void *)ret; | ||
111 | |||
112 | fatal("Virtual memory exhausted", EC_TEMPFAIL); | ||
113 | } | ||
114 | |||
115 | void fs_give(void** ptr) | ||
116 | { | ||
117 | free((void *)*ptr); | ||
118 | *ptr = 0; | ||
119 | } | ||
120 | |||
121 | #ifndef HAVE_STRLCPY | ||
122 | /* strlcpy -- copy string smartly. | ||
123 | * | ||
124 | * i believe/hope this is compatible with the BSD strlcpy(). | ||
125 | */ | ||
126 | size_t strlcpy(char *dst, const char *src, size_t len) | ||
127 | { | ||
128 | size_t n; | ||
129 | |||
130 | if (len <= 0) return strlen(src); | ||
131 | for (n = 0; n < len; n++) { | ||
132 | if ((dst[n] = src[n]) == '\0') break; | ||
133 | } | ||
134 | if (src[n] == '\0') { | ||
135 | /* copied entire string */ | ||
136 | return n; | ||
137 | } else { | ||
138 | dst[n] = '\0'; | ||
139 | /* ran out of space */ | ||
140 | return n + strlen(src + n); | ||
141 | } | ||
142 | } | ||
143 | #endif | ||
144 | |||
145 | #ifndef HAVE_STRLCAT | ||
146 | size_t strlcat(char *dst, const char *src, size_t len) | ||
147 | { | ||
148 | size_t i, j, o; | ||
149 | |||
150 | o = strlen(dst); | ||
151 | if (len < o + 1) | ||
152 | return o + strlen(src); | ||
153 | len -= o + 1; | ||
154 | for (i = 0, j = o; i < len; i++, j++) { | ||
155 | if ((dst[j] = src[i]) == '\0') break; | ||
156 | } | ||
157 | dst[j] = '\0'; | ||
158 | if (src[i] == '\0') { | ||
159 | return j; | ||
160 | } else { | ||
161 | return j + strlen(src + i); | ||
162 | } | ||
163 | } | ||
164 | #endif |
sieve/xmalloc.h
0 → 100644
1 | /* xmalloc.h -- Allocation package that calls fatal() when out of memory | ||
2 | * $Id$ | ||
3 | * | ||
4 | * Copyright (c) 1998-2000 Carnegie Mellon University. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in | ||
15 | * the documentation and/or other materials provided with the | ||
16 | * distribution. | ||
17 | * | ||
18 | * 3. The name "Carnegie Mellon University" must not be used to | ||
19 | * endorse or promote products derived from this software without | ||
20 | * prior written permission. For permission or any other legal | ||
21 | * details, please contact | ||
22 | * Office of Technology Transfer | ||
23 | * Carnegie Mellon University | ||
24 | * 5000 Forbes Avenue | ||
25 | * Pittsburgh, PA 15213-3890 | ||
26 | * (412) 268-4387, fax: (412) 268-7395 | ||
27 | * tech-transfer@andrew.cmu.edu | ||
28 | * | ||
29 | * 4. Redistributions of any form whatsoever must retain the following | ||
30 | * acknowledgment: | ||
31 | * "This product includes software developed by Computing Services | ||
32 | * at Carnegie Mellon University (http://www.cmu.edu/computing/)." | ||
33 | * | ||
34 | * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | ||
35 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
36 | * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE | ||
37 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
38 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | ||
39 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | ||
40 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
41 | * | ||
42 | */ | ||
43 | |||
44 | #ifndef INCLUDED_XMALLOC_H | ||
45 | #define INCLUDED_XMALLOC_H | ||
46 | |||
47 | /* for size_t */ | ||
48 | #include <stdio.h> | ||
49 | |||
50 | extern void *xmalloc (unsigned size); | ||
51 | extern void *xzmalloc (unsigned size); | ||
52 | extern void *xrealloc (void *ptr, unsigned size); | ||
53 | extern char *xstrdup (const char *str); | ||
54 | extern char *xstrndup (const char *str, unsigned len); | ||
55 | extern void *fs_get (unsigned size); | ||
56 | extern void fs_give (void **ptr); | ||
57 | |||
58 | /* handy string manipulation functions */ | ||
59 | #ifndef HAVE_STRLCPY | ||
60 | extern size_t strlcpy(char *dst, const char *src, size_t len); | ||
61 | #endif | ||
62 | #ifndef HAVE_STRLCAT | ||
63 | extern size_t strlcat(char *dst, const char *src, size_t len); | ||
64 | #endif | ||
65 | |||
66 | /* Functions using xmalloc.h must provide a function called fatal() conforming | ||
67 | to the following: */ | ||
68 | extern void fatal(const char *fatal_message, int fatal_code) | ||
69 | __attribute__ ((noreturn)); | ||
70 | |||
71 | #endif /* INCLUDED_XMALLOC_H */ |
-
Please register or sign in to post a comment