Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F120825458
script.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
25 KB
Referenced Files
None
Subscribers
None
script.c
View Options
/* script.c -- sieve script functions
* Larry Greenfield
* $Id: script.c,v 1.28 2000/05/28 22:45:59 leg Exp $
*/
/***********************************************************
Copyright 1999 by Carnegie Mellon University
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Carnegie Mellon
University not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
******************************************************************/
#include
<stdlib.h>
#include
<string.h>
#include
<md5global.h>
#include
<md5.h>
#include
<ctype.h>
#include
"xmalloc.h"
#include
"sieve_interface.h"
#include
"interp.h"
#include
"script.h"
#include
"tree.h"
#include
"sieve.h"
#include
"message.h"
/* does this interpretor support this requirement? */
int
script_require
(
sieve_script_t
*
s
,
char
*
req
)
{
if
(
!
strcmp
(
"fileinto"
,
req
))
{
if
(
s
->
interp
.
fileinto
)
{
s
->
support
.
fileinto
=
1
;
return
1
;
}
else
{
return
0
;
}
}
else
if
(
!
strcmp
(
"reject"
,
req
))
{
if
(
s
->
interp
.
reject
)
{
s
->
support
.
reject
=
1
;
return
1
;
}
else
{
return
0
;
}
}
else
if
(
!
strcmp
(
"envelope"
,
req
))
{
if
(
s
->
interp
.
getenvelope
)
{
s
->
support
.
envelope
=
1
;
return
1
;
}
else
{
return
0
;
}
}
else
if
(
!
strcmp
(
"vacation"
,
req
))
{
if
(
s
->
interp
.
vacation
)
{
s
->
support
.
vacation
=
1
;
return
1
;
}
else
{
return
0
;
}
}
else
if
(
!
strcmp
(
"imapflags"
,
req
))
{
if
(
s
->
interp
.
markflags
->
flag
)
{
s
->
support
.
imapflags
=
1
;
return
1
;
}
else
{
return
0
;
}
}
else
if
(
!
strcmp
(
"notify"
,
req
))
{
if
(
s
->
interp
.
notify
)
{
s
->
support
.
notify
=
1
;
return
1
;
}
else
{
return
0
;
}
#ifdef ENABLE_REGEX
}
else
if
(
!
strcmp
(
"regex"
,
req
))
{
s
->
support
.
regex
=
1
;
return
1
;
#endif
}
else
if
(
!
strcmp
(
"subaddress"
,
req
))
{
s
->
support
.
subaddress
=
1
;
return
1
;
}
else
if
(
!
strcmp
(
"comparator-i;octet"
,
req
))
{
return
1
;
}
else
if
(
!
strcmp
(
"comparator-i;ascii-casemap"
,
req
))
{
return
1
;
}
return
0
;
}
/* given an interpretor and a script, produce an executable script */
int
sieve_script_parse
(
sieve_interp_t
*
interp
,
FILE
*
script
,
void
*
script_context
,
sieve_script_t
**
ret
)
{
sieve_script_t
*
s
;
int
res
=
SIEVE_OK
;
res
=
interp_verify
(
interp
);
if
(
res
!=
SIEVE_OK
)
{
return
res
;
}
s
=
(
sieve_script_t
*
)
xmalloc
(
sizeof
(
sieve_script_t
));
s
->
interp
=
*
interp
;
s
->
script_context
=
script_context
;
/* clear all support bits */
memset
(
&
s
->
support
,
0
,
sizeof
(
struct
sieve_support
));
s
->
err
=
0
;
s
->
cmds
=
sieve_parse
(
s
,
script
);
if
(
s
->
err
>
0
)
{
if
(
s
->
cmds
)
{
free_tree
(
s
->
cmds
);
}
s
->
cmds
=
NULL
;
res
=
SIEVE_PARSE_ERROR
;
}
*
ret
=
s
;
return
res
;
}
char
**
stringlist_to_chararray
(
stringlist_t
*
list
)
{
int
size
=
0
;
stringlist_t
*
tmp
=
list
;
stringlist_t
*
tofree
;
char
**
ret
;
int
lup
;
while
(
tmp
!=
NULL
)
{
size
++
;
tmp
=
tmp
->
next
;
}
ret
=
malloc
(
sizeof
(
char
*
)
*
(
size
+
1
));
if
(
ret
==
NULL
)
return
NULL
;
tmp
=
list
;
for
(
lup
=
0
;
lup
<
size
;
lup
++
)
{
ret
[
lup
]
=
tmp
->
s
;
tmp
=
tmp
->
next
;
}
ret
[
size
]
=
NULL
;
/* free element holders */
tmp
=
list
;
while
(
tmp
!=
NULL
)
{
tofree
=
tmp
;
tmp
=
tmp
->
next
;
free
(
tofree
);
}
return
ret
;
}
int
sieve_script_free
(
sieve_script_t
**
s
)
{
if
(
*
s
)
{
if
((
*
s
)
->
cmds
)
{
free_tree
((
*
s
)
->
cmds
);
}
free
(
*
s
);
}
return
SIEVE_OK
;
}
static
int
sysaddr
(
char
*
addr
)
{
if
(
!
strncasecmp
(
addr
,
"MAILER-DAEMON"
,
13
))
return
1
;
if
(
!
strncasecmp
(
addr
,
"LISTSERV"
,
8
))
return
1
;
if
(
!
strncasecmp
(
addr
,
"majordomo"
,
9
))
return
1
;
if
(
strstr
(
addr
,
"-request"
))
return
1
;
if
(
!
strncmp
(
addr
,
"owner-"
,
6
))
return
1
;
return
0
;
}
/* look for myaddr and myaddrs in the body of a header */
static
int
look_for_me
(
char
*
myaddr
,
stringlist_t
*
myaddrs
,
const
char
**
body
)
{
int
found
=
0
;
int
l
;
stringlist_t
*
sl
;
/* loop through each TO header */
for
(
l
=
0
;
body
[
l
]
!=
NULL
&&
!
found
;
l
++
)
{
void
*
data
=
NULL
,
*
marker
=
NULL
;
char
*
addr
;
parse_address
(
body
[
l
],
&
data
,
&
marker
);
/* loop through each address in the header */
while
(
!
found
&&
((
addr
=
get_address
(
ADDRESS_ALL
,
&
data
,
&
marker
))
!=
NULL
))
{
if
(
!
strcmp
(
addr
,
myaddr
))
{
found
=
1
;
break
;
}
for
(
sl
=
myaddrs
;
sl
!=
NULL
;
sl
=
sl
->
next
)
{
/* is this address one of my addresses? */
if
(
!
strcmp
(
addr
,
sl
->
s
))
{
found
=
1
;
break
;
}
}
}
free_address
(
&
data
,
&
marker
);
}
return
found
;
}
/* evaluates the test t. returns 1 if true, 0 if false.
*/
static
int
evaltest
(
sieve_interp_t
*
i
,
test_t
*
t
,
void
*
m
)
{
testlist_t
*
tl
;
stringlist_t
*
sl
;
patternlist_t
*
pl
;
int
res
=
0
;
int
addrpart
=
0
;
switch
(
t
->
type
)
{
case
ADDRESS
:
case
ENVELOPE
:
res
=
0
;
switch
(
t
->
u
.
ae
.
addrpart
)
{
case
ALL
:
addrpart
=
ADDRESS_ALL
;
break
;
case
LOCALPART
:
addrpart
=
ADDRESS_LOCALPART
;
break
;
case
DOMAIN
:
addrpart
=
ADDRESS_DOMAIN
;
break
;
case
USER
:
addrpart
=
ADDRESS_USER
;
break
;
case
DETAIL
:
addrpart
=
ADDRESS_DETAIL
;
break
;
}
for
(
sl
=
t
->
u
.
ae
.
sl
;
sl
!=
NULL
&&
!
res
;
sl
=
sl
->
next
)
{
int
l
;
const
char
**
body
;
/* use getheader for address, getenvelope for envelope */
if
(((
t
->
type
==
ADDRESS
)
?
i
->
getheader
(
m
,
sl
->
s
,
&
body
)
:
i
->
getenvelope
(
m
,
sl
->
s
,
&
body
))
!=
SIEVE_OK
)
{
continue
;
/* try next header */
}
for
(
pl
=
t
->
u
.
ae
.
pl
;
pl
!=
NULL
&&
!
res
;
pl
=
pl
->
next
)
{
for
(
l
=
0
;
body
[
l
]
!=
NULL
&&
!
res
;
l
++
)
{
/* loop through each header */
void
*
data
=
NULL
,
*
marker
=
NULL
;
char
*
val
;
parse_address
(
body
[
l
],
&
data
,
&
marker
);
val
=
get_address
(
addrpart
,
&
data
,
&
marker
);
while
(
val
!=
NULL
&&
!
res
)
{
/* loop through each address */
res
|=
t
->
u
.
ae
.
comp
(
pl
->
p
,
val
);
val
=
get_address
(
addrpart
,
&
data
,
&
marker
);
}
free_address
(
&
data
,
&
marker
);
}
}
}
break
;
case
ANYOF
:
res
=
0
;
for
(
tl
=
t
->
u
.
tl
;
tl
!=
NULL
&&
!
res
;
tl
=
tl
->
next
)
{
res
|=
evaltest
(
i
,
tl
->
t
,
m
);
}
break
;
case
ALLOF
:
res
=
1
;
for
(
tl
=
t
->
u
.
tl
;
tl
!=
NULL
&&
res
;
tl
=
tl
->
next
)
{
res
&=
evaltest
(
i
,
tl
->
t
,
m
);
}
break
;
case
EXISTS
:
res
=
1
;
for
(
sl
=
t
->
u
.
sl
;
sl
!=
NULL
&&
res
;
sl
=
sl
->
next
)
{
const
char
**
headbody
=
NULL
;
res
&=
(
i
->
getheader
(
m
,
sl
->
s
,
&
headbody
)
==
SIEVE_OK
);
}
break
;
case
FALSE
:
res
=
0
;
break
;
case
TRUE
:
res
=
1
;
break
;
case
HEADER
:
res
=
0
;
for
(
sl
=
t
->
u
.
h
.
sl
;
sl
!=
NULL
&&
!
res
;
sl
=
sl
->
next
)
{
const
char
**
val
;
int
l
;
if
(
i
->
getheader
(
m
,
sl
->
s
,
&
val
)
!=
SIEVE_OK
)
continue
;
for
(
pl
=
t
->
u
.
h
.
pl
;
pl
!=
NULL
&&
!
res
;
pl
=
pl
->
next
)
{
for
(
l
=
0
;
val
[
l
]
!=
NULL
&&
!
res
;
l
++
)
{
res
|=
t
->
u
.
h
.
comp
(
pl
->
p
,
val
[
l
]);
}
}
}
break
;
case
NOT
:
res
=
!
evaltest
(
i
,
t
->
u
.
t
,
m
);
break
;
case
SIZE
:
{
int
sz
;
if
(
i
->
getsize
(
m
,
&
sz
)
!=
SIEVE_OK
)
break
;
if
(
t
->
u
.
sz
.
t
==
OVER
)
{
res
=
(
sz
>
t
->
u
.
sz
.
n
);
}
else
{
/* UNDER */
res
=
(
sz
<
t
->
u
.
sz
.
n
);
}
break
;
}
}
return
res
;
}
/* evaluate the script c. returns negative if error was encountered,
0 if it exited off the end, or if a stop action was encountered.
note that this is very stack hungry; we just evaluate the AST in
the naivest way. if we implement some sort of depth limit, we'll
be ok here; otherwise we'd want to transform it a little smarter */
static
int
eval
(
sieve_interp_t
*
i
,
commandlist_t
*
c
,
void
*
m
,
action_list_t
*
actions
,
notify_action_t
*
notify_action
,
const
char
**
errmsg
)
{
int
res
=
0
;
stringlist_t
*
sl
;
while
(
c
!=
NULL
)
{
switch
(
c
->
type
)
{
case
IF
:
if
(
evaltest
(
i
,
c
->
u
.
i
.
t
,
m
))
res
=
eval
(
i
,
c
->
u
.
i
.
do_then
,
m
,
actions
,
notify_action
,
errmsg
);
else
res
=
eval
(
i
,
c
->
u
.
i
.
do_else
,
m
,
actions
,
notify_action
,
errmsg
);
break
;
case
REJCT
:
res
=
do_reject
(
actions
,
c
->
u
.
str
);
if
(
res
==
SIEVE_RUN_ERROR
)
*
errmsg
=
"Reject can not be used with any other action"
;
break
;
case
FILEINTO
:
for
(
sl
=
c
->
u
.
sl
;
res
==
0
&&
sl
!=
NULL
;
sl
=
sl
->
next
)
{
res
=
do_fileinto
(
actions
,
sl
->
s
,
&
i
->
curflags
);
if
(
res
==
SIEVE_RUN_ERROR
)
*
errmsg
=
"Fileinto can not be used with Reject"
;
}
break
;
case
FORWARD
:
for
(
sl
=
c
->
u
.
sl
;
res
==
0
&&
sl
!=
NULL
;
sl
=
sl
->
next
)
{
res
=
do_forward
(
actions
,
sl
->
s
);
if
(
res
==
SIEVE_RUN_ERROR
)
*
errmsg
=
"Redirect can not be used with Reject"
;
}
break
;
case
KEEP
:
res
=
do_keep
(
actions
,
&
i
->
curflags
);
if
(
res
==
SIEVE_RUN_ERROR
)
*
errmsg
=
"Keep can not be used with Reject"
;
break
;
case
VACATION
:
{
const
char
**
body
;
char
buf
[
128
],
myaddr
[
256
],
*
fromaddr
;
char
*
reply_to
=
NULL
;
int
l
=
SIEVE_OK
;
/* is there an Auto-Submitted keyword other than "no"? */
strcpy
(
buf
,
"auto-submitted"
);
if
(
i
->
getheader
(
m
,
buf
,
&
body
)
==
SIEVE_OK
)
{
/* we don't deal with comments, etc. here */
/* skip leading white-space */
while
(
*
body
[
0
]
&&
isspace
((
int
)
*
body
[
0
]))
body
[
0
]
++
;
if
(
strcasecmp
(
body
[
0
],
"no"
))
l
=
SIEVE_DONE
;
}
if
(
l
==
SIEVE_OK
)
{
strcpy
(
buf
,
"to"
);
l
=
i
->
getenvelope
(
m
,
buf
,
&
body
);
if
(
body
[
0
])
{
strncpy
(
myaddr
,
body
[
0
],
sizeof
(
myaddr
)
-
1
);
}
}
if
(
l
==
SIEVE_OK
)
{
strcpy
(
buf
,
"from"
);
l
=
i
->
getenvelope
(
m
,
buf
,
&
body
);
}
if
(
l
==
SIEVE_OK
&&
body
[
0
])
{
/* we have to parse this address & decide whether we
want to respond to it */
void
*
data
=
NULL
,
*
marker
=
NULL
;
char
*
tmp
;
parse_address
(
body
[
0
],
&
data
,
&
marker
);
tmp
=
get_address
(
ADDRESS_ALL
,
&
data
,
&
marker
);
reply_to
=
(
tmp
!=
NULL
)
?
xstrdup
(
tmp
)
:
NULL
;
free_address
(
&
data
,
&
marker
);
/* first, is there a reply-to address? */
if
(
reply_to
==
NULL
)
{
l
=
SIEVE_DONE
;
}
/* first, is it from me? really should use a
compare_address function */
if
(
l
==
SIEVE_OK
&&
!
strcmp
(
myaddr
,
reply_to
))
{
l
=
SIEVE_DONE
;
}
/* ok, is it any of the other addresses i've
specified? */
if
(
l
==
SIEVE_OK
)
for
(
sl
=
c
->
u
.
v
.
addresses
;
sl
!=
NULL
;
sl
=
sl
->
next
)
if
(
!
strcmp
(
sl
->
s
,
reply_to
))
l
=
SIEVE_DONE
;
/* ok, is it a system address? */
if
(
l
==
SIEVE_OK
&&
sysaddr
(
reply_to
))
{
l
=
SIEVE_DONE
;
}
}
if
(
l
==
SIEVE_OK
)
{
int
found
=
0
;
/* ok, we're willing to respond to the sender.
but is this message to me? that is, is my address
in the TO or CC fields? */
if
(
strcpy
(
buf
,
"to"
),
i
->
getheader
(
m
,
buf
,
&
body
)
==
SIEVE_OK
)
found
=
look_for_me
(
myaddr
,
c
->
u
.
v
.
addresses
,
body
);
if
(
!
found
&&
(
strcpy
(
buf
,
"cc"
),
(
i
->
getheader
(
m
,
buf
,
&
body
)
==
SIEVE_OK
)))
found
=
look_for_me
(
myaddr
,
c
->
u
.
v
.
addresses
,
body
);
if
(
!
found
)
l
=
SIEVE_DONE
;
}
if
(
l
==
SIEVE_OK
)
{
/* ok, ok, if we got here maybe we should reply */
if
(
c
->
u
.
v
.
subject
==
NULL
)
{
/* we have to generate a subject */
const
char
**
s
;
strcpy
(
buf
,
"subject"
);
if
(
i
->
getheader
(
m
,
buf
,
&
s
)
!=
SIEVE_OK
||
s
[
0
]
==
NULL
)
{
strcpy
(
buf
,
"Automated reply"
);
}
else
{
/* s[0] contains the original subject */
while
(
!
strncasecmp
(
s
[
0
],
"Re: "
,
4
))
{
s
[
0
]
+=
4
;
}
snprintf
(
buf
,
sizeof
(
buf
),
"Re: %s"
,
s
[
0
]);
}
}
else
{
/* user specified subject */
strncpy
(
buf
,
c
->
u
.
v
.
subject
,
sizeof
(
buf
));
}
/* who do we want the message coming from? */
if
(
c
->
u
.
v
.
addresses
)
{
fromaddr
=
c
->
u
.
v
.
addresses
->
s
;
}
else
{
fromaddr
=
myaddr
;
}
res
=
do_vacation
(
actions
,
reply_to
,
strdup
(
fromaddr
),
strdup
(
buf
),
c
->
u
.
v
.
message
,
c
->
u
.
v
.
days
,
c
->
u
.
v
.
mime
);
if
(
res
==
SIEVE_RUN_ERROR
)
*
errmsg
=
"Vacation can not be used with Reject or Vacation"
;
}
else
{
if
(
l
!=
SIEVE_DONE
)
res
=
-1
;
/* something went wrong */
}
break
;
}
case
STOP
:
/* we're done, exit */
res
=
1
;
return
0
;
break
;
case
DISCARD
:
res
=
do_discard
(
actions
);
break
;
case
SETFLAG
:
sl
=
c
->
u
.
sl
;
res
=
do_setflag
(
actions
,
sl
->
s
);
for
(
sl
=
sl
->
next
;
res
==
0
&&
sl
!=
NULL
;
sl
=
sl
->
next
)
{
res
=
do_addflag
(
actions
,
sl
->
s
);
}
if
(
res
==
SIEVE_RUN_ERROR
)
*
errmsg
=
"Setflag can not be used with Reject"
;
break
;
case
ADDFLAG
:
for
(
sl
=
c
->
u
.
sl
;
res
==
0
&&
sl
!=
NULL
;
sl
=
sl
->
next
)
{
res
=
do_addflag
(
actions
,
sl
->
s
);
}
if
(
res
==
SIEVE_RUN_ERROR
)
*
errmsg
=
"Addflag can not be used with Reject"
;
break
;
case
REMOVEFLAG
:
for
(
sl
=
c
->
u
.
sl
;
res
==
0
&&
sl
!=
NULL
;
sl
=
sl
->
next
)
{
res
=
do_removeflag
(
actions
,
sl
->
s
);
}
if
(
res
==
SIEVE_RUN_ERROR
)
*
errmsg
=
"Removeflag can not be used with Reject"
;
break
;
case
MARK
:
res
=
do_mark
(
actions
);
if
(
res
==
SIEVE_RUN_ERROR
)
*
errmsg
=
"Mark can not be used with Reject"
;
break
;
case
UNMARK
:
res
=
do_unmark
(
actions
);
if
(
res
==
SIEVE_RUN_ERROR
)
*
errmsg
=
"Unmark can not be used with Reject"
;
break
;
case
NOTIFY
:
res
=
do_notify
(
i
,
m
,
notify_action
,
c
->
u
.
n
.
priority
,
c
->
u
.
n
.
message
,
c
->
u
.
n
.
headers_list
);
break
;
case
DENOTIFY
:
res
=
do_denotify
(
notify_action
);
break
;
}
if
(
res
)
/* we've either encountered an error */
break
;
/* execute next command */
c
=
c
->
next
;
}
return
res
;
}
#define GROW_AMOUNT 100
static
void
add_header
(
sieve_interp_t
*
i
,
char
*
header
,
void
*
message_context
,
char
**
out
,
int
*
outlen
,
int
*
outalloc
)
{
const
char
**
h
;
int
addlen
;
/* get header value */
i
->
getheader
(
message_context
,
header
,
&
h
);
if
(
!
h
||
!
h
[
0
])
return
;
addlen
=
strlen
(
header
)
+
2
+
strlen
(
h
[
0
])
+
1
;
/* realloc if necessary */
if
(
(
*
outlen
)
+
addlen
>=
*
outalloc
)
{
*
outalloc
=
(
*
outlen
)
+
addlen
+
GROW_AMOUNT
;
*
out
=
xrealloc
(
*
out
,
*
outalloc
);
}
/* add header name and value */
strcat
(
*
out
,
header
);
strcat
(
*
out
,
": "
);
strcat
(
*
out
,
h
[
0
]);
strcat
(
*
out
,
"
\n
"
);
*
outlen
+=
addlen
;
}
static
int
fillin_headers
(
sieve_interp_t
*
i
,
stringlist_t
*
sl
,
void
*
message_context
,
char
**
out
,
int
*
outlen
)
{
int
allocsize
=
GROW_AMOUNT
;
*
out
=
xmalloc
(
GROW_AMOUNT
);
*
outlen
=
0
;
(
*
out
)[
0
]
=
'\0'
;
if
(
sl
==
NULL
)
{
add_header
(
i
,
"To"
,
message_context
,
out
,
outlen
,
&
allocsize
);
add_header
(
i
,
"From"
,
message_context
,
out
,
outlen
,
&
allocsize
);
add_header
(
i
,
"Subject"
,
message_context
,
out
,
outlen
,
&
allocsize
);
}
else
{
while
(
sl
!=
NULL
)
{
add_header
(
i
,
sl
->
s
,
message_context
,
out
,
outlen
,
&
allocsize
);
sl
=
sl
->
next
;
}
}
return
SIEVE_OK
;
}
static
int
sieve_addflag
(
sieve_imapflags_t
*
imapflags
,
char
*
flag
)
{
int
n
;
/* search for flag already in list */
for
(
n
=
0
;
n
<
imapflags
->
nflags
;
n
++
)
{
if
(
!
strcmp
(
imapflags
->
flag
[
n
],
flag
))
break
;
}
/* add flag to list, iff not in list */
if
(
n
==
imapflags
->
nflags
)
{
imapflags
->
nflags
++
;
imapflags
->
flag
=
(
char
**
)
xrealloc
((
char
*
)
imapflags
->
flag
,
imapflags
->
nflags
*
sizeof
(
char
*
));
imapflags
->
flag
[
imapflags
->
nflags
-1
]
=
strdup
(
flag
);
}
return
SIEVE_OK
;
}
static
int
sieve_removeflag
(
sieve_imapflags_t
*
imapflags
,
char
*
flag
)
{
int
n
;
/* search for flag already in list */
for
(
n
=
0
;
n
<
imapflags
->
nflags
;
n
++
)
{
if
(
!
strcmp
(
imapflags
->
flag
[
n
],
flag
))
break
;
}
/* remove flag from list, iff in list */
if
(
n
<
imapflags
->
nflags
)
{
free
(
imapflags
->
flag
[
n
]);
imapflags
->
nflags
--
;
for
(;
n
<
imapflags
->
nflags
;
n
++
)
imapflags
->
flag
[
n
]
=
imapflags
->
flag
[
n
+
1
];
imapflags
->
flag
=
(
char
**
)
xrealloc
((
char
*
)
imapflags
->
flag
,
imapflags
->
nflags
*
sizeof
(
char
*
));
}
return
SIEVE_OK
;
}
static
int
send_notify_callback
(
sieve_script_t
*
s
,
void
*
message_context
,
notify_action_t
*
notify
,
char
*
actions_string
,
const
char
**
errmsg
)
{
char
*
headers
;
int
headerslen
;
int
ret
;
sieve_notify_context_t
nc
;
fillin_headers
(
&
(
s
->
interp
),
notify
->
headers
,
message_context
,
&
headers
,
&
headerslen
);
nc
.
message
=
xmalloc
(
strlen
(
notify
->
message
)
+
headerslen
+
strlen
(
actions_string
)
+
30
);
strcpy
(
nc
.
message
,
notify
->
message
);
strcat
(
nc
.
message
,
"
\n\n
"
);
strcat
(
nc
.
message
,
headers
);
strcat
(
nc
.
message
,
"
\n
"
);
free
(
headers
);
strcat
(
nc
.
message
,
actions_string
);
nc
.
priority
=
notify
->
priority
;
ret
=
s
->
interp
.
notify
(
&
nc
,
s
->
interp
.
interp_context
,
s
->
script_context
,
message_context
,
errmsg
);
free
(
nc
.
message
);
return
ret
;
}
static
char
*
action_to_string
(
action_t
action
)
{
switch
(
action
)
{
case
ACTION_REJECT
:
return
"Reject"
;
case
ACTION_FILEINTO
:
return
"Fileinto"
;
case
ACTION_KEEP
:
return
"Keep"
;
case
ACTION_REDIRECT
:
return
"Redirect"
;
case
ACTION_DISCARD
:
return
"Discard"
;
case
ACTION_VACATION
:
return
"Vacation"
;
case
ACTION_SETFLAG
:
return
"Setflag"
;
case
ACTION_ADDFLAG
:
return
"Addflag"
;
case
ACTION_REMOVEFLAG
:
return
"Removeflag"
;
case
ACTION_MARK
:
return
"Mark"
;
case
ACTION_UNMARK
:
return
"Unmark"
;
case
ACTION_NOTIFY
:
return
"Notify"
;
case
ACTION_DENOTIFY
:
return
"Denotify"
;
default
:
return
"Unknown"
;
}
return
"Error!"
;
}
static
char
*
sieve_errstr
(
int
code
)
{
switch
(
code
)
{
case
SIEVE_FAIL
:
return
"Generic Error"
;
case
SIEVE_NOT_FINALIZED
:
return
"Sieve not finalized"
;
case
SIEVE_PARSE_ERROR
:
return
"Parse error"
;
case
SIEVE_RUN_ERROR
:
return
"Run error"
;
case
SIEVE_INTERNAL_ERROR
:
return
"Internal Error"
;
case
SIEVE_NOMEM
:
return
"No memory"
;
default
:
return
"Unknown error"
;
}
return
"Error!"
;
}
#define HASHSIZE 16
static
int
makehash
(
unsigned
char
hash
[
HASHSIZE
],
char
*
s1
,
char
*
s2
)
{
MD5_CTX
ctx
;
MD5Init
(
&
ctx
);
MD5Update
(
&
ctx
,
s1
,
strlen
(
s1
));
MD5Update
(
&
ctx
,
s2
,
strlen
(
s2
));
MD5Final
(
hash
,
&
ctx
);
return
SIEVE_OK
;
}
/* execute a script on a message, producing side effects via callbacks.
it is the responsibility of the caller to save a message if this
returns anything but SIEVE_OK. */
int
sieve_execute_script
(
sieve_script_t
*
s
,
void
*
message_context
)
{
int
ret
=
0
;
int
implicit_keep
;
action_list_t
*
actions
=
NULL
,
*
a
;
action_t
lastaction
=
-1
;
notify_action_t
*
notify_action
;
char
actions_string
[
4096
]
=
""
;
const
char
*
errmsg
=
NULL
;
notify_action
=
default_notify_action
();
if
(
notify_action
==
NULL
)
return
SIEVE_NOMEM
;
actions
=
new_action_list
();
if
(
actions
==
NULL
)
{
ret
=
SIEVE_NOMEM
;
goto
error
;
}
if
((
ret
=
eval
(
&
s
->
interp
,
s
->
cmds
,
message_context
,
actions
,
notify_action
,
&
errmsg
))
!=
SIEVE_OK
)
return
SIEVE_RUN_ERROR
;
strcpy
(
actions_string
,
"Action(s) taken:
\n
"
);
/* now perform actions attached to m */
a
=
actions
;
implicit_keep
=
1
;
while
(
a
!=
NULL
)
{
lastaction
=
a
->
a
;
errmsg
=
NULL
;
switch
(
a
->
a
)
{
case
ACTION_REJECT
:
implicit_keep
=
0
;
if
(
!
s
->
interp
.
reject
)
return
SIEVE_INTERNAL_ERROR
;
ret
=
s
->
interp
.
reject
(
&
a
->
u
.
rej
,
s
->
interp
.
interp_context
,
s
->
script_context
,
message_context
,
&
errmsg
);
if
(
ret
==
SIEVE_OK
)
snprintf
(
actions_string
+
strlen
(
actions_string
),
sizeof
(
actions_string
)
-
strlen
(
actions_string
),
"Rejected with: %s
\n
"
,
a
->
u
.
rej
.
msg
);
break
;
case
ACTION_FILEINTO
:
implicit_keep
=
0
;
if
(
!
s
->
interp
.
fileinto
)
return
SIEVE_INTERNAL_ERROR
;
ret
=
s
->
interp
.
fileinto
(
&
a
->
u
.
fil
,
s
->
interp
.
interp_context
,
s
->
script_context
,
message_context
,
&
errmsg
);
if
(
ret
==
SIEVE_OK
)
snprintf
(
actions_string
+
strlen
(
actions_string
),
sizeof
(
actions_string
)
-
strlen
(
actions_string
),
"Filed into: %s
\n
"
,
a
->
u
.
fil
.
mailbox
);
break
;
case
ACTION_KEEP
:
implicit_keep
=
0
;
if
(
!
s
->
interp
.
keep
)
return
SIEVE_INTERNAL_ERROR
;
ret
=
s
->
interp
.
keep
(
&
a
->
u
.
keep
,
s
->
interp
.
interp_context
,
s
->
script_context
,
message_context
,
&
errmsg
);
if
(
ret
==
SIEVE_OK
)
snprintf
(
actions_string
+
strlen
(
actions_string
),
sizeof
(
actions_string
)
-
strlen
(
actions_string
),
"Kept
\n
"
);
break
;
case
ACTION_REDIRECT
:
implicit_keep
=
0
;
if
(
!
s
->
interp
.
redirect
)
return
SIEVE_INTERNAL_ERROR
;
ret
=
s
->
interp
.
redirect
(
&
a
->
u
.
red
,
s
->
interp
.
interp_context
,
s
->
script_context
,
message_context
,
&
errmsg
);
if
(
ret
==
SIEVE_OK
)
snprintf
(
actions_string
+
strlen
(
actions_string
),
sizeof
(
actions_string
)
-
strlen
(
actions_string
),
"Redirected to %s
\n
"
,
a
->
u
.
red
.
addr
);
break
;
case
ACTION_DISCARD
:
implicit_keep
=
0
;
if
(
s
->
interp
.
discard
)
/* discard is optional */
ret
=
s
->
interp
.
discard
(
NULL
,
s
->
interp
.
interp_context
,
s
->
script_context
,
message_context
,
&
errmsg
);
if
(
ret
==
SIEVE_OK
)
snprintf
(
actions_string
+
strlen
(
actions_string
),
sizeof
(
actions_string
)
-
strlen
(
actions_string
),
"Discarded
\n
"
);
break
;
case
ACTION_VACATION
:
{
unsigned
char
hash
[
HASHSIZE
];
if
(
!
s
->
interp
.
vacation
)
return
SIEVE_INTERNAL_ERROR
;
/* first, let's figure out if we should respond to this */
ret
=
makehash
(
hash
,
a
->
u
.
vac
.
send
.
addr
,
a
->
u
.
vac
.
send
.
msg
);
if
(
ret
==
SIEVE_OK
)
{
a
->
u
.
vac
.
autoresp
.
hash
=
hash
;
a
->
u
.
vac
.
autoresp
.
len
=
HASHSIZE
;
ret
=
s
->
interp
.
vacation
->
autorespond
(
&
a
->
u
.
vac
.
autoresp
,
s
->
interp
.
interp_context
,
s
->
script_context
,
message_context
,
&
errmsg
);
}
if
(
ret
==
SIEVE_OK
)
{
/* send the response */
ret
=
s
->
interp
.
vacation
->
send_response
(
&
a
->
u
.
vac
.
send
,
s
->
interp
.
interp_context
,
s
->
script_context
,
message_context
,
&
errmsg
);
if
(
ret
==
SIEVE_OK
)
snprintf
(
actions_string
+
strlen
(
actions_string
),
sizeof
(
actions_string
)
-
strlen
(
actions_string
),
"Sent vacation reply
\n
"
);
}
else
if
(
ret
==
SIEVE_DONE
)
{
if
(
ret
==
SIEVE_OK
)
snprintf
(
actions_string
+
strlen
(
actions_string
),
sizeof
(
actions_string
)
-
strlen
(
actions_string
),
"Vacation reply suppressed
\n
"
);
ret
=
SIEVE_OK
;
}
break
;
}
case
ACTION_SETFLAG
:
free_imapflags
(
&
s
->
interp
.
curflags
);
ret
=
sieve_addflag
(
&
s
->
interp
.
curflags
,
a
->
u
.
fla
.
flag
);
break
;
case
ACTION_ADDFLAG
:
ret
=
sieve_addflag
(
&
s
->
interp
.
curflags
,
a
->
u
.
fla
.
flag
);
break
;
case
ACTION_REMOVEFLAG
:
ret
=
sieve_removeflag
(
&
s
->
interp
.
curflags
,
a
->
u
.
fla
.
flag
);
break
;
case
ACTION_MARK
:
{
int
n
=
s
->
interp
.
markflags
->
nflags
;
ret
=
SIEVE_OK
;
while
(
n
&&
ret
==
SIEVE_OK
)
{
ret
=
sieve_addflag
(
&
s
->
interp
.
curflags
,
s
->
interp
.
markflags
->
flag
[
--
n
]);
}
break
;
}
case
ACTION_UNMARK
:
{
int
n
=
s
->
interp
.
markflags
->
nflags
;
ret
=
SIEVE_OK
;
while
(
n
&&
ret
==
SIEVE_OK
)
{
ret
=
sieve_removeflag
(
&
s
->
interp
.
curflags
,
s
->
interp
.
markflags
->
flag
[
--
n
]);
}
break
;
}
case
ACTION_NONE
:
break
;
default
:
ret
=
SIEVE_INTERNAL_ERROR
;
break
;
}
a
=
a
->
next
;
if
(
ret
!=
SIEVE_OK
)
{
/* uh oh! better bail! */
break
;
}
}
if
(
implicit_keep
)
{
sieve_keep_context_t
keep_context
=
{
&
s
->
interp
.
curflags
};
lastaction
=
ACTION_KEEP
;
ret
=
s
->
interp
.
keep
(
&
keep_context
,
s
->
interp
.
interp_context
,
s
->
script_context
,
message_context
,
&
errmsg
);
if
(
ret
==
SIEVE_OK
)
snprintf
(
actions_string
+
strlen
(
actions_string
),
sizeof
(
actions_string
)
-
strlen
(
actions_string
),
"Kept
\n
"
);
}
error
:
/* report run-time errors */
if
(
ret
!=
SIEVE_OK
)
{
if
(
lastaction
==
-1
)
/* we never executed an action */
snprintf
(
actions_string
+
strlen
(
actions_string
),
sizeof
(
actions_string
)
-
strlen
(
actions_string
),
"script execution failed: %s
\n
"
,
errmsg
?
errmsg
:
sieve_errstr
(
ret
));
else
snprintf
(
actions_string
+
strlen
(
actions_string
),
sizeof
(
actions_string
)
-
strlen
(
actions_string
),
"%s action failed: %s
\n
"
,
action_to_string
(
lastaction
),
errmsg
?
errmsg
:
sieve_errstr
(
ret
));
}
/* Process notify action if there is one */
if
(
s
->
interp
.
notify
&&
notify_action
->
exists
)
{
ret
|=
send_notify_callback
(
s
,
message_context
,
notify_action
,
actions_string
,
&
errmsg
);
}
if
((
ret
!=
SIEVE_OK
)
&&
s
->
interp
.
err
)
{
char
buf
[
1024
];
if
(
lastaction
==
-1
)
/* we never executed an action */
sprintf
(
buf
,
"%s"
,
errmsg
?
errmsg
:
sieve_errstr
(
ret
));
else
sprintf
(
buf
,
"%s: %s"
,
action_to_string
(
lastaction
),
errmsg
?
errmsg
:
sieve_errstr
(
ret
));
ret
|=
s
->
interp
.
execute_err
(
buf
,
s
->
interp
.
interp_context
,
s
->
script_context
,
message_context
);
}
if
(
actions
)
free_action_list
(
actions
);
return
ret
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Fri, Apr 24, 10:39 AM (2 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18859871
Default Alt Text
script.c (25 KB)
Attached To
Mode
R111 cyrus-imapd
Attached
Detach File
Event Timeline