From cc7a4672bbcbde9b686cff494bd95972f4f875ca Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Thu, 25 Oct 2007 22:43:53 +0200 Subject: [PATCH] Made address and size tests executable and fixed minor bug regarding the lexer. --- sieve/tests/basic.sieve | 4 +- src/lib-sieve/sieve-binary.c | 10 +- src/lib-sieve/sieve-code.c | 42 +++- src/lib-sieve/sieve-code.h | 1 + src/lib-sieve/sieve-interpreter.c | 321 ++++++++++++++++++++++++------ src/lib-sieve/sieve-interpreter.h | 50 +++-- src/lib-sieve/sieve-lexer.c | 13 +- src/lib-sieve/sieve.c | 13 +- src/lib-sieve/sieve.h | 2 +- src/lib-sieve/tst-address.c | 60 +++++- src/lib-sieve/tst-size.c | 55 ++++- src/sieve-bin/Makefile.am | 4 +- src/sieve-bin/sieve_test.c | 37 +++- src/sieve-bin/sievec.c | 4 +- 14 files changed, 497 insertions(+), 119 deletions(-) diff --git a/sieve/tests/basic.sieve b/sieve/tests/basic.sieve index 5ee7bc2dc..876dc5a00 100644 --- a/sieve/tests/basic.sieve +++ b/sieve/tests/basic.sieve @@ -1,6 +1,6 @@ -if false { +if address :is ["from", "to", "cc"] "sirius@drunksnipers.com { keep; -} elsif false { +} elsif size :under 4000 { stop; } else { discard; diff --git a/src/lib-sieve/sieve-binary.c b/src/lib-sieve/sieve-binary.c index 90920446e..811470d0b 100644 --- a/src/lib-sieve/sieve-binary.c +++ b/src/lib-sieve/sieve-binary.c @@ -51,12 +51,16 @@ unsigned int sieve_binary_link_extension(struct sieve_binary *binary, const stru const struct sieve_extension *sieve_binary_get_extension(struct sieve_binary *binary, unsigned int index) { - const struct sieve_extension * const*ext = array_idx(&(binary->extensions), index); + const struct sieve_extension * const *ext; - return *ext; + if ( array_count(&(binary->extensions)) > index ) { + ext = array_idx(&(binary->extensions), index); + return *ext; + } + + return NULL; } - /* Emission functions */ inline sieve_size_t sieve_binary_emit_data(struct sieve_binary *binary, void *data, sieve_size_t size) diff --git a/src/lib-sieve/sieve-code.c b/src/lib-sieve/sieve-code.c index 8c5e7713b..fafb6c1be 100644 --- a/src/lib-sieve/sieve-code.c +++ b/src/lib-sieve/sieve-code.c @@ -45,14 +45,20 @@ const struct sieve_opcode *sieve_opcodes[] = { &tst_size_under_opcode }; +const unsigned int sieve_opcode_count = + (sizeof(sieve_opcodes) / sizeof(sieve_opcodes[0])); + /* Code dump for core commands */ static bool sieve_code_dump_jmp(struct sieve_interpreter *interpreter) { unsigned int pc = sieve_interpreter_program_counter(interpreter); - int offset = sieve_interpreter_read_offset(interpreter); + int offset; - printf("JMP %d [%08x]\n", offset, pc + offset); + if ( sieve_interpreter_read_offset_operand(interpreter, &offset) ) + printf("JMP %d [%08x]\n", offset, pc + offset); + else + return FALSE; return TRUE; } @@ -60,9 +66,12 @@ static bool sieve_code_dump_jmp(struct sieve_interpreter *interpreter) static bool sieve_code_dump_jmptrue(struct sieve_interpreter *interpreter) { unsigned int pc = sieve_interpreter_program_counter(interpreter); - int offset = sieve_interpreter_read_offset(interpreter); - - printf("JMPTRUE %d [%08x]\n", offset, pc + offset); + int offset; + + if ( sieve_interpreter_read_offset_operand(interpreter, &offset) ) + printf("JMPTRUE %d [%08x]\n", offset, pc + offset); + else + return FALSE; return TRUE; } @@ -70,9 +79,12 @@ static bool sieve_code_dump_jmptrue(struct sieve_interpreter *interpreter) static bool sieve_code_dump_jmpfalse(struct sieve_interpreter *interpreter) { unsigned int pc = sieve_interpreter_program_counter(interpreter); - int offset = sieve_interpreter_read_offset(interpreter); + int offset; - printf("JMPFALSE %d [%08x]\n", offset, pc + offset); + if ( sieve_interpreter_read_offset_operand(interpreter, &offset) ) + printf("JMPFALSE %d [%08x]\n", offset, pc + offset); + else + return FALSE; return TRUE; } @@ -102,21 +114,31 @@ static bool sieve_code_dump_discard(struct sieve_interpreter *interpreter ATTR_U static bool sieve_code_execute_jmp(struct sieve_interpreter *interpreter) { - sieve_interpreter_program_jump(interpreter); + printf("JMP\n"); + if ( !sieve_interpreter_program_jump(interpreter, TRUE) ) + return FALSE; return TRUE; } static bool sieve_code_execute_jmptrue(struct sieve_interpreter *interpreter) { - sieve_interpreter_program_jump(interpreter); + if ( !sieve_interpreter_program_jump(interpreter, + sieve_interpreter_get_test_result(interpreter)) ) + return FALSE; + + printf("JMPTRUE\n"); return TRUE; } static bool sieve_code_execute_jmpfalse(struct sieve_interpreter *interpreter) { - sieve_interpreter_program_jump(interpreter); + if ( !sieve_interpreter_program_jump(interpreter, + !sieve_interpreter_get_test_result(interpreter)) ) + return FALSE; + + printf("JMPFALSE\n"); return TRUE; } diff --git a/src/lib-sieve/sieve-code.h b/src/lib-sieve/sieve-code.h index 3af305ba0..3e34eb5fc 100644 --- a/src/lib-sieve/sieve-code.h +++ b/src/lib-sieve/sieve-code.h @@ -29,6 +29,7 @@ enum sieve_core_operation { }; extern const struct sieve_opcode *sieve_opcodes[]; +extern const unsigned int sieve_opcode_count; enum sieve_core_operand { SIEVE_OPERAND_NUMBER = 0x01, diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c index 1f59d2069..a1702edfb 100644 --- a/src/lib-sieve/sieve-interpreter.c +++ b/src/lib-sieve/sieve-interpreter.c @@ -4,6 +4,7 @@ #include "lib.h" #include "mempool.h" #include "array.h" +#include "mail-storage.h" #include "sieve-commands-private.h" #include "sieve-generator.h" @@ -16,6 +17,7 @@ struct sieve_coded_stringlist { struct sieve_interpreter *interpreter; sieve_size_t start_address; sieve_size_t end_address; + sieve_size_t current_offset; int length; int index; }; @@ -25,6 +27,11 @@ struct sieve_coded_stringlist { #define CODE_BYTES_LEFT(interpreter) (interpreter->code_size - interpreter->pc) #define CODE_JUMP(interpreter, offset) interpreter->pc += offset +#define ADDR_CODE_AT(interpreter, address) (interpreter->code[*address]) +#define ADDR_DATA_AT(interpreter, address) ((unsigned char) (interpreter->code[*address])) +#define ADDR_BYTES_LEFT(interpreter, address) (interpreter->code_size - (*address)) +#define ADDR_JUMP(address, offset) (*address) += offset + struct sieve_interpreter { pool_t pool; @@ -34,9 +41,13 @@ struct sieve_interpreter { const char *code; sieve_size_t code_size; + /* Execution status */ sieve_size_t pc; - + bool test_result; struct sieve_result *result; + + /* Execution environment */ + struct mail *mail; }; struct sieve_interpreter *sieve_interpreter_create(struct sieve_binary *binary) @@ -63,6 +74,15 @@ void sieve_interpreter_free(struct sieve_interpreter *interpreter) pool_unref(&(interpreter->pool)); } +/* Accessing runtinme environment */ + +inline struct mail *sieve_interpreter_get_mail(struct sieve_interpreter *interpreter) +{ + return interpreter->mail; +} + +/* Program counter */ + inline void sieve_interpreter_reset(struct sieve_interpreter *interpreter) { interpreter->pc = 0; @@ -74,48 +94,68 @@ inline sieve_size_t sieve_interpreter_program_counter(struct sieve_interpreter * } inline bool sieve_interpreter_program_jump - (struct sieve_interpreter *interpreter) + (struct sieve_interpreter *interpreter, bool jump) { sieve_size_t pc = sieve_interpreter_program_counter(interpreter); - int offset = sieve_interpreter_read_offset(interpreter); + int offset; + + if ( !sieve_interpreter_read_offset(interpreter, &(interpreter->pc), &offset) ) + return FALSE; - if ( pc + offset < interpreter->code_size && pc + offset > 0 ) { - interpreter->pc = pc + offset; + if ( pc + offset <= interpreter->code_size && pc + offset > 0 ) { + if ( jump ) + interpreter->pc = pc + offset; + return TRUE; } return FALSE; } +inline void sieve_interpreter_set_test_result(struct sieve_interpreter *interpreter, bool result) +{ + interpreter->test_result = result; +} + +inline bool sieve_interpreter_get_test_result(struct sieve_interpreter *interpreter) +{ + return interpreter->test_result; +} /* Literals */ -int sieve_interpreter_read_offset(struct sieve_interpreter *interpreter) +bool sieve_interpreter_read_offset + (struct sieve_interpreter *interpreter, sieve_size_t *address, int *offset) { - uint32_t offset = 0; + uint32_t offs = 0; - if ( CODE_BYTES_LEFT(interpreter) >= 4 ) { + if ( ADDR_BYTES_LEFT(interpreter, address) >= 4 ) { int i; for ( i = 0; i < 4; i++ ) { - offset = (offset << 8) + DATA_AT_PC(interpreter); - CODE_JUMP(interpreter, 1); + offs = (offs << 8) + ADDR_DATA_AT(interpreter, address); + ADDR_JUMP(address, 1); } + + if ( offset != NULL ) + *offset = (int) offs; + + return TRUE; } - return (int) offset; + return FALSE; } bool sieve_interpreter_read_integer - (struct sieve_interpreter *interpreter, sieve_size_t *integer) + (struct sieve_interpreter *interpreter, sieve_size_t *address, sieve_size_t *integer) { int bits = sizeof(sieve_size_t) * 8; *integer = 0; - while ( (DATA_AT_PC(interpreter) & 0x80) > 0 ) { - if ( CODE_BYTES_LEFT(interpreter) > 0 && bits > 0) { - *integer |= DATA_AT_PC(interpreter) & 0x7F; - CODE_JUMP(interpreter, 1); + while ( (ADDR_DATA_AT(interpreter, address) & 0x80) > 0 ) { + if ( ADDR_BYTES_LEFT(interpreter, address) > 0 && bits > 0) { + *integer |= ADDR_DATA_AT(interpreter, address) & 0x7F; + ADDR_JUMP(address, 1); *integer <<= 7; bits -= 7; @@ -125,69 +165,113 @@ bool sieve_interpreter_read_integer } } - *integer |= DATA_AT_PC(interpreter) & 0x7F; - CODE_JUMP(interpreter, 1); + *integer |= ADDR_DATA_AT(interpreter, address) & 0x7F; + ADDR_JUMP(address, 1); return TRUE; } -/* FIXME: add this to lib/str. (cannot use str_c on non-modifyable buffer) */ +/* FIXME: add this to lib/str. */ static string_t *t_str_const(const void *cdata, size_t size) { - return buffer_create_const_data(pool_datastack_create(), cdata, size); + string_t *result = t_str_new(size); + + str_append_n(result, cdata, size); + + return result; + //return buffer_create_const_data(pool_datastack_create(), cdata, size); } bool sieve_interpreter_read_string - (struct sieve_interpreter *interpreter, string_t **str) + (struct sieve_interpreter *interpreter, sieve_size_t *address, string_t **str) { sieve_size_t strlen = 0; - if ( !sieve_interpreter_read_integer(interpreter, &strlen) ) + if ( !sieve_interpreter_read_integer(interpreter, address, &strlen) ) return FALSE; - if ( strlen > CODE_BYTES_LEFT(interpreter) ) + if ( strlen > ADDR_BYTES_LEFT(interpreter, address) ) return FALSE; - *str = t_str_const(&CODE_AT_PC(interpreter), strlen); - CODE_JUMP(interpreter, strlen); + *str = t_str_const(&ADDR_CODE_AT(interpreter, address), strlen); + ADDR_JUMP(address, strlen); return TRUE; } -bool sieve_interpreter_read_stringlist - (struct sieve_interpreter *interpreter, struct sieve_coded_stringlist **strlist) +struct sieve_coded_stringlist *sieve_interpreter_read_stringlist + (struct sieve_interpreter *interpreter, sieve_size_t *address, bool single) { - sieve_size_t pc = interpreter->pc; - sieve_size_t end = pc + sieve_interpreter_read_offset(interpreter); + struct sieve_coded_stringlist *strlist; + + sieve_size_t pc = *address; + sieve_size_t end; sieve_size_t length = 0; + + if ( single ) { + sieve_size_t strlen; + + if ( !sieve_interpreter_read_integer(interpreter, address, &strlen) ) + return FALSE; + + end = *address + strlen; + length = 1; + *address = pc; + } else { + int end_offset; + + if ( !sieve_interpreter_read_offset(interpreter, address, &end_offset) ) + return NULL; - if ( !sieve_interpreter_read_integer(interpreter, &length) ) - return FALSE; + end = pc + end_offset; + + if ( !sieve_interpreter_read_integer(interpreter, address, &length) ) + return NULL; + } + + if ( end > interpreter->code_size ) + return NULL; - *strlist = p_new(pool_datastack_create(), struct sieve_coded_stringlist, 1); - (*strlist)->interpreter = interpreter; - (*strlist)->start_address = pc; - (*strlist)->end_address = end; - (*strlist)->length = length; - (*strlist)->index = 0; + strlist = p_new(pool_datastack_create(), struct sieve_coded_stringlist, 1); + strlist->interpreter = interpreter; + strlist->start_address = *address; + strlist->current_offset = *address; + strlist->end_address = end; + strlist->length = length; + strlist->index = 0; - return TRUE; + /* Skip over the string list for now */ + *address = end; + + return strlist; } -bool sieve_coded_stringlist_read_item(struct sieve_coded_stringlist *strlist, string_t **str) +bool sieve_coded_stringlist_next_item(struct sieve_coded_stringlist *strlist, string_t **str) { + sieve_size_t address; *str = NULL; if ( strlist->index >= strlist->length ) return TRUE; - else if ( sieve_interpreter_read_string(strlist->interpreter, str) ) { - strlist->index++; - return TRUE; + else { + address = strlist->current_offset; + + if ( sieve_interpreter_read_string(strlist->interpreter, &address, str) ) { + strlist->index++; + strlist->current_offset = address; + return TRUE; + } } return FALSE; } +void sieve_coded_stringlist_reset(struct sieve_coded_stringlist *strlist) +{ + strlist->current_offset = strlist->start_address; + strlist->index = 0; +} + /* Opcodes and operands */ static const struct sieve_opcode *sieve_interpreter_read_opcode @@ -200,21 +284,95 @@ static const struct sieve_opcode *sieve_interpreter_read_opcode CODE_JUMP(interpreter, 1); if ( opcode < SIEVE_OPCODE_EXT_OFFSET ) { - return sieve_opcodes[opcode]; + if ( opcode < sieve_opcode_count ) + return sieve_opcodes[opcode]; + else + return NULL; } else { const struct sieve_extension *ext = sieve_binary_get_extension(interpreter->binary, opcode - SIEVE_OPCODE_EXT_OFFSET); - return &(ext->opcode); + if ( ext != NULL ) + return &(ext->opcode); + else + return NULL; } } return NULL; } + +bool sieve_interpreter_read_offset_operand + (struct sieve_interpreter *interpreter, int *offset) +{ + return sieve_interpreter_read_offset(interpreter, &(interpreter->pc), offset); +} + +bool sieve_interpreter_read_number_operand + (struct sieve_interpreter *interpreter, sieve_size_t *number) +{ + if ( CODE_AT_PC(interpreter) != SIEVE_OPERAND_NUMBER ) { + return FALSE; + } + CODE_JUMP(interpreter, 1); + + return sieve_interpreter_read_integer(interpreter, &(interpreter->pc), number); +} + +bool sieve_interpreter_read_string_operand + (struct sieve_interpreter *interpreter, string_t **str) +{ + if ( CODE_AT_PC(interpreter) != SIEVE_OPERAND_STRING ) { + return FALSE; + } + CODE_JUMP(interpreter, 1); + + return sieve_interpreter_read_string(interpreter, &(interpreter->pc), str); +} + +struct sieve_coded_stringlist * + sieve_interpreter_read_stringlist_operand + (struct sieve_interpreter *interpreter) +{ + bool single = FALSE; + + switch ( CODE_AT_PC(interpreter) ) { + case SIEVE_OPERAND_STRING: + single = TRUE; + break; + case SIEVE_OPERAND_STRING_LIST: + single = FALSE; + break; + default: + return NULL; + } + CODE_JUMP(interpreter, 1); + + return sieve_interpreter_read_stringlist + (interpreter, &(interpreter->pc), single); +} + +/* Stringlist Utility */ + +bool sieve_stringlist_match + (struct sieve_coded_stringlist *key_list, const char *value) +{ + string_t *key_item; + sieve_coded_stringlist_reset(key_list); + + /* Match to all key values */ + key_item = NULL; + while ( sieve_coded_stringlist_next_item(key_list, &key_item) && key_item != NULL ) { + if ( strncmp(value, str_c(key_item), str_len(key_item)) == 0 ) + return TRUE; + } + + return FALSE; +} /* Code Dump */ -static void sieve_interpreter_dump_operation +static bool sieve_interpreter_dump_operation (struct sieve_interpreter *interpreter) { const struct sieve_opcode *opcode = sieve_interpreter_read_opcode(interpreter); @@ -226,20 +384,28 @@ static void sieve_interpreter_dump_operation (void) opcode->dump(interpreter); else printf("<< UNSPECIFIED OPERATION >>\n"); + + return TRUE; } + + return FALSE; } -void sieve_interpreter_dump_number +bool sieve_interpreter_dump_number (struct sieve_interpreter *interpreter) { sieve_size_t number = 0; - if (sieve_interpreter_read_integer(interpreter, &number) ) { + if (sieve_interpreter_read_integer(interpreter, &(interpreter->pc), &number) ) { printf("NUM: %ld\n", (long) number); + + return TRUE; } + + return FALSE; } -static void sieve_interpreter_print_string(string_t *str) +void sieve_interpreter_print_string(string_t *str) { unsigned int i = 0; const unsigned char *sdata = str_data(str); @@ -261,41 +427,50 @@ static void sieve_interpreter_print_string(string_t *str) printf("...\n"); } -void sieve_interpreter_dump_string +bool sieve_interpreter_dump_string (struct sieve_interpreter *interpreter) { string_t *str; - if ( sieve_interpreter_read_string(interpreter, &str) ) { + if ( sieve_interpreter_read_string(interpreter, &(interpreter->pc), &str) ) { sieve_interpreter_print_string(str); + + return TRUE; } + + return FALSE; } -void sieve_interpreter_dump_string_list +bool sieve_interpreter_dump_string_list (struct sieve_interpreter *interpreter) { struct sieve_coded_stringlist *strlist; - if ( sieve_interpreter_read_stringlist(interpreter, &strlist) ) { - sieve_size_t pc = interpreter->pc; + if ( (strlist=sieve_interpreter_read_stringlist(interpreter, &(interpreter->pc), FALSE)) != NULL ) { + sieve_size_t pc; string_t *stritem; printf("STRLIST [%d] (END %08x)\n", strlist->length, strlist->end_address); - while ( sieve_coded_stringlist_read_item(strlist, &stritem) && stritem != NULL ) { + pc = strlist->current_offset; + while ( sieve_coded_stringlist_next_item(strlist, &stritem) && stritem != NULL ) { printf("%08x: ", pc); sieve_interpreter_print_string(stritem); - pc = interpreter->pc; + pc = strlist->current_offset; } + + return TRUE; } + + return FALSE; } -void sieve_interpreter_dump_operand +bool sieve_interpreter_dump_operand (struct sieve_interpreter *interpreter) { char opcode = CODE_AT_PC(interpreter); printf("%08x: ", interpreter->pc); - CODE_JUMP(interpreter, 1); + CODE_JUMP(interpreter, 1); if ( opcode < SIEVE_CORE_OPERAND_MASK ) { switch (opcode) { @@ -308,16 +483,29 @@ void sieve_interpreter_dump_operand case SIEVE_OPERAND_STRING_LIST: sieve_interpreter_dump_string_list(interpreter); break; + + default: + return FALSE; } + + return TRUE; } + + return FALSE; } void sieve_interpreter_dump_code(struct sieve_interpreter *interpreter) { sieve_interpreter_reset(interpreter); + interpreter->result = NULL; + interpreter->mail = NULL; + while ( interpreter->pc < interpreter->code_size ) { - sieve_interpreter_dump_operation(interpreter); + if ( !sieve_interpreter_dump_operation(interpreter) ) { + printf("Binary is corrupt.\n"); + return; + } } printf("%08x: [End of code]\n", interpreter->code_size); @@ -333,27 +521,36 @@ bool sieve_interpreter_execute_opcode if ( opcode != NULL ) { if ( opcode->execute != NULL ) return opcode->execute(interpreter); - + else + printf("\n"); + return TRUE; } return FALSE; } -struct sieve_result *sieve_interpreter_run(struct sieve_interpreter *interpreter) +struct sieve_result *sieve_interpreter_run + (struct sieve_interpreter *interpreter, struct mail *mail) { struct sieve_result *result; sieve_interpreter_reset(interpreter); result = sieve_result_create(); + interpreter->result = result; + interpreter->mail = mail; while ( interpreter->pc < interpreter->code_size ) { - printf("%08x:\n", interpreter->pc); + printf("%08x: ", interpreter->pc); - if ( !sieve_interpreter_execute_opcode(interpreter) ) + if ( !sieve_interpreter_execute_opcode(interpreter) ) { + printf("Execution aborted.\n"); return NULL; + } } + interpreter->result = NULL; + return result; } diff --git a/src/lib-sieve/sieve-interpreter.h b/src/lib-sieve/sieve-interpreter.h index 0c7bf2ca4..f022fb96c 100644 --- a/src/lib-sieve/sieve-interpreter.h +++ b/src/lib-sieve/sieve-interpreter.h @@ -19,33 +19,57 @@ inline void sieve_interpreter_reset inline sieve_size_t sieve_interpreter_program_counter (struct sieve_interpreter *interpreter); inline bool sieve_interpreter_program_jump + (struct sieve_interpreter *interpreter, bool jump); + +inline void sieve_interpreter_set_test_result + (struct sieve_interpreter *interpreter, bool result); +inline bool sieve_interpreter_get_test_result (struct sieve_interpreter *interpreter); - -int sieve_interpreter_read_offset(struct sieve_interpreter *interpreter); +bool sieve_interpreter_read_offset + (struct sieve_interpreter *interpreter, sieve_size_t *address, int *offset); bool sieve_interpreter_read_integer - (struct sieve_interpreter *interpreter, sieve_size_t *integer); + (struct sieve_interpreter *interpreter, sieve_size_t *address, sieve_size_t *integer); bool sieve_interpreter_read_string - (struct sieve_interpreter *interpreter, string_t **str); + (struct sieve_interpreter *interpreter, sieve_size_t *address, string_t **str); -bool sieve_interpreter_read_stringlist - (struct sieve_interpreter *interpreter, struct sieve_coded_stringlist **strlist); -bool sieve_coded_stringlist_read_item - (struct sieve_coded_stringlist *strlist, string_t **str); +struct sieve_coded_stringlist *sieve_interpreter_read_stringlist + (struct sieve_interpreter *interpreter, sieve_size_t *address, bool single); +bool sieve_coded_stringlist_next_item(struct sieve_coded_stringlist *strlist, string_t **str); +void sieve_coded_stringlist_reset(struct sieve_coded_stringlist *strlist); + +/* Opcodes and operands */ +bool sieve_interpreter_read_offset_operand + (struct sieve_interpreter *interpreter, int *offset); +bool sieve_interpreter_read_number_operand + (struct sieve_interpreter *interpreter, sieve_size_t *number); +bool sieve_interpreter_read_string_operand + (struct sieve_interpreter *interpreter, string_t **str); +struct sieve_coded_stringlist *sieve_interpreter_read_stringlist_operand + (struct sieve_interpreter *interpreter); + +/* Stringlist Utility */ + +bool sieve_stringlist_match + (struct sieve_coded_stringlist *key_list, const char *value); + +/* Accessing runtime information */ +inline struct mail *sieve_interpreter_get_mail(struct sieve_interpreter *interpreter); /* Code dump (debugging purposes) */ -void sieve_interpreter_dump_number(struct sieve_interpreter *interpreter); -void sieve_interpreter_dump_string(struct sieve_interpreter *interpreter); -void sieve_interpreter_dump_string_list(struct sieve_interpreter *interpreter); -void sieve_interpreter_dump_operand(struct sieve_interpreter *interpreter); +bool sieve_interpreter_dump_number(struct sieve_interpreter *interpreter); +bool sieve_interpreter_dump_string(struct sieve_interpreter *interpreter); +bool sieve_interpreter_dump_string_list(struct sieve_interpreter *interpreter); +bool sieve_interpreter_dump_operand(struct sieve_interpreter *interpreter); void sieve_interpreter_dump_code(struct sieve_interpreter *interpreter); /* Code execute */ bool sieve_interpreter_execute_opcode(struct sieve_interpreter *interpreter); -struct sieve_result *sieve_interpreter_run(struct sieve_interpreter *interpreter); +struct sieve_result *sieve_interpreter_run + (struct sieve_interpreter *interpreter, struct mail *mail); #endif diff --git a/src/lib-sieve/sieve-lexer.c b/src/lib-sieve/sieve-lexer.c index 804e9d2f3..4b08cc1b4 100644 --- a/src/lib-sieve/sieve-lexer.c +++ b/src/lib-sieve/sieve-lexer.c @@ -194,6 +194,7 @@ __inline__ int sieve_lexer_current_line(struct sieve_lexer *lexer) { */ bool sieve_lexer_scan_raw_token(struct sieve_lexer *lexer) { + int start_line; string_t *str; /* Read first character */ @@ -228,6 +229,7 @@ bool sieve_lexer_scan_raw_token(struct sieve_lexer *lexer) // ;; or unless it is followed by a character that isn't a // ;; slash.) case '/': + start_line = lexer->current_line; sieve_lexer_shift(lexer); if ( sieve_lexer_curchar(lexer) == '*' ) { @@ -244,13 +246,13 @@ bool sieve_lexer_scan_raw_token(struct sieve_lexer *lexer) return TRUE; } else if ( sieve_lexer_curchar(lexer) == -1 ) { - sieve_lexer_error(lexer, "end of file before end of bracket comment ('/* ... */')"); + sieve_lexer_error(lexer, "end of file before end of bracket comment ('/* ... */') started at line %d", start_line); lexer->token_type = STT_ERROR; return FALSE; } } else if ( sieve_lexer_curchar(lexer) == -1 ) { - sieve_lexer_error(lexer, "end of file before end of bracket comment ('/* ... */')"); + sieve_lexer_error(lexer, "end of file before end of bracket comment ('/* ... */') started at line %d", start_line); lexer->token_type = STT_ERROR; return FALSE; @@ -286,11 +288,18 @@ bool sieve_lexer_scan_raw_token(struct sieve_lexer *lexer) /* quoted-string */ case '"': + start_line = lexer->current_line; sieve_lexer_shift(lexer); str = str_new(lexer->pool, 16); lexer->token_str_value = str; while ( sieve_lexer_curchar(lexer) != '"' ) { + if ( sieve_lexer_curchar(lexer) == -1 ) { + sieve_lexer_error(lexer, "end of file before end of quoted string started at line %d", start_line); + lexer->token_type = STT_ERROR; + return FALSE; + } + if ( sieve_lexer_curchar(lexer) == '\\' ) { sieve_lexer_shift(lexer); } diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c index 05d9d902d..76473cda0 100644 --- a/src/lib-sieve/sieve.c +++ b/src/lib-sieve/sieve.c @@ -128,18 +128,13 @@ void sieve_dump(struct sieve_binary *binary) sieve_interpreter_free(interpreter); } -bool sieve_execute(struct sieve_binary *binary) +bool sieve_execute(struct sieve_binary *binary, struct mail *mail) { + struct sieve_interpreter *interpreter = sieve_interpreter_create(binary); bool result = TRUE; - struct sieve_interpreter *interpreter; - - printf("Code Dump:\n\n"); - interpreter = sieve_interpreter_create(binary); - - sieve_interpreter_dump_code(interpreter); - + printf("Code Execute:\n\n"); - if ( sieve_interpreter_run(interpreter) == NULL ) { + if ( sieve_interpreter_run(interpreter, mail) == NULL ) { result = FALSE; } diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h index 29dff8791..42fab8b1d 100644 --- a/src/lib-sieve/sieve.h +++ b/src/lib-sieve/sieve.h @@ -5,6 +5,6 @@ struct sieve_binary *sieve_compile(int fd); void sieve_dump(struct sieve_binary *binary); -bool sieve_execute(struct sieve_binary *binary); +bool sieve_execute(struct sieve_binary *binary, struct mail *mail); #endif diff --git a/src/lib-sieve/tst-address.c b/src/lib-sieve/tst-address.c index 665bfebec..ed849e8a6 100644 --- a/src/lib-sieve/tst-address.c +++ b/src/lib-sieve/tst-address.c @@ -9,9 +9,10 @@ /* Opcodes */ static bool tst_address_opcode_dump(struct sieve_interpreter *interpreter); +static bool tst_address_opcode_execute(struct sieve_interpreter *interpreter); const struct sieve_opcode tst_address_opcode = - { tst_address_opcode_dump, NULL }; + { tst_address_opcode_dump, tst_address_opcode_execute }; /* Test registration */ @@ -84,9 +85,58 @@ bool tst_address_generate static bool tst_address_opcode_dump(struct sieve_interpreter *interpreter) { - printf("ADDRESS\n"); - sieve_interpreter_dump_operand(interpreter); - sieve_interpreter_dump_operand(interpreter); + printf("ADDRESS\n"); + sieve_interpreter_dump_operand(interpreter); + sieve_interpreter_dump_operand(interpreter); - return TRUE; + return TRUE; +} + +/* Code execution */ + +static bool tst_address_opcode_execute(struct sieve_interpreter *interpreter) +{ + struct mail *mail = sieve_interpreter_get_mail(interpreter); + struct sieve_coded_stringlist *hdr_list; + struct sieve_coded_stringlist *key_list; + string_t *hdr_item; + bool matched; + + printf("?? ADDRESS\n"); + + t_push(); + + /* Read header-list */ + if ( (hdr_list=sieve_interpreter_read_stringlist_operand(interpreter)) == NULL ) { + t_pop(); + return FALSE; + } + + /* Read key-list */ + if ( (key_list=sieve_interpreter_read_stringlist_operand(interpreter)) == NULL ) { + t_pop(); + return FALSE; + } + + /* Iterate through all requested headers to match */ + hdr_item = NULL; + matched = FALSE; + while ( !matched && sieve_coded_stringlist_next_item(hdr_list, &hdr_item) && hdr_item != NULL ) { + const char *const *headers; + + if ( mail_get_headers_utf8(mail, str_c(hdr_item), &headers) >= 0 ) { + + int i; + for ( i = 0; !matched && headers[i] != NULL; i++ ) { + if ( sieve_stringlist_match(key_list, headers[i]) ) + matched = TRUE; + } + } + } + + t_pop(); + + sieve_interpreter_set_test_result(interpreter, matched); + + return TRUE; } diff --git a/src/lib-sieve/tst-size.c b/src/lib-sieve/tst-size.c index 751c76f45..20f89cd76 100644 --- a/src/lib-sieve/tst-size.c +++ b/src/lib-sieve/tst-size.c @@ -11,11 +11,13 @@ static bool tst_size_over_opcode_dump(struct sieve_interpreter *interpreter); static bool tst_size_under_opcode_dump(struct sieve_interpreter *interpreter); +static bool tst_size_over_opcode_execute(struct sieve_interpreter *interpreter); +static bool tst_size_under_opcode_execute(struct sieve_interpreter *interpreter); const struct sieve_opcode tst_size_over_opcode = - { tst_size_over_opcode_dump, NULL }; + { tst_size_over_opcode_dump, tst_size_over_opcode_execute }; const struct sieve_opcode tst_size_under_opcode = - { tst_size_under_opcode_dump, NULL }; + { tst_size_under_opcode_dump, tst_size_under_opcode_execute }; /* Context structures */ @@ -147,3 +149,52 @@ static bool tst_size_under_opcode_dump(struct sieve_interpreter *interpreter) return TRUE; } + +/* Code execution */ + +static bool tst_size_get(struct sieve_interpreter *interpreter, sieve_size_t *size) +{ + struct mail *mail = sieve_interpreter_get_mail(interpreter); + uoff_t psize; + + if ( mail_get_physical_size(mail, &psize) < 0 ) + return FALSE; + + *size = psize; + + return TRUE; +} + +static bool tst_size_over_opcode_execute(struct sieve_interpreter *interpreter) +{ + sieve_size_t mail_size, limit; + + printf("SIZEOVER\n"); + + if ( !sieve_interpreter_read_number_operand(interpreter, &limit) ) + return FALSE; + + if ( !tst_size_get(interpreter, &mail_size) ) + return FALSE; + + sieve_interpreter_set_test_result(interpreter, (mail_size > limit)); + + return TRUE; +} + +static bool tst_size_under_opcode_execute(struct sieve_interpreter *interpreter) +{ + sieve_size_t mail_size, limit; + + printf("SIZEUNDER\n"); + + if ( !sieve_interpreter_read_number_operand(interpreter, &limit) ) + return FALSE; + + if ( !tst_size_get(interpreter, &mail_size) ) + return FALSE; + + sieve_interpreter_set_test_result(interpreter, (mail_size < limit)); + + return TRUE; +} diff --git a/src/sieve-bin/Makefile.am b/src/sieve-bin/Makefile.am index 2aa0b5243..f00371f1a 100644 --- a/src/sieve-bin/Makefile.am +++ b/src/sieve-bin/Makefile.am @@ -16,8 +16,8 @@ plugin_dir = \ plugins = \ $(plugin_dir)/vacation/lib_ext_vacation.a -sievec_LDFLAGS = -export-dynamic -sieve_test_LDFLAGS = -export-dynamic +sievec_LDFLAGS = -export-dynamic -Wl,--start-group +sieve_test_LDFLAGS = -export-dynamic -Wl,--start-group libs = \ $(top_srcdir)/src/lib-sieve/libsieve.a \ diff --git a/src/sieve-bin/sieve_test.c b/src/sieve-bin/sieve_test.c index 367609f99..da3cf665f 100644 --- a/src/sieve-bin/sieve_test.c +++ b/src/sieve-bin/sieve_test.c @@ -185,22 +185,22 @@ create_mbox_stream(int fd, const char *envelope_sender, bool **first_r) return input; } -void mail_test(struct mail *mail) +void sieve_test(struct sieve_binary *sbin, struct mail *mail) { const char *const *headers; printf("HEADERS\n"); - if (mail_get_headers_utf8(mail, "from", &headers) >= 0) - { - printf("HEADERS FOUND\n"); + if (mail_get_headers_utf8(mail, "from", &headers) >= 0) { int i; for ( i = 0; headers[i] != NULL; i++ ) { printf("HEADER: From: %s\n", headers[i]); - } + } } + + sieve_execute(sbin, mail); } -int main(void) +int main(int argc, char **argv) { const char *envelope_sender = DEFAULT_ENVELOPE_SENDER; const char *mailbox = "INBOX"; @@ -215,6 +215,8 @@ int main(void) uid_t process_euid; pool_t namespace_pool; bool *input_first; + int fd; + struct sieve_binary *sbin; lib_init(); ioloop = io_loop_create(); @@ -224,6 +226,27 @@ int main(void) lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL); lib_signals_ignore(SIGPIPE, TRUE); lib_signals_ignore(SIGALRM, FALSE); + + if ( argc < 2 ) { + printf( "Usage: sieve_test <filename>\n"); + exit(1); + } + + /* Compile sieve script */ + + if ( (fd = open(argv[1], O_RDONLY)) < 0 ) { + perror("open()"); + exit(1); + } + + printf("Parsing sieve script '%s'...\n", argv[1]); + + if ( (sbin = sieve_compile(fd)) == NULL ) + exit(1); + + (void) sieve_dump(sbin); + + close(fd); /* we're non-root. get our username and possibly our home. */ process_euid = geteuid(); @@ -264,7 +287,7 @@ int main(void) /* */ i_stream_seek(input, 0); - mail_test(mail); + sieve_test(sbin, mail); //ret = deliver_save(ns, &storage, mailbox, mail, 0, NULL); i_stream_unref(&input); diff --git a/src/sieve-bin/sievec.c b/src/sieve-bin/sievec.c index a4e01dbb7..583ea07af 100644 --- a/src/sieve-bin/sievec.c +++ b/src/sieve-bin/sievec.c @@ -35,7 +35,9 @@ int main(int argc, char **argv) { printf("Parsing sieve script '%s'...\n", argv[1]); sbin = sieve_compile(fd); - (void) sieve_dump(sbin); + + if ( sbin != NULL ) + (void) sieve_dump(sbin); close(fd); } -- GitLab