/* Write out a testlist to a given file descriptor. * return # of bytes written on success and -1 on error */ static int bc_testlist_emit(int fd, int *codep, bytecode_info_t *bc) { int len = bc->data[(*codep)++].len; int i; int ret; int begin, end; int wrote = 2*sizeof(int); /* Write out number of items in the list */ if(write_int(fd, len)== -1) return -1; /* skip one spot for end of list position*/ begin = lseek(fd, 0, SEEK_CUR); lseek(fd, sizeof(int), SEEK_CUR); /* Loop through all the items of the list, writing out each * test as we reach it in sequence. */ for(i=0; i < len; i++) { int nextcodep = bc->data[(*codep)++].jump; ret = bc_test_emit(fd, codep, bc); if(ret < 0 ) return -1; wrote+=ret; *codep = nextcodep; } end = lseek(fd, 0, SEEK_CUR); if (end < 0) return -1; /* go back and write the end of list position */ lseek(fd,begin,SEEK_SET); if(write_int(fd, end) == -1) return -1; /*return to the end */ lseek(fd,end,SEEK_SET); return wrote; }
/* emit the bytecode to a file descriptor given a flattened parse tree * returns -1 on failure, size of emitted bytecode on success. * * this takes care of everything except the comparisons */ static int bc_action_emit(int fd, int codep, int stopcodep, bytecode_info_t *bc, int filelen) { int len; /* Temporary Length Variable */ int ret; /* Temporary Return Value Variable */ int start_filelen = filelen; int i; /*debugging variable to check filelen*/ /*int location;*/ syslog(LOG_DEBUG, "entered bc_action_emit with filelen: %d", filelen); /* All non-string data MUST be sizeof(int) byte alligned so the end of each string may require a pad */ /* * Note that for purposes of jumps you must multiply codep by sizeof(int) */ while(codep < stopcodep) { /* Output this opcode */ if(write_int(fd, bc->data[codep].op) == -1) return -1; filelen+=sizeof(int); switch(bc->data[codep++].op) { case B_IF: { /* IF * test * jump (false condition) * then * (if there is an else) jump(finish) * (if there is an else) else */ int testEndLoc=-1; int testdist, thendist, elsedist; int c; int jumpFalseLoc=-1;/*this is the location that is being reserved for the first jump command we jump to the false condition of the test*/ int jumpEndLoc=-1; /* this is the location that is being reserved for the optional jump command it jumps over the else statement to the end*/ int jumpto=-1; int jumpop= B_JUMP; /*leave space to store the location of end of the test*/ ret = lseek(fd, sizeof(int), SEEK_CUR); if(ret == -1) return ret; testEndLoc=filelen; filelen+=sizeof(int); /* spew the test */ c=codep+3; testdist = bc_test_emit(fd, &c, bc); if(testdist == -1)return -1; filelen +=testdist; /*store the location for the end of the test *this is important for short circuiting of allof/anyof*/ jumpto=filelen/4; if(lseek(fd, testEndLoc, SEEK_SET) == -1) return -1; if(write_int(fd,jumpto) == -1) return -1; if(lseek(fd,filelen,SEEK_SET) == -1) return -1; /* leave space for jump */ if(write_int(fd, jumpop) == -1) return -1; ret = lseek(fd, sizeof(int), SEEK_CUR); if(ret == -1) return ret; jumpFalseLoc=filelen+sizeof(int); filelen +=2*sizeof(int); /*jumpop + jump*/ /* spew the then code */ thendist = bc_action_emit(fd, bc->data[codep].value, bc->data[codep+1].value, bc, filelen); filelen+=thendist; /* there is an else case */ if(bc->data[codep+2].value != -1) { /* leave space for jump */ if(write_int(fd, jumpop) == -1) return -1; ret = lseek(fd, sizeof(int), SEEK_CUR); if(ret == -1) return ret; jumpEndLoc=filelen+sizeof(int); filelen+=2*sizeof(int);/*jumpop + jump*/ } /*put previous jump to the end of the then code, *or the end of the jump if there is an else case */ jumpto=filelen/4; if(lseek(fd, jumpFalseLoc, SEEK_SET) == -1) return -1; if(write_int(fd,jumpto) == -1) return -1; if(lseek(fd,filelen,SEEK_SET) == -1) return -1; /* there is an else case */ if(bc->data[codep+2].value != -1) { /* spew the else code */ elsedist = bc_action_emit(fd, bc->data[codep+1].value, bc->data[codep+2].value, bc, filelen); filelen+=elsedist; /*put jump to the end of the else code*/ jumpto=filelen/4; if(lseek(fd, jumpEndLoc, SEEK_SET) == -1) return -1; if(write_int(fd,jumpto) == -1) return -1; if(lseek(fd,filelen,SEEK_SET) == -1) return -1; codep = bc->data[codep+2].value; } else { codep = bc->data[codep+1].value; } break; } case B_KEEP: /* Flags Stringlist, Copy (word) */ /* Dump a stringlist of flags */ ret = bc_stringlist_emit(fd, &codep, bc); if(ret < 0) return -1; filelen += ret; if(write_int(fd,bc->data[codep++].value) == -1) return -1; filelen += sizeof(int); break; case B_FILEINTO: /* Flags Stringlist, Copy (word), Folder String */ /* Dump a stringlist of flags */ ret = bc_stringlist_emit(fd, &codep, bc); if(ret < 0) return -1; filelen += ret; /* Write Copy */ if(write_int(fd,bc->data[codep++].value) == -1) return -1; filelen += sizeof(int); /* Write string length of Folder */ len = bc->data[codep++].len; if(write_int(fd,len) == -1) return -1; filelen+=sizeof(int); /* Write Folder */ if(write(fd,bc->data[codep++].str,len) == -1) return -1; ret = align_string(fd, len); if(ret == -1) return -1; filelen += len + ret; break; case B_REDIRECT: /* Copy (word), Address String */ if(write_int(fd,bc->data[codep++].value) == -1) return -1; filelen += sizeof(int); len = bc->data[codep++].len; if(write_int(fd,len) == -1) return -1; filelen+=sizeof(int); if(write(fd,bc->data[codep++].str,len) == -1) return -1; ret = align_string(fd, len); if(ret == -1) return -1; filelen += len + ret; break; case B_REJECT: /*just a string*/ len = bc->data[codep++].len; if(write_int(fd,len) == -1) return -1; filelen+=sizeof(int); if(write(fd,bc->data[codep++].str,len) == -1) return -1; ret = align_string(fd, len); if(ret == -1) return -1; filelen += len + ret; break; case B_SETFLAG: case B_ADDFLAG: case B_REMOVEFLAG: /* Dump just a stringlist */ ret = bc_stringlist_emit(fd, &codep, bc); if(ret < 0) return -1; filelen += ret; break; case B_NOTIFY: /* method string, id string, options string list, priotity, Message String */ /*method and id*/ for(i=0; i<2; i++) { len = bc->data[codep++].len; if(write_int(fd,len) == -1) return -1; filelen += sizeof(int); if(len == -1) { /* this will probably only happen for the id */ /* this is a nil string */ /* skip the null pointer and make up for it * by adjusting the offset */ codep++; } else { if(write(fd,bc->data[codep++].str,len) == -1) return -1; ret = align_string(fd, len); if(ret == -1) return -1; filelen += len + ret; } } /*options */ ret = bc_stringlist_emit(fd, &codep, bc); if(ret < 0) return -1; filelen+=ret; /*priority*/ if(write_int(fd, bc->data[codep].value) == -1) return -1; codep++; filelen += sizeof(int); len = bc->data[codep++].len; if(write_int(fd,len) == -1) return -1; filelen += sizeof(int); if(write(fd,bc->data[codep++].str,len) == -1) return -1; ret = align_string(fd, len); if(ret == -1) return -1; filelen += len + ret; break; case B_DENOTIFY: /* priority num,comptype num,relat num, comp string*/ /* priority*/ if(write_int(fd, bc->data[codep].value) == -1) return -1; filelen += sizeof(int); codep++; /* comptype */ if(write_int(fd, bc->data[codep].value) == -1) return -1; filelen += sizeof(int); codep++; /* relational*/ if(write_int(fd, bc->data[codep].value) == -1) return -1; filelen += sizeof(int); codep++; /* comp string*/ len = bc->data[codep++].len; if(write_int(fd,len) == -1) return -1; filelen += sizeof(int); if(len == -1) { /* this is a nil string */ /* skip the null pointer and make up for it * by adjusting the offset */ codep++; } else { if(write(fd,bc->data[codep++].str,len) == -1) return -1; ret = align_string(fd, len); if(ret == -1) return -1; filelen += len + ret; } break; case B_VACATION: /* Address list, Subject String, Message String, Seconds (word), Mime (word), From String, Handle String */ /*new code-this might be broken*/ ret = bc_stringlist_emit(fd, &codep, bc); if(ret < 0) return -1; filelen += ret; /*end of new code*/ for(i=0; i<2; i++) {/*writing strings*/ /*write length of string*/ len = bc->data[codep++].len; if(write_int(fd,len) == -1) return -1; filelen += sizeof(int); if(len == -1) { /* this is a nil string */ /* skip the null pointer and make up for it * by adjusting the offset */ codep++; } else { /*write string*/ if(write(fd,bc->data[codep++].str,len) == -1) return -1; ret = align_string(fd, len); if(ret == -1) return -1; filelen += len + ret; } } /* Seconds*/ if(write_int(fd,bc->data[codep].value) == -1) return -1; codep++; filelen += sizeof(int); /*Mime */ if(write_int(fd,bc->data[codep].value) == -1) return -1; codep++; for(i=0; i<2; i++) {/*writing strings*/ /*write length of string*/ len = bc->data[codep++].len; if(write_int(fd,len) == -1) return -1; filelen += sizeof(int); if(len == -1) { /* this is a nil string */ /* skip the null pointer and make up for it * by adjusting the offset */ codep++; } else { /*write string*/ if(write(fd,bc->data[codep++].str,len) == -1) return -1; ret = align_string(fd, len); if(ret == -1) return -1; filelen += len + ret; } } filelen += sizeof(int); break; case B_INCLUDE: /* Location + (Once<<6) + (Optional<<7) (word), Filename String */ /* Location + (Once<<6) + (Optional<<7) */ if(write_int(fd, bc->data[codep].value) == -1) return -1; filelen += sizeof(int); codep++; /* Filename */ len = bc->data[codep++].len; if(write_int(fd,len) == -1) return -1; filelen += sizeof(int); if(write(fd,bc->data[codep++].str,len) == -1) return -1; ret = align_string(fd, len); if(ret == -1) return -1; filelen += len + ret; break; case B_NULL: case B_STOP: case B_DISCARD: case B_MARK: case B_UNMARK: case B_RETURN: /* No Parameters! */ break; default: /* Unknown opcode? */ return -1; } } return filelen - start_filelen; }
/* emit the bytecode for a test. returns -1 on failure or size of * emitted bytecode on success */ static int bc_test_emit(int fd, int *codep, bytecode_info_t *bc) { int opcode; int wrote=0;/* Relative offset to account for interleaved strings */ int ret; /* Temporary Return Value Variable */ /* Output this opcode */ opcode = bc->data[(*codep)++].op; if(write_int(fd, opcode) == -1) return -1; wrote += sizeof(int); switch(opcode) { case BC_TRUE: case BC_FALSE: /* No parameter opcodes */ break; case BC_NOT: { /* Single parameter: another test */ ret = bc_test_emit(fd, codep, bc); if(ret < 0) return -1; else wrote+=ret; break; } case BC_ALLOF: case BC_ANYOF: /*where we jump to?*/ /* Just drop a testlist */ ret = bc_testlist_emit(fd, codep, bc); if(ret < 0) return -1; else wrote+=ret; break; case BC_SIZE: /* Drop tag and number */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; if(write_int(fd, bc->data[(*codep)+1].value) == -1) return -1; wrote += 2 * sizeof(int); (*codep) += 2; break; case BC_EXISTS: { int ret; ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote += ret; break; } case BC_HEADER: case BC_HASFLAG: { int ret; if (BC_HEADER == opcode) { /* drop index */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; } /* Drop match type */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*now drop relation*/ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*drop comparator */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /* Now drop haystacks */ ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote+=ret; /* Now drop needles */ ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote+=ret; break; } case BC_ADDRESS: /* drop index */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /* fall-through */ case BC_ENVELOPE: { int ret; /* Drop match type */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*drop comparator */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*now drop relation*/ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*now drop address part*/ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /* Now drop headers */ ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote+=ret; /* Now drop data */ ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote+=ret; break; } case BC_BODY: { int ret; /* Drop match type */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*drop comparator */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*now drop relation*/ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*now drop transform*/ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*now drop offset*/ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*now drop content-types*/ ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote+=ret; /* Now drop data */ ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote+=ret; break; } case BC_DATE: case BC_CURRENTDATE: { int ret; int datalen; int tmp; /* drop index */ if(BC_DATE == opcode) { if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; } /* drop zone tag */ tmp = bc->data[(*codep)].value; if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /* drop timezone offset */ if (tmp == B_TIMEZONE) { if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; } /* drop match type */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /* drop relation */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /* drop comparator */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /* drop date-part */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; if (BC_DATE == opcode) { /* drop header-name */ datalen = bc->data[(*codep)++].len; if(write_int(fd, datalen) == -1) return -1; wrote += sizeof(int); if(write(fd, bc->data[(*codep)++].str, datalen) == -1) return -1; wrote += datalen; ret = align_string(fd,datalen); if(ret == -1) return -1; wrote+=ret; } /* drop keywords */ ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote+=ret; break; } default: /* Unknown testcode? */ return -1; } return wrote; }
/* emit the bytecode for a test. returns -1 on failure or size of * emitted bytecode on success */ static int bc_test_emit(int fd, int *codep, bytecode_info_t *bc) { int wrote=0;/* Relative offset to account for interleaved strings */ int ret; /* Temporary Return Value Variable */ /* Output this opcode */ if(write_int(fd, bc->data[(*codep)].op) == -1) return -1; wrote += sizeof(int); switch(bc->data[(*codep)++].op) { case BC_TRUE: case BC_FALSE: /* No parameter opcodes */ break; case BC_NOT: { /* Single parameter: another test */ ret = bc_test_emit(fd, codep, bc); if(ret < 0) return -1; else wrote+=ret; break; } case BC_ALLOF: case BC_ANYOF: /*where we jump to?*/ /* Just drop a testlist */ ret = bc_testlist_emit(fd, codep, bc); if(ret < 0) return -1; else wrote+=ret; break; case BC_SIZE: /* Drop tag and number */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; if(write_int(fd, bc->data[(*codep)+1].value) == -1) return -1; wrote += 2 * sizeof(int); (*codep) += 2; break; case BC_EXISTS: { int ret; ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote += ret; break; } case BC_HEADER: { int ret; /* Drop match type */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*drop comparator */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*now drop relation*/ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /* Now drop headers */ ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote+=ret; /* Now drop data */ ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote+=ret; break; } case BC_ADDRESS: case BC_ENVELOPE: { int ret; /* Drop match type */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*drop comparator */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*now drop relation*/ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*now drop address part*/ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /* Now drop headers */ ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote+=ret; /* Now drop data */ ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote+=ret; break; } case BC_BODY: { int ret; /* Drop match type */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*drop comparator */ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*now drop relation*/ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*now drop transform*/ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*now drop offset*/ if(write_int(fd, bc->data[(*codep)].value) == -1) return -1; wrote += sizeof(int); (*codep)++; /*now drop content-types*/ ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote+=ret; /* Now drop data */ ret = bc_stringlist_emit(fd, codep, bc); if(ret < 0) return -1; wrote+=ret; break; } default: /* Unknown testcode? */ return -1; } return wrote; }