/* bc_eval.c - evaluate the bytecode * $Id: bc_eval.c,v 1.3 2005/03/05 00:37:37 dasenbro Exp $ */ /*********************************************************** Copyright 2001 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. ******************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include "sieve_interface.h" #include "interp.h" #include "message.h" #include "bytecode.h" #include "xmalloc.h" #include #include /**************************************************************************/ /**************************************************************************/ /**************************************************************************/ /**************************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 */ 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; igetheader(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; } /* is there a Precedence keyword of "junk | bulk | list"? */ 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] && isspace((int) *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]) { parse_address(body[0], &data, &marker); tmp = get_address(ADDRESS_ALL, &data, &marker, 1); myaddr = (tmp != NULL) ? xstrdup(tmp) : NULL; free_address(&data, &marker); } } 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 */ parse_address(body[0], &data, &marker); tmp = get_address(ADDRESS_ALL, &data, &marker, 1); 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? */ 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) { curra=i; for(x=0; xgetheader(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) 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 */ 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; xgetheader(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; xgetheader(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 if (parse_address(val[y], &data, &marker)!=SIEVE_OK) return 0; while (!res && (addr = get_address(addrpart, &data, &marker, 0))) { #if VERBOSE printf("working addr %s\n", (addr ? addr : "[nil]")); #endif if (match == B_COUNT) { count++; } else { /*search through all the data*/ currd=datai+2; for (z=0; zgetheader(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]!=NULL && !res; y++) { if (match == B_COUNT) { count++; } else { /*search through all the data*/ currd=datai+2; for (z=0; zgetheader(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]; while (!strncasecmp(origsubj, "Re: ", 4)) origsubj += 4; snprintf(subject, sizeof(subject), "Re: %s", origsubj); } } else { /* user specified subject */ strlcpy(subject, data, sizeof(subject)); } ip = unwrap_string(bc, ip, &message, NULL); res = do_vacation(actions, toaddr, fromaddr, xstrdup(subject), message, ntohl(bc[ip].value), ntohl(bc[ip+1].value)); ip+=2; 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*/ } 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; default: if(errmsg) *errmsg = "Invalid sieve bytecode"; return SIEVE_FAIL; } if (res) /* we've either encountered an error or a stop */ break; } return res; }