From 5135e910c18e9920909d3ade53e3dc5665389334 Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Sat, 27 Oct 2007 04:25:17 +0200 Subject: [PATCH] Moved literall access functions from interpreter to binary. --- src/lib-sieve/sieve-binary.c | 230 +++++++++++++++++++++++++-- src/lib-sieve/sieve-binary.h | 23 ++- src/lib-sieve/sieve-comparators.c | 2 + src/lib-sieve/sieve-interpreter.c | 253 ++++++------------------------ src/lib-sieve/sieve-interpreter.h | 14 +- 5 files changed, 287 insertions(+), 235 deletions(-) diff --git a/src/lib-sieve/sieve-binary.c b/src/lib-sieve/sieve-binary.c index c0d7a8bcd..073b0f174 100644 --- a/src/lib-sieve/sieve-binary.c +++ b/src/lib-sieve/sieve-binary.c @@ -5,10 +5,22 @@ #include "sieve-binary.h" +struct sieve_coded_stringlist { + struct sieve_binary *binary; + sieve_size_t start_address; + sieve_size_t end_address; + sieve_size_t current_offset; + int length; + int index; +}; + struct sieve_binary { pool_t pool; ARRAY_DEFINE(extensions, const struct sieve_extension *); - buffer_t *code; + buffer_t *data; + + const char *code; + size_t code_size; }; struct sieve_binary *sieve_binary_create_new(void) @@ -20,7 +32,7 @@ struct sieve_binary *sieve_binary_create_new(void) binary = p_new(pool, struct sieve_binary, 1); binary->pool = pool; - binary->code = buffer_create_dynamic(pool, 256); + binary->data = buffer_create_dynamic(pool, 256); p_array_init(&binary->extensions, pool, 4); @@ -40,6 +52,16 @@ void sieve_binary_unref(struct sieve_binary **binary) } } +inline sieve_size_t sieve_binary_get_code_size(struct sieve_binary *binary) +{ + return buffer_get_used_size(binary->data); +} + +void sieve_binary_commit(struct sieve_binary *binary) +{ + binary->code = buffer_get_data(binary->data, &(binary->code_size)); +} + /* Extension handling */ unsigned int sieve_binary_link_extension(struct sieve_binary *binary, const struct sieve_extension *extension) @@ -69,9 +91,9 @@ const struct sieve_extension *sieve_binary_get_extension(struct sieve_binary *bi inline sieve_size_t sieve_binary_emit_data(struct sieve_binary *binary, void *data, sieve_size_t size) { - sieve_size_t address = buffer_get_used_size(binary->code); + sieve_size_t address = buffer_get_used_size(binary->data); - buffer_append(binary->code, data, size); + buffer_append(binary->data, data, size); return address; } @@ -84,17 +106,7 @@ inline sieve_size_t sieve_binary_emit_byte(struct sieve_binary *binary, unsigned inline void sieve_binary_update_data (struct sieve_binary *binary, sieve_size_t address, void *data, sieve_size_t size) { - buffer_write(binary->code, address, data, size); -} - -inline sieve_size_t sieve_binary_get_code_size(struct sieve_binary *binary) -{ - return buffer_get_used_size(binary->code); -} - -inline const char *sieve_binary_get_code(struct sieve_binary *binary, sieve_size_t *code_size) -{ - return buffer_get_data(binary->code, code_size); + buffer_write(binary->data, address, data, size); } /* Offset emission functions */ @@ -158,8 +170,196 @@ sieve_size_t sieve_binary_emit_string(struct sieve_binary *binary, const string_ return address; } + +/* + * Code retrieval + */ +#define ADDR_CODE_AT(binary, address) (binary->code[*address]) +#define ADDR_DATA_AT(binary, address) ((unsigned char) (binary->code[*address])) +#define ADDR_BYTES_LEFT(binary, address) (binary->code_size - (*address)) +#define ADDR_JUMP(address, offset) (*address) += offset +/* Literals */ + +bool sieve_binary_read_byte + (struct sieve_binary *binary, sieve_size_t *address, unsigned int *byte_val) +{ + if ( ADDR_BYTES_LEFT(binary, address) >= 1 ) { + if ( byte_val != NULL ) + *byte_val = ADDR_DATA_AT(binary, address); + ADDR_JUMP(address, 1); + + return TRUE; + } + + return FALSE; +} + +bool sieve_binary_read_offset + (struct sieve_binary *binary, sieve_size_t *address, int *offset) +{ + uint32_t offs = 0; + + if ( ADDR_BYTES_LEFT(binary, address) >= 4 ) { + int i; + + for ( i = 0; i < 4; i++ ) { + offs = (offs << 8) + ADDR_DATA_AT(binary, address); + ADDR_JUMP(address, 1); + } + + if ( offset != NULL ) + *offset = (int) offs; + + return TRUE; + } + + return FALSE; +} + +bool sieve_binary_read_integer + (struct sieve_binary *binary, sieve_size_t *address, sieve_size_t *integer) +{ + int bits = sizeof(sieve_size_t) * 8; + *integer = 0; + + while ( (ADDR_DATA_AT(binary, address) & 0x80) > 0 ) { + if ( ADDR_BYTES_LEFT(binary, address) > 0 && bits > 0) { + *integer |= ADDR_DATA_AT(binary, address) & 0x7F; + ADDR_JUMP(address, 1); + + *integer <<= 7; + bits -= 7; + } else { + /* This is an error */ + return FALSE; + } + } + + *integer |= ADDR_DATA_AT(binary, address) & 0x7F; + ADDR_JUMP(address, 1); + + return TRUE; +} + +/* FIXME: add this to lib/str. */ +static string_t *t_str_const(const void *cdata, size_t 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_binary_read_string + (struct sieve_binary *binary, sieve_size_t *address, string_t **str) +{ + sieve_size_t strlen = 0; + + if ( !sieve_binary_read_integer(binary, address, &strlen) ) + return FALSE; + + if ( strlen > ADDR_BYTES_LEFT(binary, address) ) + return FALSE; + + *str = t_str_const(&ADDR_CODE_AT(binary, address), strlen); + ADDR_JUMP(address, strlen); + + return TRUE; +} + +/* String list */ + +struct sieve_coded_stringlist *sieve_binary_read_stringlist + (struct sieve_binary *binary, sieve_size_t *address, bool single) +{ + 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_binary_read_integer(binary, address, &strlen) ) + return FALSE; + + end = *address + strlen; + length = 1; + *address = pc; + } else { + int end_offset; + + if ( !sieve_binary_read_offset(binary, address, &end_offset) ) + return NULL; + + end = pc + end_offset; + + if ( !sieve_binary_read_integer(binary, address, &length) ) + return NULL; + } + + if ( end > binary->code_size ) + return NULL; + + strlist = p_new(pool_datastack_create(), struct sieve_coded_stringlist, 1); + strlist->binary = binary; + strlist->start_address = *address; + strlist->current_offset = *address; + strlist->end_address = end; + strlist->length = length; + strlist->index = 0; + + /* Skip over the string list for now */ + *address = end; + + return strlist; +} + +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 { + address = strlist->current_offset; + + if ( sieve_binary_read_string(strlist->binary, &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; +} + +inline int sieve_coded_stringlist_get_length(struct sieve_coded_stringlist *strlist) +{ + return strlist->length; +} + +inline sieve_size_t sieve_coded_stringlist_get_end_address(struct sieve_coded_stringlist *strlist) +{ + return strlist->end_address; +} + +inline sieve_size_t sieve_coded_stringlist_get_current_offset(struct sieve_coded_stringlist *strlist) +{ + return strlist->current_offset; +} diff --git a/src/lib-sieve/sieve-binary.h b/src/lib-sieve/sieve-binary.h index f731deea8..a3f03dd00 100644 --- a/src/lib-sieve/sieve-binary.h +++ b/src/lib-sieve/sieve-binary.h @@ -13,6 +13,8 @@ struct sieve_binary *sieve_binary_create_new(void); void sieve_binary_ref(struct sieve_binary *binary); void sieve_binary_unref(struct sieve_binary **binary); +void sieve_binary_commit(struct sieve_binary *binary); + /* * Extension handling */ @@ -46,6 +48,25 @@ sieve_size_t sieve_binary_emit_string(struct sieve_binary *binary, const string_ * Code retrieval */ -inline const char *sieve_binary_get_code(struct sieve_binary *binary, sieve_size_t *code_size); +/* Literals */ +bool sieve_binary_read_byte + (struct sieve_binary *binary, sieve_size_t *address, unsigned int *byte_val); +bool sieve_binary_read_offset + (struct sieve_binary *binary, sieve_size_t *address, int *offset); +bool sieve_binary_read_integer + (struct sieve_binary *binary, sieve_size_t *address, sieve_size_t *integer); +bool sieve_binary_read_string + (struct sieve_binary *binary, sieve_size_t *address, string_t **str); + +/* String list */ + +struct sieve_coded_stringlist *sieve_binary_read_stringlist + (struct sieve_binary *binary, 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); + +inline int sieve_coded_stringlist_get_length(struct sieve_coded_stringlist *strlist); +inline sieve_size_t sieve_coded_stringlist_get_end_address(struct sieve_coded_stringlist *strlist); +inline sieve_size_t sieve_coded_stringlist_get_current_offset(struct sieve_coded_stringlist *strlist); #endif diff --git a/src/lib-sieve/sieve-comparators.c b/src/lib-sieve/sieve-comparators.c index c404e6012..ea7dd1404 100644 --- a/src/lib-sieve/sieve-comparators.c +++ b/src/lib-sieve/sieve-comparators.c @@ -80,6 +80,8 @@ static bool tag_comparator_generate opr_comparator_emit(generator, (struct sieve_comparator *) (*arg)->context); *arg = sieve_ast_argument_next(*arg); + + return TRUE; } /* diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c index 771dcadcc..39285a796 100644 --- a/src/lib-sieve/sieve-interpreter.c +++ b/src/lib-sieve/sieve-interpreter.c @@ -13,34 +13,11 @@ #include "sieve-interpreter.h" -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; -}; - -#define CODE_AT_PC(interpreter) (interpreter->code[interpreter->pc]) -#define DATA_AT_PC(interpreter) ((unsigned char) (interpreter->code[interpreter->pc])) -#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; struct sieve_binary *binary; - - /* Direct pointer to code inside binary (which is considered immutable) */ - const char *code; - sieve_size_t code_size; - + /* Execution status */ sieve_size_t pc; bool test_result; @@ -60,8 +37,8 @@ struct sieve_interpreter *sieve_interpreter_create(struct sieve_binary *binary) interpreter->pool = pool; interpreter->binary = binary; - interpreter->code = sieve_binary_get_code(binary, &interpreter->code_size); sieve_binary_ref(binary); + sieve_binary_commit(binary); interpreter->pc = 0; @@ -99,10 +76,10 @@ inline bool sieve_interpreter_program_jump sieve_size_t pc = sieve_interpreter_program_counter(interpreter); int offset; - if ( !sieve_interpreter_read_offset(interpreter, &(interpreter->pc), &offset) ) + if ( !sieve_interpreter_read_offset_operand(interpreter, &offset) ) return FALSE; - if ( pc + offset <= interpreter->code_size && pc + offset > 0 ) { + if ( pc + offset <= sieve_binary_get_code_size(interpreter->binary) && pc + offset > 0 ) { if ( jump ) interpreter->pc = pc + offset; @@ -122,155 +99,6 @@ inline bool sieve_interpreter_get_test_result(struct sieve_interpreter *interpre return interpreter->test_result; } -/* Literals */ - -bool sieve_interpreter_read_offset - (struct sieve_interpreter *interpreter, sieve_size_t *address, int *offset) -{ - uint32_t offs = 0; - - if ( ADDR_BYTES_LEFT(interpreter, address) >= 4 ) { - int i; - - for ( i = 0; i < 4; i++ ) { - offs = (offs << 8) + ADDR_DATA_AT(interpreter, address); - ADDR_JUMP(address, 1); - } - - if ( offset != NULL ) - *offset = (int) offs; - - return TRUE; - } - - return FALSE; -} - -bool sieve_interpreter_read_integer - (struct sieve_interpreter *interpreter, sieve_size_t *address, sieve_size_t *integer) -{ - int bits = sizeof(sieve_size_t) * 8; - *integer = 0; - - 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; - } else { - /* This is an error */ - return FALSE; - } - } - - *integer |= ADDR_DATA_AT(interpreter, address) & 0x7F; - ADDR_JUMP(address, 1); - - return TRUE; -} - -/* FIXME: add this to lib/str. */ -static string_t *t_str_const(const void *cdata, size_t 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, sieve_size_t *address, string_t **str) -{ - sieve_size_t strlen = 0; - - if ( !sieve_interpreter_read_integer(interpreter, address, &strlen) ) - return FALSE; - - if ( strlen > ADDR_BYTES_LEFT(interpreter, address) ) - return FALSE; - - *str = t_str_const(&ADDR_CODE_AT(interpreter, address), strlen); - ADDR_JUMP(address, strlen); - - return TRUE; -} - -struct sieve_coded_stringlist *sieve_interpreter_read_stringlist - (struct sieve_interpreter *interpreter, sieve_size_t *address, bool single) -{ - 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; - - 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 = *address; - strlist->current_offset = *address; - strlist->end_address = end; - strlist->length = length; - strlist->index = 0; - - /* Skip over the string list for now */ - *address = end; - - return strlist; -} - -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 { - 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 */ @@ -279,9 +107,7 @@ static const struct sieve_opcode *sieve_interpreter_read_opcode { unsigned int opcode; - if ( CODE_BYTES_LEFT(interpreter) > 0 ) { - opcode = DATA_AT_PC(interpreter); - CODE_JUMP(interpreter, 1); + if ( sieve_binary_read_byte(interpreter->binary, &(interpreter->pc), &opcode) ) { if ( opcode < SIEVE_OPCODE_EXT_OFFSET ) { if ( opcode < sieve_opcode_count ) @@ -305,38 +131,48 @@ static const struct sieve_opcode *sieve_interpreter_read_opcode bool sieve_interpreter_read_offset_operand (struct sieve_interpreter *interpreter, int *offset) { - return sieve_interpreter_read_offset(interpreter, &(interpreter->pc), offset); + return sieve_binary_read_offset(interpreter->binary, &(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 ) { + unsigned int op; + + if ( !sieve_binary_read_byte(interpreter->binary, &(interpreter->pc), &op) ) return FALSE; - } - CODE_JUMP(interpreter, 1); - - return sieve_interpreter_read_integer(interpreter, &(interpreter->pc), number); + + if ( op != SIEVE_OPERAND_NUMBER ) + return FALSE; + + return sieve_binary_read_integer(interpreter->binary, &(interpreter->pc), number); } bool sieve_interpreter_read_string_operand (struct sieve_interpreter *interpreter, string_t **str) { - if ( CODE_AT_PC(interpreter) != SIEVE_OPERAND_STRING ) { + unsigned int op; + + if ( !sieve_binary_read_byte(interpreter->binary, &(interpreter->pc), &op) ) return FALSE; - } - CODE_JUMP(interpreter, 1); - - return sieve_interpreter_read_string(interpreter, &(interpreter->pc), str); + + if ( op != SIEVE_OPERAND_STRING ) + return FALSE; + + return sieve_binary_read_string(interpreter->binary, &(interpreter->pc), str); } struct sieve_coded_stringlist * sieve_interpreter_read_stringlist_operand (struct sieve_interpreter *interpreter) { + unsigned int op; bool single = FALSE; - switch ( CODE_AT_PC(interpreter) ) { + if ( !sieve_binary_read_byte(interpreter->binary, &(interpreter->pc), &op) ) + return FALSE; + + switch ( op ) { case SIEVE_OPERAND_STRING: single = TRUE; break; @@ -346,10 +182,9 @@ struct sieve_coded_stringlist * default: return NULL; } - CODE_JUMP(interpreter, 1); - return sieve_interpreter_read_stringlist - (interpreter, &(interpreter->pc), single); + return sieve_binary_read_stringlist + (interpreter->binary, &(interpreter->pc), single); } /* Stringlist Utility */ @@ -396,7 +231,7 @@ bool sieve_interpreter_dump_number { sieve_size_t number = 0; - if (sieve_interpreter_read_integer(interpreter, &(interpreter->pc), &number) ) { + if (sieve_binary_read_integer(interpreter->binary, &(interpreter->pc), &number) ) { printf("NUM: %ld\n", (long) number); return TRUE; @@ -432,7 +267,7 @@ bool sieve_interpreter_dump_string { string_t *str; - if ( sieve_interpreter_read_string(interpreter, &(interpreter->pc), &str) ) { + if ( sieve_binary_read_string(interpreter->binary, &(interpreter->pc), &str) ) { sieve_interpreter_print_string(str); return TRUE; @@ -446,17 +281,19 @@ bool sieve_interpreter_dump_string_list { struct sieve_coded_stringlist *strlist; - if ( (strlist=sieve_interpreter_read_stringlist(interpreter, &(interpreter->pc), FALSE)) != NULL ) { + if ( (strlist=sieve_binary_read_stringlist(interpreter->binary, &(interpreter->pc), FALSE)) != NULL ) { sieve_size_t pc; string_t *stritem; - printf("STRLIST [%d] (END %08x)\n", strlist->length, strlist->end_address); + printf("STRLIST [%d] (END %08x)\n", + sieve_coded_stringlist_get_length(strlist), + sieve_coded_stringlist_get_end_address(strlist)); - pc = strlist->current_offset; + pc = sieve_coded_stringlist_get_current_offset(strlist); while ( sieve_coded_stringlist_next_item(strlist, &stritem) && stritem != NULL ) { printf("%08x: ", pc); sieve_interpreter_print_string(stritem); - pc = strlist->current_offset; + pc = sieve_coded_stringlist_get_current_offset(strlist); } return TRUE; @@ -468,12 +305,14 @@ bool sieve_interpreter_dump_string_list bool sieve_interpreter_dump_operand (struct sieve_interpreter *interpreter) { - char opcode = CODE_AT_PC(interpreter); + unsigned int op; printf("%08x: ", interpreter->pc); - CODE_JUMP(interpreter, 1); + + if ( !sieve_binary_read_byte(interpreter->binary, &(interpreter->pc), &op) ) + return FALSE; - if ( opcode < SIEVE_OPERAND_CORE_MASK ) { - switch (opcode) { + if ( op < SIEVE_OPERAND_CORE_MASK ) { + switch (op) { case SIEVE_OPERAND_NUMBER: sieve_interpreter_dump_number(interpreter); break; @@ -501,14 +340,14 @@ void sieve_interpreter_dump_code(struct sieve_interpreter *interpreter) interpreter->result = NULL; interpreter->mail = NULL; - while ( interpreter->pc < interpreter->code_size ) { + while ( interpreter->pc < sieve_binary_get_code_size(interpreter->binary) ) { if ( !sieve_interpreter_dump_operation(interpreter) ) { printf("Binary is corrupt.\n"); return; } } - printf("%08x: [End of code]\n", interpreter->code_size); + printf("%08x: [End of code]\n", sieve_binary_get_code_size(interpreter->binary)); } /* Code execute */ @@ -540,7 +379,7 @@ struct sieve_result *sieve_interpreter_run interpreter->result = result; interpreter->mail = mail; - while ( interpreter->pc < interpreter->code_size ) { + while ( interpreter->pc < sieve_binary_get_code_size(interpreter->binary) ) { printf("%08x: ", interpreter->pc); if ( !sieve_interpreter_execute_opcode(interpreter) ) { diff --git a/src/lib-sieve/sieve-interpreter.h b/src/lib-sieve/sieve-interpreter.h index f022fb96c..87231e046 100644 --- a/src/lib-sieve/sieve-interpreter.h +++ b/src/lib-sieve/sieve-interpreter.h @@ -26,19 +26,8 @@ inline void sieve_interpreter_set_test_result inline bool sieve_interpreter_get_test_result (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 *address, sieve_size_t *integer); -bool sieve_interpreter_read_string - (struct sieve_interpreter *interpreter, sieve_size_t *address, 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 @@ -54,6 +43,7 @@ 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) */ -- GitLab