Commit 6366c5c6 6366c5c6ed8ae63ed3578610729de531d33a03fa by Sam Roberts

Initial commit of the port of CMU's sieve engine. It builds, and some

actions work, but has seen very little use.
1 parent fcc8b0cb
1 gram-sieve.tab.c
2 Makefile
3 Makefile.in
4 addr.c
5 addr.h
6 sieve-gram.c
7 sieve-gram.h
8 addr-lex.c
9 sieve-lex.c
10 .deps
11 .libs
12 sieve
13 test
14 _*
1 Larry Greenfield <leg+sieve@andrew.cmu.edu> wrote the first pass.
2
3 Alexy Melnikov <mel@taxxi.com> submitted some bug fixes and improvements.
4
5 Ken Murchison <ken@oceana.com> took the ball, added more extensions
6 than existed in the known world, and overall improved the code mightily.
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 ******************************************************************/
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
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
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.
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 }
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 }
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 }
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
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 */
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 */
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 }
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 */
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 }
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
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 }
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*));
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
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
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
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
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 */
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
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
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 }
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 }
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
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
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
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
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
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
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_ */
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, &notify);
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 }
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 }
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
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 }
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 */
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
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 */