/* * Test getting parts of a fully featured address */ static void test_getparts(void) { struct address *a; char *s; a = NULL; parseaddr_list("Fred Bloggs <*****@*****.**>", &a); CU_ASSERT_PTR_NOT_NULL_FATAL(a); s = address_get_all(a, 0); CU_ASSERT_STRING_EQUAL(s, "*****@*****.**"); free(s); s = address_get_all(a, 1); CU_ASSERT_STRING_EQUAL(s, "*****@*****.**"); free(s); s = address_get_localpart(a); CU_ASSERT_STRING_EQUAL(s, "fbloggs+foo"); free(s); s = address_get_domain(a, 0); CU_ASSERT_STRING_EQUAL(s, "FastMAIL.fm"); free(s); s = address_get_domain(a, 1); CU_ASSERT_STRING_EQUAL(s, "fastmail.fm"); free(s); s = address_get_user(a); CU_ASSERT_STRING_EQUAL(s, "fbloggs"); free(s); s = address_get_detail(a); CU_ASSERT_STRING_EQUAL(s, "foo"); free(s); parseaddr_free(a); }
/* * Test getting parts of an address with no domain part */ static void test_getparts_nodomain(void) { struct address *a; char *s; a = NULL; parseaddr_list("Fred Bloggs <fbloggs>", &a); CU_ASSERT_PTR_NOT_NULL_FATAL(a); s = address_get_all(a, 0); CU_ASSERT_STRING_EQUAL(s, "fbloggs@unspecified-domain"); free(s); s = address_get_all(a, 1); CU_ASSERT_STRING_EQUAL(s, "fbloggs@unspecified-domain"); free(s); s = address_get_localpart(a); CU_ASSERT_STRING_EQUAL(s, "fbloggs"); free(s); s = address_get_domain(a, 0); CU_ASSERT_STRING_EQUAL(s, "unspecified-domain"); free(s); s = address_get_domain(a, 1); CU_ASSERT_STRING_EQUAL(s, "unspecified-domain"); free(s); s = address_get_user(a); CU_ASSERT_STRING_EQUAL(s, "fbloggs"); free(s); s = address_get_detail(a); CU_ASSERT_PTR_NULL(s); parseaddr_free(a); }
/* 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; }