Page MenuHomePhorge

bc_eval.c
No OneTemporary

Authored By
Unknown
Size
32 KB
Referenced Files
None
Subscribers
None

bc_eval.c

/* bc_eval.c - evaluate the bytecode
*
* Copyright (c) 1994-2008 Carnegie Mellon University. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name "Carnegie Mellon University" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For permission or any legal
* details, please contact
* Carnegie Mellon University
* Center for Technology Transfer and Enterprise Creation
* 4615 Forbes Avenue
* Suite 302
* Pittsburgh, PA 15213
* (412) 268-7393, fax: (412) 268-7395
* innovation@andrew.cmu.edu
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Computing Services
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
*
* 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.
*
* $Id: bc_eval.c,v 1.19.2.2 2010/02/12 03:41:11 brong Exp $
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "sieve_interface.h"
#include "interp.h"
#include "message.h"
#include "script.h"
#include "parseaddr.h"
#include "bytecode.h"
#include "charset.h"
#include "hash.h"
#include "xmalloc.h"
#include "xstrlcpy.h"
#include "xstrlcat.h"
#include "util.h"
#include <string.h>
#include <ctype.h>
#define SCOUNT_SIZE 20
char scount[SCOUNT_SIZE];
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/**************************EXECUTING BYTECODE******************************/
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* Given a bytecode_input_t at the beginning of a string (the len block),
* return the string, the length, and the bytecode index of the NEXT
* item */
int unwrap_string(bytecode_input_t *bc, int pos, const char **str, int *len)
{
int local_len = ntohl(bc[pos].value);
pos++;
if(local_len == -1) {
/* -1 length indicates NULL */
*str = NULL;
} else {
/* This cast is ugly, but necessary */
*str = (const char *)&bc[pos].str;
/* Compute the next index */
pos += ((ROUNDUP(local_len+1))/sizeof(bytecode_input_t));
}
if(len) *len = local_len;
return pos;
}
/* this is used by notify to pass the options list to do_notify
* do_notify needs null-terminated (char *)[],
* we have a stringlist, the beginning of which is pointed at by pos */
static const char ** bc_makeArray(bytecode_input_t *bc, int *pos)
{
int i;
const char** array;
int len = ntohl(bc[*pos].value);
(*pos)+=2; /* Skip # Values and Total Byte Length */
array=(const char **)xmalloc((len+1) * sizeof(char *));
for (i=0; i<len; i++) {
*pos = unwrap_string(bc, *pos, &(array[i]), NULL);
}
array[i] = NULL;
return array;
}
/* Compile a regular expression for use during parsing */
static regex_t * bc_compile_regex(const char *s, int ctag,
char *errmsg, size_t errsiz)
{
int ret;
regex_t *reg = (regex_t *) xmalloc(sizeof(regex_t));
#ifdef HAVE_PCREPOSIX_H
/* support UTF8 comparisons */
ctag |= REG_UTF8;
#endif
if ( (ret=regcomp(reg, s, ctag)) != 0)
{
(void) regerror(ret, reg, errmsg, errsiz);
free(reg);
return NULL;
}
return reg;
}
/* Determine if addr is a system address */
static int sysaddr(const 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 - return the match */
static char* look_for_me(char *myaddr, int numaddresses,
bytecode_input_t *bc, int i, const char **body)
{
char *found = NULL;
int l;
int curra,x ;
/* loop through each TO header */
for (l = 0; body[l] != NULL && !found; l++) {
struct address_itr ai;
const struct address *a;
address_itr_init(&ai, body[l]);
/* loop through each address in the header */
while (!found && (a = address_itr_next(&ai)) != NULL) {
char *addr = address_get_all(a, 0);
if (!addr) addr = xstrdup("");
if (!strcasecmp(addr, myaddr)) {
free(addr);
found = xstrdup(myaddr);
break;
}
curra=i;
for(x=0; x<numaddresses; x++)
{
char *altaddr;
const char *str;
curra = unwrap_string(bc, curra, &str, NULL);
/* is this address one of my addresses? */
altaddr = address_canonicalise(str);
if (!strcasecmp(addr,altaddr)) {
free(altaddr);
found=xstrdup(str);
break;
}
free(altaddr);
}
free(addr);
}
address_itr_fini(&ai);
}
return found;
}
static char *list_fields[] = {
"list-id",
"list-help",
"list-subscribe",
"list-unsubscribe",
"list-post",
"list-owner",
"list-archive",
NULL
};
/* Determine if we should respond to a vacation message */
static int shouldRespond(void * m, sieve_interp_t *interp,
int numaddresses, bytecode_input_t* bc,
int i, char **from, char **to)
{
const char **body;
char buf[128];
char *myaddr = NULL;
int l = SIEVE_OK, j;
int curra, x;
char *found = NULL;
char *reply_to = NULL;
/* Implementations SHOULD NOT respond to any message that contains a
"List-Id" [RFC2919], "List-Help", "List-Subscribe", "List-
Unsubscribe", "List-Post", "List-Owner" or "List-Archive" [RFC2369]
header field. */
for (j = 0; list_fields[j]; j++) {
strcpy(buf, list_fields[j]);
if (interp->getheader(m, buf, &body) == SIEVE_OK) {
l = SIEVE_DONE;
break;
}
}
/* Implementations SHOULD NOT respond to any message that has an
"Auto-submitted" header field with a value other than "no".
This header field is described in [RFC3834]. */
strcpy(buf, "auto-submitted");
if (interp->getheader(m, buf, &body) == SIEVE_OK) {
/* we don't deal with comments, etc. here */
/* skip leading white-space */
while (*body[0] && Uisspace(*body[0])) body[0]++;
if (strcasecmp(body[0], "no")) l = SIEVE_DONE;
}
/* is there a Precedence keyword of "junk | bulk | list"? */
/* XXX non-standard header, but worth checking */
strcpy(buf, "precedence");
if (interp->getheader(m, buf, &body) == SIEVE_OK) {
/* we don't deal with comments, etc. here */
/* skip leading white-space */
while (*body[0] && Uisspace(*body[0])) body[0]++;
if (!strcasecmp(body[0], "junk") ||
!strcasecmp(body[0], "bulk") ||
!strcasecmp(body[0], "list"))
l = SIEVE_DONE;
}
/* Note: the domain-part of all addresses are canonicalized */
/* grab my address from the envelope */
if (l == SIEVE_OK) {
strcpy(buf, "to");
l = interp->getenvelope(m, buf, &body);
if (body[0])
myaddr = address_canonicalise(body[0]);
}
if (l == SIEVE_OK) {
strcpy(buf, "from");
l = interp->getenvelope(m, buf, &body);
}
if (l == SIEVE_OK && body[0]) {
/* we have to parse this address & decide whether we
want to respond to it */
reply_to = address_canonicalise(body[0]);
/* first, is there a reply-to address? */
if (reply_to == NULL) {
l = SIEVE_DONE;
}
/* first, is it from me? */
if (l == SIEVE_OK && myaddr && !strcmp(myaddr, reply_to)) {
l = SIEVE_DONE;
}
/* ok, is it any of the other addresses i've
specified? */
if (l == SIEVE_OK)
{
curra=i;
for(x=0; x<numaddresses; x++) {
const char *address;
curra = unwrap_string(bc, curra, &address, NULL);
if (!strcmp(address, 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) {
/* ok, we're willing to respond to the sender.
but is this message to me? that is, is my address
in the [Resent]-To, [Resent]-Cc or [Resent]-Bcc fields? */
if (strcpy(buf, "to"),
interp->getheader(m, buf, &body) == SIEVE_OK)
found = look_for_me(myaddr, numaddresses ,bc, i, body);
if (!found && (strcpy(buf, "cc"),
(interp->getheader(m, buf, &body) == SIEVE_OK)))
found = look_for_me(myaddr, numaddresses, bc, i, body);
if (!found && (strcpy(buf, "bcc"),
(interp->getheader(m, buf, &body) == SIEVE_OK)))
found = look_for_me(myaddr, numaddresses, bc, i, body);
if (!found && (strcpy(buf, "resent-to"),
(interp->getheader(m, buf, &body) == SIEVE_OK)))
found = look_for_me(myaddr, numaddresses ,bc, i, body);
if (!found && (strcpy(buf, "resent-cc"),
(interp->getheader(m, buf, &body) == SIEVE_OK)))
found = look_for_me(myaddr, numaddresses, bc, i, body);
if (!found && (strcpy(buf, "resent-bcc"),
(interp->getheader(m, buf, &body) == SIEVE_OK)))
found = look_for_me(myaddr, numaddresses, bc, i, body);
if (!found)
l = SIEVE_DONE;
}
/* ok, ok, if we got here maybe we should reply */
if (myaddr) free(myaddr);
*from = found;
*to = reply_to;
return l;
}
/* Evaluate a bytecode test */
static int eval_bc_test(sieve_interp_t *interp, void* m,
bytecode_input_t * bc, int * ip)
{
int res=0;
int i=*ip;
int x,y,z;/* loop variable */
int list_len; /* for allof/anyof/exists */
int list_end; /* for allof/anyof/exists */
int address=0;/*to differentiate between address and envelope*/
comparator_t * comp=NULL;
void * comprock=NULL;
int op= ntohl(bc[i].op);
switch(op)
{
case BC_FALSE:
res=0; i++; break;
case BC_TRUE:
res=1; i++; break;
case BC_NOT:/*2*/
i+=1;
res = eval_bc_test(interp, m, bc, &i);
if(res >= 0) res = !res; /* Only invert in non-error case */
break;
case BC_EXISTS:/*3*/
{
int headersi=i+1;
const char** val;
int currh;
res=1;
list_len=ntohl(bc[headersi].len);
list_end=ntohl(bc[headersi+1].value)/4;
currh=headersi+2;
for(x=0; x<list_len && res; x++)
{
const char *str;
currh = unwrap_string(bc, currh, &str, NULL);
if(interp->getheader(m,str, &val) != SIEVE_OK)
res = 0;
}
i=list_end; /* adjust for short-circuit */
break;
}
case BC_SIZE:/*4*/
{
int s;
int sizevar=ntohl(bc[i+1].value);
int x=ntohl(bc[i+2].value);
if (interp->getsize(m, &s) != SIEVE_OK)
break;
if (sizevar ==B_OVER) {
/* over */
res= s > x;
} else {
/* under */
res= s < x;
}
i+=3;
break;
}
case BC_ANYOF:/*5*/
res = 0;
list_len=ntohl(bc[i+1].len);
list_end=ntohl(bc[i+2].len)/4;
i+=3;
/* need to process all of them, to ensure our instruction pointer stays
* in the right place */
for (x=0; x<list_len && !res; x++) {
int tmp;
tmp = eval_bc_test(interp, m, bc, &i);
if(tmp < 0) {
res = tmp;
break;
}
res = res || tmp;
}
i = list_end; /* handle short-circuting */
break;
case BC_ALLOF:/*6*/
res = 1;
list_len=ntohl(bc[i+1].len);
list_end=ntohl(bc[i+2].len)/4;
i+=3;
/* return 1 unless you find one that isn't true, then return 0 */
for (x=0; x<list_len && res; x++) {
int tmp;
tmp = eval_bc_test(interp, m, bc, &i);
if(tmp < 0) {
res = tmp;
break;
}
res = res && tmp;
}
i = list_end; /* handle short-circuiting */
break;
case BC_ADDRESS:/*7*/
address=1;
/* fall through */
case BC_ENVELOPE:/*8*/
{
const char ** val;
struct address_itr ai;
const struct address *a;
char *addr;
int headersi=i+5;/* the i value for the begining of the headers */
int datai=(ntohl(bc[headersi+1].value)/4);
int numheaders=ntohl(bc[headersi].len);
int numdata=ntohl(bc[datai].len);
int currh, currd; /* current header, current data */
int match=ntohl(bc[i+1].value);
int relation=ntohl(bc[i+2].value);
int comparator=ntohl(bc[i+3].value);
int apart=ntohl(bc[i+4].value);
int count=0;
int isReg = (match==B_REGEX);
int ctag = 0;
regex_t *reg;
char errbuf[100]; /* Basically unused, as regexps are tested at compile */
/* set up variables needed for compiling regex */
if (isReg)
{
if (comparator== B_ASCIICASEMAP)
{
ctag = REG_EXTENDED | REG_NOSUB | REG_ICASE;
}
else
{
ctag = REG_EXTENDED | REG_NOSUB;
}
}
/*find the correct comparator fcn*/
comp = lookup_comp(comparator, match, relation, &comprock);
if(!comp) {
res = SIEVE_RUN_ERROR;
break;
}
/*loop through all the headers*/
currh=headersi+2;
#if VERBOSE
printf("about to process %d headers\n", numheaders);
#endif
for (x=0; x<numheaders && !res; x++)
{
const char *this_header;
currh = unwrap_string(bc, currh, &this_header, NULL);
/* Try the next string if we don't have this one */
if(address) {
/* Header */
if(interp->getheader(m, this_header, &val) != SIEVE_OK)
continue;
#if VERBOSE
printf(" [%d] header %s is %s\n", x, this_header, val[0]);
#endif
} else {
/* Envelope */
if(interp->getenvelope(m, this_header, &val) != SIEVE_OK)
continue;
}
/*header exists, now to test it*/
/*search through all the headers that match*/
for (y=0; val[y]!=NULL && !res; y++) {
#if VERBOSE
printf("about to parse %s\n", val[y]);
#endif
address_itr_init(&ai, val[y]);
while (!res && (a = address_itr_next(&ai)) != NULL) {
#if VERBOSE
printf("working addr %s\n", (addr ? addr : "[nil]"));
#endif
/*find the part of the address that we want*/
switch(apart)
{
case B_ALL:
addr = address_get_all(a, /*canon_domain*/0);
break;
case B_LOCALPART:
addr = address_get_localpart(a);
break;
case B_DOMAIN:
addr = address_get_domain(a, /*canon_domain*/0);
break;
case B_USER:
addr = address_get_user(a);
break;
case B_DETAIL:
addr = address_get_detail(a);
break;
default:
/* this shouldn't happen with correct bytecode */
res = SIEVE_RUN_ERROR;
goto envelope_err;
}
if (!addr) addr = xstrdup("");
if (match == B_COUNT) {
count++;
} else {
/*search through all the data*/
currd=datai+2;
for (z=0; z<numdata && !res; z++)
{
const char *data_val;
currd = unwrap_string(bc, currd, &data_val, NULL);
if (isReg) {
reg = bc_compile_regex(data_val, ctag,
errbuf, sizeof(errbuf));
if (!reg) {
/* Oops */
free(addr);
res=-1;
goto alldone;
}
res |= comp(addr, strlen(addr),
(const char *)reg, comprock);
free(reg);
} else {
#if VERBOSE
printf("%s compared to %s(from script)\n",
addr, data_val);
#endif
res |= comp(addr, strlen(addr),
data_val, comprock);
}
} /* For each data */
}
free(addr);
} /* For each address */
address_itr_fini(&ai);
}/* For each message header */
#if VERBOSE
printf("end of loop, res is %d, x is %d (%d)\n", res, x, numheaders);
#endif
} /* For each script header */
if (match == B_COUNT)
{
snprintf(scount, SCOUNT_SIZE, "%u", count);
/* search through all the data */
currd=datai+2;
for (z=0; z<numdata && !res; z++)
{
const char *data_val;
currd = unwrap_string(bc, currd, &data_val, NULL);
res |= comp(scount, strlen(scount), data_val, comprock);
}
}
/* Update IP */
i=(ntohl(bc[datai+1].value)/4);
envelope_err:
break;
}
case BC_HEADER:/*9*/
{
const char** val;
int headersi=i+4;/*the i value for the begining of hte headers*/
int datai=(ntohl(bc[headersi+1].value)/4);
int numheaders=ntohl(bc[headersi].len);
int numdata=ntohl(bc[datai].len);
int currh, currd; /*current header, current data*/
int match=ntohl(bc[i+1].value);
int relation=ntohl(bc[i+2].value);
int comparator=ntohl(bc[i+3].value);
int count=0;
int isReg = (match==B_REGEX);
int ctag = 0;
regex_t *reg;
char errbuf[100]; /* Basically unused, regexps tested at compile */
char *decoded_header;
/* set up variables needed for compiling regex */
if (isReg)
{
if (comparator== B_ASCIICASEMAP)
{
ctag= REG_EXTENDED | REG_NOSUB | REG_ICASE;
}
else
{
ctag= REG_EXTENDED | REG_NOSUB;
}
}
/*find the correct comparator fcn*/
comp=lookup_comp(comparator, match, relation, &comprock);
if(!comp) {
res = SIEVE_RUN_ERROR;
break;
}
/*search through all the flags for the header*/
currh=headersi+2;
for(x=0; x<numheaders && !res; x++)
{
const char *this_header;
currh = unwrap_string(bc, currh, &this_header, NULL);
if(interp->getheader(m, this_header, &val) != SIEVE_OK) {
continue; /*this header does not exist, search the next*/
}
#if VERBOSE
printf ("val %s %s %s\n", val[0], val[1], val[2]);
#endif
/* search through all the headers that match */
for (y = 0; val[y] && !res; y++)
{
if (match == B_COUNT) {
count++;
} else {
decoded_header = charset_parse_mimeheader(val[y]);
/*search through all the data*/
currd=datai+2;
for (z=0; z<numdata && !res; z++)
{
const char *data_val;
currd = unwrap_string(bc, currd, &data_val, NULL);
if (isReg) {
reg= bc_compile_regex(data_val, ctag, errbuf,
sizeof(errbuf));
if (!reg)
{
/* Oops */
res=-1;
goto alldone;
}
res |= comp(decoded_header, strlen(decoded_header),
(const char *)reg, comprock);
free(reg);
} else {
res |= comp(decoded_header, strlen(decoded_header),
data_val, comprock);
}
}
free(decoded_header);
}
}
}
if (match == B_COUNT )
{
snprintf(scount, SCOUNT_SIZE, "%u", count);
/*search through all the data*/
currd=datai+2;
for (z=0; z<numdata && !res; z++)
{
const char *data_val;
currd = unwrap_string(bc, currd, &data_val, NULL);
#if VERBOSE
printf("%d, %s \n", count, data_val);
#endif
res |= comp(scount, strlen(scount), data_val, comprock);
}
}
/* Update IP */
i=(ntohl(bc[datai+1].value)/4);
break;
}
case BC_BODY:/*10*/
{
sieve_bodypart_t ** val;
const char **content_types = NULL;
int typesi=i+6;/* the i value for the begining of the content-types */
int datai=(ntohl(bc[typesi+1].value)/4);
int numdata=ntohl(bc[datai].len);
int currd; /* current data */
int match=ntohl(bc[i+1].value);
int relation=ntohl(bc[i+2].value);
int comparator=ntohl(bc[i+3].value);
int transform=ntohl(bc[i+4].value);
/* ntohl(bc[i+5].value) is the now unused 'offset' */
int count=0;
int isReg = (match==B_REGEX);
int ctag = 0;
regex_t *reg;
char errbuf[100]; /* Basically unused, as regexps are tested at compile */
/* set up variables needed for compiling regex */
if (isReg)
{
if (comparator== B_ASCIICASEMAP)
{
ctag = REG_EXTENDED | REG_NOSUB | REG_ICASE;
}
else
{
ctag = REG_EXTENDED | REG_NOSUB;
}
}
/*find the correct comparator fcn*/
comp = lookup_comp(comparator, match, relation, &comprock);
if(!comp) {
res = SIEVE_RUN_ERROR;
break;
}
if (transform == B_RAW) {
/* XXX - we never handled this properly, it has to search the
* RAW message body, totally un-decoded, as a single string
*
* ignore - or just search in the UTF-8. I think the UTF-8 makes more sense
*/
/* break; */
}
/*find the part(s) of the body that we want*/
content_types = bc_makeArray(bc, &typesi);
if(interp->getbody(m, content_types, &val) != SIEVE_OK) {
res = SIEVE_RUN_ERROR;
break;
}
free(content_types);
/* bodypart(s) exist, now to test them */
for (y = 0; val && val[y] && !res; y++) {
if (match == B_COUNT) {
count++;
} else if (val[y]->decoded_body) {
const char *content = val[y]->decoded_body;
/* search through all the data */
currd=datai+2;
for (z=0; z<numdata && !res; z++)
{
const char *data_val;
currd = unwrap_string(bc, currd, &data_val, NULL);
if (isReg) {
reg = bc_compile_regex(data_val, ctag,
errbuf, sizeof(errbuf));
if (!reg) {
/* Oops */
res=-1;
goto alldone;
}
res |= comp(content, strlen(content), (const char *)reg, comprock);
free(reg);
} else {
res |= comp(content, strlen(content), data_val, comprock);
}
} /* For each data */
}
/* free the bodypart */
free(val[y]);
} /* For each body part */
/* free the bodypart array */
if (val) free(val);
if (match == B_COUNT)
{
snprintf(scount, SCOUNT_SIZE, "%u", count);
/* search through all the data */
currd=datai+2;
for (z=0; z<numdata && !res; z++)
{
const char *data_val;
currd = unwrap_string(bc, currd, &data_val, NULL);
res |= comp(scount, strlen(scount), data_val, comprock);
}
}
/* Update IP */
i=(ntohl(bc[datai+1].value)/4);
break;
}
default:
#if VERBOSE
printf("WERT, can't evaluate if statement. %d is not a valid command",
op);
#endif
return SIEVE_RUN_ERROR;
}
alldone:
*ip=i;
return res;
}
/* The entrypoint for bytecode evaluation */
int sieve_eval_bc(sieve_execute_t *exe, int is_incl, sieve_interp_t *i,
void *sc, void *m,
strarray_t *imapflags, action_list_t *actions,
notify_list_t *notify_list, const char **errmsg)
{
const char *data;
int res=0;
int op;
int version;
sieve_bytecode_t *bc_cur = exe->bc_cur;
bytecode_input_t *bc = (bytecode_input_t *) bc_cur->data;
int ip = 0, ip_max = (bc_cur->len/sizeof(bytecode_input_t));
if (bc_cur->is_executing) {
*errmsg = "Recursive Include";
return SIEVE_RUN_ERROR;
}
bc_cur->is_executing = 1;
/* Check that we
* a) have bytecode
* b) it is atleast long enough for the magic number, the version
* and one opcode */
if(!bc) return SIEVE_FAIL;
if(bc_cur->len < (BYTECODE_MAGIC_LEN + 2*sizeof(bytecode_input_t)))
return SIEVE_FAIL;
if(memcmp(bc, BYTECODE_MAGIC, BYTECODE_MAGIC_LEN)) {
*errmsg = "Not a bytecode file";
return SIEVE_FAIL;
}
ip = BYTECODE_MAGIC_LEN / sizeof(bytecode_input_t);
version= ntohl(bc[ip].op);
/* this is because there was a time where integers were not network byte
order. all the scripts written then would have version 0x01 written
in host byte order.*/
if(version == (int)ntohl(1)) {
if(errmsg) {
*errmsg =
"Incorrect Bytecode Version, please recompile (use sievec)";
}
return SIEVE_FAIL;
}
if((version < BYTECODE_MIN_VERSION) || (version > BYTECODE_VERSION)) {
if(errmsg) {
*errmsg =
"Incorrect Bytecode Version, please recompile (use sievec)";
}
return SIEVE_FAIL;
}
#if VERBOSE
printf("version number %d\n",version);
#endif
for(ip++; ip<ip_max; ) {
int copy = 0;
op=ntohl(bc[ip].op);
switch(op) {
case B_STOP:/*0*/
res=1;
break;
case B_KEEP:/*1*/
res = do_keep(actions, imapflags);
if (res == SIEVE_RUN_ERROR)
*errmsg = "Keep can not be used with Reject";
ip++;
break;
case B_DISCARD:/*2*/
res=do_discard(actions);
ip++;
break;
case B_REJECT:/*3*/
ip = unwrap_string(bc, ip+1, &data, NULL);
res = do_reject(actions, data);
if (res == SIEVE_RUN_ERROR)
*errmsg = "Reject can not be used with any other action";
break;
case B_FILEINTO:/*19*/
copy = ntohl(bc[ip+1].value);
ip+=1;
/* fall through */
case B_FILEINTO_ORIG:/*4*/
{
ip = unwrap_string(bc, ip+1, &data, NULL);
res = do_fileinto(actions, data, !copy, imapflags);
if (res == SIEVE_RUN_ERROR)
*errmsg = "Fileinto can not be used with Reject";
break;
}
case B_REDIRECT:/*20*/
copy = ntohl(bc[ip+1].value);
ip+=1;
/* fall through */
case B_REDIRECT_ORIG:/*5*/
{
ip = unwrap_string(bc, ip+1, &data, NULL);
res = do_redirect(actions, data, !copy);
if (res == SIEVE_RUN_ERROR)
*errmsg = "Redirect can not be used with Reject";
break;
}
case B_IF:/*6*/
{
int testend=ntohl(bc[ip+1].value);
int result;
ip+=2;
result=eval_bc_test(i, m, bc, &ip);
if (result<0) {
*errmsg = "Invalid test";
return SIEVE_FAIL;
} else if (result) {
/*skip over jump instruction*/
testend+=2;
}
ip=testend;
break;
}
case B_MARK:/*8*/
res = do_mark(actions);
ip++;
break;
case B_UNMARK:/*9*/
res = do_unmark(actions);
ip++;
break;
case B_ADDFLAG:/*10*/
{
int x;
int list_len=ntohl(bc[ip+1].len);
ip+=3; /* skip opcode, list_len, and list data len */
for (x=0; x<list_len; x++) {
ip = unwrap_string(bc, ip, &data, NULL);
res = do_addflag(actions, data);
if (res == SIEVE_RUN_ERROR)
*errmsg = "addflag can not be used with Reject";
}
break;
}
case B_SETFLAG:
{
int x;
int list_len=ntohl(bc[ip+1].len);
ip+=3; /* skip opcode, list_len, and list data len */
ip = unwrap_string(bc, ip, &data, NULL);
res = do_setflag(actions, data);
if (res == SIEVE_RUN_ERROR) {
*errmsg = "setflag can not be used with Reject";
} else {
for (x=1; x<list_len; x++) {
ip = unwrap_string(bc, ip, &data, NULL);
res = do_addflag(actions, data);
if (res == SIEVE_RUN_ERROR)
*errmsg = "setflag can not be used with Reject";
}
}
break;
}
case B_REMOVEFLAG:
{
int x;
int list_len=ntohl(bc[ip+1].len);
ip+=3; /* skip opcode, list_len, and list data len */
for (x=0; x<list_len; x++) {
ip = unwrap_string(bc, ip, &data, NULL);
res = do_removeflag(actions, data);
if (res == SIEVE_RUN_ERROR)
*errmsg = "removeflag can not be used with Reject";
}
break;
}
case B_NOTIFY:
{
const char * id;
const char * method;
const char **options = NULL;
const char *priority = NULL;
const char * message;
int pri;
ip++;
/* method */
ip = unwrap_string(bc, ip, &method, NULL);
/* id */
ip = unwrap_string(bc, ip, &id, NULL);
/*options*/
options=bc_makeArray(bc, &ip);
/* priority */
pri=ntohl(bc[ip].value);
ip++;
switch (pri)
{
case B_LOW:
priority="low";
break;
case B_NORMAL:
priority="normal";
break;
case B_HIGH:
priority="high";
break;
case B_ANY:
priority="any";
break;
default:
res=SIEVE_RUN_ERROR;
}
/* message */
ip = unwrap_string(bc, ip, &message, NULL);
res = do_notify(notify_list, id, method, options,
priority, message);
break;
}
case B_DENOTIFY:
{
/*
* i really have no idea what the count matchtype should do here.
* the sanest thing would be to use 1.
* however that would require passing on the match type to do_notify.
* -jsmith2
*/
comparator_t *comp = NULL;
const char *pattern;
regex_t *reg;
const char *priority = NULL;
void *comprock = NULL;
int comparator;
int pri;
ip++;
pri=ntohl(bc[ip].value);
ip++;
switch (pri)
{
case B_LOW:
priority="low";
break;
case B_NORMAL:
priority="normal";
break;
case B_HIGH:
priority="high";
break;
case B_ANY:
priority="any";
break;
default:
res=SIEVE_RUN_ERROR;
}
if(res == SIEVE_RUN_ERROR)
break;
comparator =ntohl( bc[ip].value);
ip++;
if (comparator == B_ANY)
{
ip++;/* skip placeholder this has no comparator function */
comp=NULL;
} else {
int x= ntohl(bc[ip].value);
ip++;
comp=lookup_comp(B_ASCIICASEMAP,comparator,
x, &comprock);
}
ip = unwrap_string(bc, ip, &pattern, NULL);
if (comparator == B_REGEX)
{
char errmsg[1024]; /* Basically unused */
reg=bc_compile_regex(pattern,
REG_EXTENDED | REG_NOSUB | REG_ICASE,
errmsg, sizeof(errmsg));
if (!reg) {
res = SIEVE_RUN_ERROR;
} else {
res = do_denotify(notify_list, comp, reg,
comprock, priority);
free(reg);
}
} else {
res = do_denotify(notify_list, comp, pattern,
comprock, priority);
}
break;
}
case B_VACATION:
{
int respond;
char *fromaddr = NULL; /* relative to message we send */
char *toaddr = NULL; /* relative to message we send */
const char *handle = NULL;
const char *message = NULL;
int days, mime;
char buf[128];
char subject[1024];
int x;
ip++;
x = ntohl(bc[ip].len);
respond = shouldRespond(m, i, x, bc, ip+2,
&fromaddr, &toaddr);
ip = ntohl(bc[ip+1].value) / 4;
if (respond==SIEVE_OK)
{
ip = unwrap_string(bc, ip, &data, NULL);
if (!data)
{
/* we have to generate a subject */
const char **s;
strlcpy(buf, "subject", sizeof(buf));
if (i->getheader(m, buf, &s) != SIEVE_OK ||
s[0] == NULL) {
strlcpy(subject, "Automated reply", sizeof(subject));
} else {
/* s[0] contains the original subject */
const char *origsubj = s[0];
snprintf(subject, sizeof(subject), "Auto: %s", origsubj);
}
} else {
/* user specified subject */
strlcpy(subject, data, sizeof(subject));
}
ip = unwrap_string(bc, ip, &message, NULL);
days = ntohl(bc[ip].value);
mime = ntohl(bc[ip+1].value);
ip+=2;
if (version >= 0x05) {
ip = unwrap_string(bc, ip, &data, NULL);
if (data) {
/* user specified from address */
free(fromaddr);
fromaddr = xstrdup(data);
}
ip = unwrap_string(bc, ip, &data, NULL);
if (data) {
/* user specified handle */
handle = data;
}
}
res = do_vacation(actions, toaddr, fromaddr, xstrdup(subject),
message, days, mime, handle);
if (res == SIEVE_RUN_ERROR)
*errmsg = "Vacation can not be used with Reject or Vacation";
} else if (respond == SIEVE_DONE) {
/* skip subject and message */
ip = unwrap_string(bc, ip, &data, NULL);
ip = unwrap_string(bc, ip, &data, NULL);
ip+=2;/*skip days and mime flag*/
if (version >= 0x05) {
/* skip from and handle */
ip = unwrap_string(bc, ip, &data, NULL);
ip = unwrap_string(bc, ip, &data, NULL);
}
} else {
res = SIEVE_RUN_ERROR; /* something is bad */
}
break;
}
case B_NULL:/*15*/
ip++;
break;
case B_JUMP:/*16*/
ip= ntohl(bc[ip+1].jump);
break;
case B_INCLUDE:/*17*/
{
int isglobal = (ntohl(bc[ip+1].value) == B_GLOBAL);
char fpath[4096];
ip = unwrap_string(bc, ip+2, &data, NULL);
res = i->getinclude(sc, data, isglobal, fpath, sizeof(fpath));
if (res != SIEVE_OK)
*errmsg = "Include can not find script";
if (!res) {
res = sieve_script_load(fpath, &exe);
if (res != SIEVE_OK)
*errmsg = "Include can not load script";
}
if (!res)
res = sieve_eval_bc(exe, 1, i,
sc, m, imapflags, actions,
notify_list, errmsg);
break;
}
case B_RETURN:/*18*/
if (is_incl)
goto done;
else
res=1;
break;
default:
if(errmsg) *errmsg = "Invalid sieve bytecode";
return SIEVE_FAIL;
}
if (res) /* we've either encountered an error or a stop */
break;
}
done:
bc_cur->is_executing = 0;
return res;
}

File Metadata

Mime Type
text/x-c
Expires
Sun, Apr 5, 11:17 PM (1 w, 6 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18831538
Default Alt Text
bc_eval.c (32 KB)

Event Timeline