/* 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 int write_list(int list_len, int i, bytecode_input_t * d) { int x; i++; for (x=0; x<list_len; x++) { const char *data; int len; i = unwrap_string(d, i, &data, &len); printf("{%d}%s\n", len, data); } return i; }
/* 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_ORIG: 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 seconds, 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); seconds = ntohl(bc[ip].value); if (op == B_VACATION_ORIG) { seconds *= DAY2SEC; } 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, seconds, 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) & 63) == B_GLOBAL; int once = ntohl(bc[ip+1].value) & 64 ? 1 : 0; int isoptional = ntohl(bc[ip+1].value) & 128 ? 1 : 0; char fpath[4096]; ip = unwrap_string(bc, ip+2, &data, NULL); res = i->getinclude(sc, data, isglobal, fpath, sizeof(fpath)); if (res != SIEVE_OK) { if (isoptional == 0) *errmsg = "Include can not find script"; else res = SIEVE_OK; break; } res = sieve_script_load(fpath, &exe); if (res == SIEVE_SCRIPT_RELOADED) { if (once == 1) { res = SIEVE_OK; break; } } else if (res != SIEVE_OK) { /* SIEVE_FAIL */ if (isoptional == 0) *errmsg = "Include can not load script"; else res = SIEVE_OK; break; } 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; }
/* 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); #define SCOUNT_SIZE 20 char scount[SCOUNT_SIZE]; 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; }
/* 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; }
void write(obj_t obj) { char c; char *str; if (obj == imm_empty_list) { printf("()"); } else if (is_pair(obj)) { printf("("); write_pair(obj); printf(")"); } else if (is_symbol(obj)) { printf("%s", unwrap_symbol(obj)->value); } else if (is_string(obj)) { printf("\"%s\"", unwrap_string(obj)->value); } else if (is_boolean(obj)) { printf("#%c", obj==imm_false ? 'f' : 't'); } else if (is_fixnum(obj)) { printf("%lld", unwrap_fixnum(obj)); } else if (is_thunk(obj)) { printf("#<thunk>"); } else if (is_primitive_proc(obj)) { printf("#<primitive fn>"); } else if (obj == imm_undefined) { printf("#<undefined>"); } else { assert(0); } #if 0 case SYMBOL: printf("%s", obj->data.symbol->value); break; case FIXNUM: printf("%ld", obj->data.fixnum); break; case CHARACTER: c = obj->data.character; printf("#\\"); switch (c) { case '\n': printf("newline"); break; case ' ': printf("space"); break; default: putchar(c); } break; case STRING: str = obj->data.string->value; putchar('"'); while (*str != '\0') { switch (*str) { case '\n': printf("\\n"); break; case '\\': printf("\\\\"); break; case '"': printf("\\\""); break; default: putchar(*str); } str++; } putchar('"'); break; case PAIR: printf("("); write_pair(obj); printf(")"); break; case PRIMITIVE_PROC: case COMPOUND_PROC: printf("#<procedure>"); break; default: fprintf(stderr, "cannot write unknown type\n"); exit(1); }
static void dump2(bytecode_input_t *d, int bc_len) { int i; int version; const char *data; int len; if (!d) return; if (memcmp(d, BYTECODE_MAGIC, BYTECODE_MAGIC_LEN)) { printf("not a bytecode file [magic number test failed]\n"); return; } i = BYTECODE_MAGIC_LEN / sizeof(bytecode_input_t); version = ntohl(d[i].op); printf("Sievecode version %d\n", version); for(i++; i<bc_len;) { int copy = 0; printf("%d: ",i); switch(ntohl(d[i++].op)) { case B_STOP:/*0*/ printf("STOP\n"); break; case B_KEEP:/*1*/ printf("KEEP\n"); break; case B_DISCARD:/*2*/ printf("DISCARD\n"); break; case B_REJECT:/*3*/ i = unwrap_string(d, i, &data, &len); printf("REJECT {%d}%s\n", len, data); break; case B_FILEINTO: /*19*/ copy = ntohl(d[i++].value); /* fall through */ case B_FILEINTO_ORIG: /*4*/ i = unwrap_string(d, i, &data, &len); printf("FILEINTO COPY(%d) FOLDER({%d}%s)\n",copy,len,data); break; case B_REDIRECT: /*20*/ copy = ntohl(d[i++].value); /* fall through */ case B_REDIRECT_ORIG: /*5*/ i = unwrap_string(d, i, &data, &len); printf("REDIRECT COPY(%d) ADDRESS({%d}%s)\n",copy,len,data); break; case B_IF:/*6*/ printf("IF (ends at %d)", ntohl(d[i].value)); /* there is no short circuiting involved here*/ i = dump2_test(d,i+1); printf("\n"); break; case B_MARK:/*7*/ printf("MARK\n"); break; case B_UNMARK:/*8*/ printf("UNMARK\n"); break; case B_ADDFLAG: /*9*/ printf("ADDFLAG {%d}\n",ntohl(d[i].len)); i=write_list(ntohl(d[i].len),i+1,d); break; case B_SETFLAG: /*10*/ printf("SETFLAG {%d}\n",ntohl(d[i].len)); i=write_list(ntohl(d[i].len),i+1,d); break; case B_REMOVEFLAG: /*11*/ printf("REMOVEFLAG {%d}\n",ntohl(d[i].len)); i=write_list(ntohl(d[i].len),i+1,d); break; case B_DENOTIFY:/*12*/ printf("DENOTIFY\n"); printf(" PRIORITY(%d) Comparison type %d (relat %d)\n", ntohl(d[i].value), ntohl(d[i+1].value), ntohl(d[i+2].value)); i+=3; i = unwrap_string(d, i+1, &data, &len); printf(" ({%d}%s)\n", len, (!data ? "[nil]" : data)); break; case B_NOTIFY: /*13*/ i = unwrap_string(d, i, &data, &len); printf("NOTIFY METHOD({%d}%s)\n",len,data); i = unwrap_string(d, i, &data, &len); printf(" ID({%d}%s) OPTIONS ", len, (!data ? "[nil]" : data)); i=write_list(ntohl(d[i].len),i+1,d); printf(" PRIORITY(%d)\n", ntohl(d[i].value)); i++; i = unwrap_string(d, i, &data, &len); printf(" MESSAGE({%d}%s)\n", len, data); break; case B_VACATION:/*14*/ printf("VACATION\n"); /*add address list here!*/ i=write_list(ntohl(d[i].len),i+1,d); i = unwrap_string(d, i, &data, &len); printf("%d SUBJ({%d}%s) \n",i, len, (!data ? "[nil]" : data)); i = unwrap_string(d, i, &data, &len); printf("%d MESG({%d}%s) \n", i, len, (!data ? "[nil]" : data)); printf("DAYS(%d) MIME(%d)\n", ntohl(d[i].value), ntohl(d[i+1].value)); i+=2; if (version >= 0x05) { i = unwrap_string(d, i, &data, &len); printf("%d FROM({%d}%s) \n",i, len, (!data ? "[nil]" : data)); i = unwrap_string(d, i, &data, &len); printf("%d HANDLE({%d}%s) \n",i, len, (!data ? "[nil]" : data)); } break; case B_NULL:/*15*/ printf("NULL\n"); break; case B_JUMP:/*16*/ printf("JUMP %d\n", ntohl(d[i].jump)); i+=1; break; case B_INCLUDE:/*17*/ printf("INCLUDE "); switch (ntohl(d[i].value)) { case B_PERSONAL: printf("Personal"); break; case B_GLOBAL: printf("Global"); break; } i = unwrap_string(d, i+1, &data, &len); printf(" {%d}%s\n", len, data); break; case B_RETURN:/*18*/ printf("RETURN\n"); break; default: printf("%d (NOT AN OP)\n",ntohl(d[i-1].op)); exit(1); } } printf("full len is: %d\n", bc_len); }