diff --git a/sieve/tests/comparator.sieve b/sieve/tests/comparator.sieve index 291276ab2a98575175607afffe5151dcec13802d..ae157db47c78db1ee2a1976f947ab115dfc4a8de 100644 --- a/sieve/tests/comparator.sieve +++ b/sieve/tests/comparator.sieve @@ -1,7 +1,7 @@ -if header :is :comparator "i;ascii-casemap" "from" "STEPHAN@drunksnipers.com" { +if header :comparator "i;ascii-casemap" "from" "STEPHAN@drunksnipers.com" { discard; - if address :is :comparator "i;octet" :domain "from" "drunksnipers.com" { + if address :comparator "i;octet" "from" "drunksnipers.com" { keep; } stop; diff --git a/src/lib-sieve/Makefile.am b/src/lib-sieve/Makefile.am index 9c08e2289d009ca85d72912aa9fad430ea1caaa9..7cac3ae3db0c4e446c99d62a5e271699ac145ab3 100644 --- a/src/lib-sieve/Makefile.am +++ b/src/lib-sieve/Makefile.am @@ -38,6 +38,7 @@ libsieve_a_SOURCES = \ sieve-result.c \ sieve-error.c \ sieve-comparators.c \ + sieve-address-parts.c \ sieve-commands.c \ sieve-code.c \ $(tsts) \ @@ -57,6 +58,7 @@ noinst_HEADERS = \ sieve-result.h sieve-error.h \ sieve-comparators.h \ + sieve-address-parts.h \ sieve-commands.h \ sieve-code.h \ sieve-extensions.h \ diff --git a/src/lib-sieve/cmd-require.c b/src/lib-sieve/cmd-require.c index 22388510c416e74f4a89f7ad7109f9858d95649c..67e40f935f63887da08662ee106567fbebd7c967 100644 --- a/src/lib-sieve/cmd-require.c +++ b/src/lib-sieve/cmd-require.c @@ -36,18 +36,25 @@ bool cmd_require_validate(struct sieve_validator *validator, struct sieve_comman cmd->data = (void *) arg; /* Check argument and load specified extension(s) */ - if ( sieve_ast_argument_type(arg) == SAAT_STRING ) + if ( sieve_ast_argument_type(arg) == SAAT_STRING ) { /* Single string */ - arg->context = (void *) sieve_validator_load_extension + int ext_id = sieve_validator_extension_load (validator, cmd, sieve_ast_argument_strc(arg)); - else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) { + + if ( ext_id < 0 ) return FALSE; + arg->context = (void *) ext_id; + + } else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) { /* String list */ struct sieve_ast_argument *stritem = sieve_ast_strlist_first(arg); while ( stritem != NULL ) { - stritem->context = (void *) sieve_validator_load_extension + int ext_id = sieve_validator_extension_load (validator, cmd, sieve_ast_strlist_strc(stritem)); - + + if ( ext_id < 0 ) return FALSE; + stritem->context = (void *) ext_id; + stritem = sieve_ast_strlist_next(stritem); } } else { @@ -67,17 +74,17 @@ bool cmd_require_generate struct sieve_ast_argument *arg = (struct sieve_ast_argument *) ctx->data; if ( sieve_ast_argument_type(arg) == SAAT_STRING ) { - struct sieve_extension *ext = (struct sieve_extension *) arg->context; + int ext_id = (int) arg->context; - sieve_generator_register_extension(generator, ext); + sieve_generator_link_extension(generator, ext_id); } else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) { /* String list */ struct sieve_ast_argument *stritem = sieve_ast_strlist_first(arg); while ( stritem != NULL ) { - struct sieve_extension *ext = (struct sieve_extension *) stritem->context; + int ext_id = (int) stritem->context; - sieve_generator_register_extension(generator, ext); + sieve_generator_link_extension(generator, ext_id); stritem = sieve_ast_strlist_next(stritem); } diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c index 268ad1154294325b5361bad6ad8fed52634e190a..66fa6e8938d8a48ef8975afca4210a4c2a8b0c4a 100644 --- a/src/lib-sieve/ext-envelope.c +++ b/src/lib-sieve/ext-envelope.c @@ -2,12 +2,16 @@ #include "sieve-extensions.h" #include "sieve-commands.h" +#include "sieve-comparators.h" +#include "sieve-address-parts.h" + #include "sieve-validator.h" #include "sieve-generator.h" #include "sieve-interpreter.h" /* Forward declarations */ +static bool ext_envelope_load(int ext_id); static bool ext_envelope_validator_load(struct sieve_validator *validator); static bool ext_envelope_opcode_dump @@ -22,14 +26,30 @@ static bool tst_envelope_generate /* Extension definitions */ +static int ext_my_id; + const struct sieve_opcode envelope_opcode = { ext_envelope_opcode_dump, NULL }; -const struct sieve_extension envelope_extension = - { "envelope", ext_envelope_validator_load, NULL, NULL, &envelope_opcode, NULL }; + +const struct sieve_extension envelope_extension = { + "envelope", + ext_envelope_load, + ext_envelope_validator_load, + NULL, + NULL, + &envelope_opcode, + NULL +}; static const struct sieve_command envelope_test = { "envelope", SCT_TEST, tst_envelope_registered, tst_envelope_validate, tst_envelope_generate, NULL }; +static bool ext_envelope_load(int ext_id) +{ + ext_my_id = ext_id; + return TRUE; +} + /* Optional arguments */ enum tst_envelope_optional { @@ -43,8 +63,8 @@ enum tst_envelope_optional { static bool tst_envelope_registered(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) { /* The order of these is not significant */ - sieve_validator_link_comparator_tag(validator, cmd_reg, OPT_COMPARATOR); - sieve_validator_link_address_part_tags(validator, cmd_reg, OPT_ADDRESS_PART); + sieve_comparators_link_tag(validator, cmd_reg, OPT_COMPARATOR); + sieve_address_parts_link_tags(validator, cmd_reg, OPT_ADDRESS_PART); sieve_validator_link_match_type_tags(validator, cmd_reg, OPT_MATCH_TYPE); return TRUE; @@ -103,7 +123,7 @@ static bool ext_envelope_validator_load(struct sieve_validator *validator) static bool tst_envelope_generate (struct sieve_generator *generator, struct sieve_command_context *ctx) { - sieve_generator_emit_opcode_ext(generator, &envelope_extension); + (void)sieve_generator_emit_opcode_ext(generator, ext_my_id); /* Generate arguments */ if ( !sieve_generate_arguments(generator, ctx, NULL) ) diff --git a/src/lib-sieve/ext-fileinto.c b/src/lib-sieve/ext-fileinto.c index fcb23480e3ed034aadf2d838af21a9da3b839633..42d0cbb53b2e3a71f7581c0d24e70caf5d98bfab 100644 --- a/src/lib-sieve/ext-fileinto.c +++ b/src/lib-sieve/ext-fileinto.c @@ -7,6 +7,7 @@ #include "sieve-interpreter.h" /* Forward declarations */ +static bool ext_fileinto_load(int ext_id); static bool ext_fileinto_validator_load(struct sieve_validator *validator); static bool ext_fileinto_opcode_dump @@ -18,14 +19,31 @@ static bool cmd_fileinto_validate(struct sieve_validator *validator, struct siev static bool cmd_fileinto_generate(struct sieve_generator *generator, struct sieve_command_context *ctx); /* Extension definitions */ + +static int ext_my_id; + const struct sieve_opcode fileinto_opcode = { ext_fileinto_opcode_dump, ext_fileinto_opcode_execute }; -const struct sieve_extension fileinto_extension = - { "fileinto", ext_fileinto_validator_load, NULL, NULL, &fileinto_opcode, NULL }; +const struct sieve_extension fileinto_extension = { + "fileinto", + ext_fileinto_load, + ext_fileinto_validator_load, + NULL, + NULL, + &fileinto_opcode, + NULL +}; + static const struct sieve_command fileinto_command = { "fileinto", SCT_COMMAND, NULL, cmd_fileinto_validate, cmd_fileinto_generate, NULL }; +static bool ext_fileinto_load(int ext_id) +{ + ext_my_id = ext_id; + return TRUE; +} + /* Validation */ static bool cmd_fileinto_validate(struct sieve_validator *validator, struct sieve_command_context *cmd) @@ -64,7 +82,7 @@ static bool ext_fileinto_validator_load(struct sieve_validator *validator) static bool cmd_fileinto_generate (struct sieve_generator *generator, struct sieve_command_context *ctx) { - sieve_generator_emit_opcode_ext(generator, &fileinto_extension); + sieve_generator_emit_opcode_ext(generator, ext_my_id); /* Generate arguments */ if ( !sieve_generate_arguments(generator, ctx, NULL) ) diff --git a/src/lib-sieve/ext-reject.c b/src/lib-sieve/ext-reject.c index de5dd7c8a2d2a54e406f7d1f88f3cd5fc9b53768..141123a02234980a32451975c6ffb38be4232dec 100644 --- a/src/lib-sieve/ext-reject.c +++ b/src/lib-sieve/ext-reject.c @@ -8,24 +8,47 @@ /* Forward declarations */ -static bool cmd_reject_validate(struct sieve_validator *validator, struct sieve_command_context *cmd); -static bool cmd_reject_generate(struct sieve_generator *generator, struct sieve_command_context *ctx); - +static bool ext_reject_load(int ext_id); static bool ext_reject_validator_load(struct sieve_validator *validator); static bool ext_reject_generator_load(struct sieve_generator *generator); +static bool cmd_reject_validate(struct sieve_validator *validator, struct sieve_command_context *cmd); +static bool cmd_reject_generate(struct sieve_generator *generator, struct sieve_command_context *ctx); + static bool ext_reject_opcode_dump (struct sieve_interpreter *interp, struct sieve_binary *sbin, sieve_size_t *address); /* Extension definitions */ + +static int ext_my_id; + struct sieve_opcode reject_opcode = { ext_reject_opcode_dump, NULL }; -struct sieve_extension reject_extension = - { "reject", ext_reject_validator_load, ext_reject_generator_load, NULL, &reject_opcode, NULL }; - -static const struct sieve_command reject_command = - { "reject", SCT_COMMAND, NULL, cmd_reject_validate, cmd_reject_generate, NULL }; +struct sieve_extension reject_extension = { + "reject", + ext_reject_load, + ext_reject_validator_load, + ext_reject_generator_load, + NULL, + &reject_opcode, + NULL +}; + +static const struct sieve_command reject_command = { + "reject", + SCT_COMMAND, + NULL, + cmd_reject_validate, + cmd_reject_generate, + NULL +}; + +static bool ext_reject_load(int ext_id) +{ + ext_my_id = ext_id; + return TRUE; +} /* * Validation @@ -66,7 +89,7 @@ static bool ext_reject_validator_load(struct sieve_validator *validator) static bool cmd_reject_generate (struct sieve_generator *generator, struct sieve_command_context *ctx) { - sieve_generator_emit_opcode_ext(generator, &reject_extension); + sieve_generator_emit_opcode_ext(generator, ext_my_id); /* Generate arguments */ if ( !sieve_generate_arguments(generator, ctx, NULL) ) diff --git a/src/lib-sieve/plugins/vacation/ext-vacation.c b/src/lib-sieve/plugins/vacation/ext-vacation.c index 7d9d39dd1ff6e3baadbcd8a0db523481f4b633a3..13383a0d16c7a188d79b5e8b6060c03bfc79508b 100644 --- a/src/lib-sieve/plugins/vacation/ext-vacation.c +++ b/src/lib-sieve/plugins/vacation/ext-vacation.c @@ -10,6 +10,7 @@ #include "sieve-interpreter.h" /* Forward declarations */ +static bool ext_vacation_load(int ext_id); static bool ext_vacation_validator_load(struct sieve_validator *validator); static bool ext_vacation_opcode_dump @@ -20,12 +21,39 @@ static bool cmd_vacation_validate(struct sieve_validator *validator, struct siev static bool cmd_vacation_generate(struct sieve_generator *generator, struct sieve_command_context *ctx); /* Extension definitions */ -const struct sieve_opcode vacation_opcode = - { ext_vacation_opcode_dump, NULL }; -const struct sieve_extension vacation_extension = - { "vacation", ext_vacation_validator_load, NULL, NULL, &vacation_opcode, NULL}; -static const struct sieve_command vacation_command = - { "vacation", SCT_COMMAND, cmd_vacation_registered, cmd_vacation_validate, cmd_vacation_generate, NULL }; + +int ext_my_id; + +const struct sieve_opcode vacation_opcode = { + ext_vacation_opcode_dump, + NULL +}; + +const struct sieve_extension vacation_extension = { + "vacation", + ext_vacation_load, + ext_vacation_validator_load, + NULL, + NULL, + &vacation_opcode, + NULL +}; + +static const struct sieve_command vacation_command = { + "vacation", + SCT_COMMAND, + cmd_vacation_registered, + cmd_vacation_validate, + cmd_vacation_generate, + NULL +}; + +static bool ext_vacation_load(int ext_id) +{ + ext_my_id = ext_id; + + return TRUE; +} /* Tag validation */ @@ -243,7 +271,7 @@ static bool ext_vacation_validator_load(struct sieve_validator *validator) static bool cmd_vacation_generate (struct sieve_generator *generator, struct sieve_command_context *ctx) { - sieve_generator_emit_opcode_ext(generator, &vacation_extension); + sieve_generator_emit_opcode_ext(generator, ext_my_id); /* Generate arguments */ if ( !sieve_generate_arguments(generator, ctx, NULL) ) diff --git a/src/lib-sieve/sieve-address-parts.c b/src/lib-sieve/sieve-address-parts.c new file mode 100644 index 0000000000000000000000000000000000000000..595961096ae2e034a3fd39e6eb122b4c4e51c83b --- /dev/null +++ b/src/lib-sieve/sieve-address-parts.c @@ -0,0 +1,291 @@ +#include <stdio.h> + +#include "lib.h" +#include "compat.h" +#include "hash.h" +#include "array.h" + +#include "sieve-extensions.h" +#include "sieve-code.h" +#include "sieve-binary.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" + +#include "sieve-address-parts.h" + +#include <string.h> + +/* + * Predeclarations + */ + +static struct sieve_interpreter_registry *addrp_registry = NULL; + +static void opr_address_part_emit + (struct sieve_binary *sbin, unsigned int code); +static void opr_address_part_emit_ext + (struct sieve_binary *sbin, const struct sieve_extension *ext); + +/* + * Comparator 'extension' + */ + +static int ext_my_id = -1; + +static bool addrp_extension_load(int ext_id); +static bool addrp_validator_load(struct sieve_validator *validator); +static bool addrp_interpreter_load(struct sieve_interpreter *interp); + +const struct sieve_extension address_part_extension = { + "@address-part", + addrp_extension_load, + addrp_validator_load, + NULL, + NULL, //addrp_interpreter_load, + NULL, + NULL +}; + +static bool addrp_extension_load(int ext_id) +{ + ext_my_id = ext_id; + return TRUE; +} + +/* + * Validator context: + * name-based comparator registry. + */ + +struct addrp_validator_context { + struct hash_table *address_parts; +}; + +static inline struct addrp_validator_context * + get_validator_context(struct sieve_validator *validator) +{ + return (struct addrp_validator_context *) + sieve_validator_extension_get_context(validator, ext_my_id); +} + +void sieve_address_part_register + (struct sieve_validator *validator, const struct sieve_address_part *addrp) +{ + struct addrp_validator_context *ctx = get_validator_context(validator); + + hash_insert(ctx->address_parts, (void *) addrp->identifier, (void *) addrp); +} + +const struct sieve_address_part *sieve_address_part_find + (struct sieve_validator *validator, const char *addrp_name) +{ + struct addrp_validator_context *ctx = get_validator_context(validator); + + return (const struct sieve_address_part *) + hash_lookup(ctx->address_parts, addrp_name); +} + +static bool addrp_validator_load(struct sieve_validator *validator) +{ + unsigned int i; + pool_t pool = sieve_validator_pool(validator); + + struct addrp_validator_context *ctx = + p_new(pool, struct addrp_validator_context, 1); + + /* Setup comparator registry */ + ctx->address_parts = hash_create + (pool, pool, 0, str_hash, (hash_cmp_callback_t *)strcmp); + + /* Register core comparators */ + for ( i = 0; i < sieve_core_address_parts_count; i++ ) { + const struct sieve_address_part *addrp = sieve_core_address_parts[i]; + + hash_insert(ctx->address_parts, (void *) addrp->identifier, (void *) addrp); + } + + sieve_validator_extension_set_context(validator, ext_my_id, ctx); + + return TRUE; +} + + +/* + * Address-part operand + */ + +struct sieve_operand_class address_part_class = { "address-part", NULL }; +struct sieve_operand address_part_operand = { "address-part", &address_part_class, FALSE }; + +/* + * Address-part tag + */ + +static bool tag_address_part_validate + (struct sieve_validator *validator ATTR_UNUSED, + struct sieve_ast_argument **arg, + struct sieve_command_context *cmd ATTR_UNUSED) +{ + const struct sieve_address_part *addrp; + + /* Syntax: + * ":localpart" / ":domain" / ":all" + */ + + /* Get address_part from registry */ + addrp = sieve_address_part_find(validator, sieve_ast_argument_tag(*arg)); + + if ( addrp == NULL ) { + sieve_command_validate_error(validator, cmd, + "unknown address-part modifier '%s' " + "(this error should not occur and is probably a bug)", + sieve_ast_argument_strc(*arg)); + + return FALSE; + } + + /* Store comparator in context */ + (*arg)->context = (void *) addrp; + + /* Skip tag */ + *arg = sieve_ast_argument_next(*arg); + + return TRUE; +} + +const struct sieve_argument address_localpart_tag = + { "localpart", tag_address_part_validate, NULL }; +const struct sieve_argument address_domain_tag = + { "domain", tag_address_part_validate, NULL }; +const struct sieve_argument address_all_tag = + { "all", tag_address_part_validate, NULL }; + +/* Address part validation */ + +void sieve_address_parts_link_tags + (struct sieve_validator *validator, + struct sieve_command_registration *cmd_reg, + unsigned int id_code) +{ + sieve_validator_register_tag + (validator, cmd_reg, &address_localpart_tag, id_code); + sieve_validator_register_tag + (validator, cmd_reg, &address_domain_tag, id_code); + sieve_validator_register_tag + (validator, cmd_reg, &address_all_tag, id_code); +} + +/* Code generation */ + +static void opr_address_parts_emit + (struct sieve_binary *sbin, unsigned int code) +{ + (void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_ADDRESS_PART); + (void) sieve_binary_emit_byte(sbin, code); +} + +static void opr_address_parts_emit_ext + (struct sieve_binary *sbin, int ext_id) +{ + unsigned char cmp_code = SIEVE_ADDRESS_PART_CUSTOM + + sieve_binary_extension_get_index(sbin, ext_id); + + (void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_ADDRESS_PART); + (void) sieve_binary_emit_byte(sbin, cmp_code); +} + +const struct sieve_address_part *sieve_opr_address_part_read + (struct sieve_binary *sbin, sieve_size_t *address) +{ + unsigned int addrp_code; + const struct sieve_operand *operand = sieve_operand_read(sbin, address); + + if ( operand == NULL || operand->class != &address_part_class ) + return NULL; + + if ( sieve_binary_read_byte(sbin, address, &addrp_code) ) { + if ( addrp_code < SIEVE_ADDRESS_PART_CUSTOM ) { + if ( addrp_code < sieve_core_address_parts_count ) + return sieve_core_address_parts[addrp_code]; + else + return NULL; + } else { + /*const struct sieve_extension *ext = + sieve_binary_get_extension(sbin, cmp_code - SIEVE_ADDRESS_PART_CUSTOM); + + if ( ext != NULL ) + return (const struct sieve_address_part *) + sieve_interpreter_registry_get(addrp_registry, ext); + else*/ + return NULL; + } + } + + return NULL; +} + +bool sieve_opr_address_part_dump(struct sieve_binary *sbin, sieve_size_t *address) +{ + sieve_size_t pc = *address; + const struct sieve_address_part *addrp = sieve_opr_address_part_read(sbin, address); + + if ( addrp == NULL ) + return FALSE; + + printf("%08x: ADDRP: %s\n", pc, addrp->identifier); + + return TRUE; +} + +static bool tag_address_part_generate + (struct sieve_generator *generator, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd ATTR_UNUSED) +{ + struct sieve_binary *sbin = sieve_generator_get_binary(generator); + struct sieve_address_part *addrp = (struct sieve_address_part *) (*arg)->context; + + if ( addrp->extension == NULL ) { + if ( addrp->code < SIEVE_ADDRESS_PART_CUSTOM ) + opr_address_part_emit(sbin, addrp->code); + else + return FALSE; + } else { + //opr_comparator_emit_ext(sbin, cmp->extension); + } + + *arg = sieve_ast_argument_next(*arg); + + return TRUE; +} + +/* + * Core address-part modifiers + */ + +const struct sieve_address_part all_address_part = { + "all", + SIEVE_ADDRESS_PART_ALL, + NULL +}; + +const struct sieve_address_part local_address_part = { + "localpart", + SIEVE_ADDRESS_PART_LOCAL, + NULL +}; + +const struct sieve_address_part domain_address_part = { + "domain", + SIEVE_ADDRESS_PART_LOCAL, + NULL +}; + +const struct sieve_address_part *sieve_core_address_parts[] = { + &all_address_part, &local_address_part, &domain_address_part +}; + +const unsigned int sieve_core_address_parts_count = + (sizeof(sieve_core_address_parts) / sizeof(sieve_core_address_parts[0])); + + diff --git a/src/lib-sieve/sieve-address-parts.h b/src/lib-sieve/sieve-address-parts.h new file mode 100644 index 0000000000000000000000000000000000000000..a89b67e0dfe601ec42923d882aa172e0f82f450b --- /dev/null +++ b/src/lib-sieve/sieve-address-parts.h @@ -0,0 +1,42 @@ +#ifndef __SIEVE_ADDRESS_PARTS_H +#define __SIEVE_ADDRESS_PARTS_H + +enum sieve_address_part_code { + SIEVE_ADDRESS_PART_ALL, + SIEVE_ADDRESS_PART_LOCAL, + SIEVE_ADDRESS_PART_DOMAIN, + SIEVE_ADDRESS_PART_CUSTOM +}; + +struct sieve_address_part { + const char *identifier; + + enum sieve_address_part_code code; + const struct sieve_extension *extension; +}; + +void sieve_address_parts_link_tags + (struct sieve_validator *validator, + struct sieve_command_registration *cmd_reg, + unsigned int id_code); + +void sieve_address_part_register + (struct sieve_validator *validator, const struct sieve_address_part *addrp); +const struct sieve_address_part *sieve_address_part_find + (struct sieve_validator *validator, const char *addrp_name); + +const struct sieve_address_part all_address_part; +const struct sieve_address_part local_address_part; +const struct sieve_address_part domain_address_part; + +extern const struct sieve_address_part *sieve_core_address_parts[]; +extern const unsigned int sieve_core_address_parts_count; + +const struct sieve_address_part *sieve_opr_address_part_read + (struct sieve_binary *sbin, sieve_size_t *address); +bool sieve_opr_address_part_dump + (struct sieve_binary *sbin, sieve_size_t *address); + +void sieve_address_parts_init_registry(struct sieve_interpreter *interp); + +#endif /* __SIEVE_ADDRESS_PARTS_H */ diff --git a/src/lib-sieve/sieve-binary.c b/src/lib-sieve/sieve-binary.c index 1097e82271cfcaad148fc9b9ee9f45a3134bdd78..4357fddbff302937b294072b15bc7f5a86b8dcc9 100644 --- a/src/lib-sieve/sieve-binary.c +++ b/src/lib-sieve/sieve-binary.c @@ -5,19 +5,21 @@ #include "hash.h" #include "array.h" -#include "sieve-binary.h" +#include "sieve-extensions.h" #include "sieve-code.h" +#include "sieve-binary.h" -struct sieve_extension_registration { +struct sieve_binary_extension { const struct sieve_extension *extension; - unsigned int opcode; + int ext_id; + int index; }; struct sieve_binary { pool_t pool; - ARRAY_DEFINE(extensions, const struct sieve_extension *); - struct hash_table *extension_index; + ARRAY_DEFINE(extensions, struct sieve_binary_extension *); + ARRAY_DEFINE(extension_index, struct sieve_binary_extension *); buffer_t *data; @@ -36,9 +38,8 @@ struct sieve_binary *sieve_binary_create_new(void) sbin->data = buffer_create_dynamic(pool, 256); - p_array_init(&sbin->extensions, pool, 4); - sbin->extension_index = hash_create - (pool, pool, 0, NULL, NULL); + p_array_init(&sbin->extensions, pool, sieve_extensions_get_count()); + p_array_init(&sbin->extension_index, pool, sieve_extensions_get_count()); return sbin; } @@ -68,49 +69,58 @@ void sieve_binary_commit(struct sieve_binary *binary) /* Extension handling */ -static int sieve_binary_link_extension(struct sieve_binary *binary, const struct sieve_extension *extension) +int sieve_binary_extension_link + (struct sieve_binary *sbin, int ext_id) { - array_append(&(binary->extensions), &extension, 1); + int index = array_count(&sbin->extensions); + const struct sieve_extension *ext = sieve_extension_get_by_id(ext_id); + struct sieve_binary_extension *bext; + + if ( ext != NULL ) { + bext = p_new(sbin->pool, struct sieve_binary_extension, 1); + bext->index = index; + bext->ext_id = ext_id; + bext->extension = ext; - return array_count(&(binary->extensions)) - 1; -} - -const struct sieve_extension *sieve_binary_get_extension(struct sieve_binary *binary, unsigned int index) -{ - const struct sieve_extension * const *ext; + array_idx_set(&sbin->extensions, (unsigned int) index, &bext); + array_idx_set(&sbin->extension_index, (unsigned int) ext_id, &bext); - if ( array_count(&(binary->extensions)) > index ) { - ext = array_idx(&(binary->extensions), index); - return *ext; + return index; } - return NULL; + return -1; } -int sieve_binary_register_extension - (struct sieve_binary *sbin, const struct sieve_extension *extension) +const struct sieve_extension *sieve_binary_extension_get_by_index + (struct sieve_binary *sbin, int index, int *ext_id) { - struct sieve_extension_registration *reg; + struct sieve_binary_extension * const *ext; - reg = p_new(sbin->pool, struct sieve_extension_registration, 1); - reg->extension = extension; - reg->opcode = sieve_binary_link_extension(sbin, extension); + if ( index < (int) array_count(&sbin->extensions) ) { + ext = array_idx(&sbin->extensions, (unsigned int) index); + + if ( ext_id != NULL ) *ext_id = (*ext)->ext_id; + + return (*ext)->extension; + } - hash_insert(sbin->extension_index, (void *) extension, (void *) reg); + if ( ext_id != NULL ) *ext_id = -1; - return reg->opcode; + return NULL; } -int sieve_binary_get_extension_index - (struct sieve_binary *sbin, const struct sieve_extension *extension) +int sieve_binary_extension_get_index + (struct sieve_binary *sbin, int ext_id) { - struct sieve_extension_registration *reg = - (struct sieve_extension_registration *) hash_lookup(sbin->extension_index, extension); - - if ( reg == NULL ) - return -1; - - return reg->opcode; + struct sieve_binary_extension * const *ext; + + if ( ext_id < (int) array_count(&sbin->extension_index) ) { + ext = array_idx(&sbin->extension_index, (unsigned int) ext_id); + + return (*ext)->index; + } + + return -1; } /* diff --git a/src/lib-sieve/sieve-binary.h b/src/lib-sieve/sieve-binary.h index 7ddbc6c70ce9d61a91a771f6e5ca2d844550d915..fcea7fe2b3edf6dd6fd295f3fbe154361fd203ec 100644 --- a/src/lib-sieve/sieve-binary.h +++ b/src/lib-sieve/sieve-binary.h @@ -18,13 +18,13 @@ void sieve_binary_commit(struct sieve_binary *binary); * Extension handling */ -int sieve_binary_register_extension - (struct sieve_binary *sbin, const struct sieve_extension *extension); -const struct sieve_extension *sieve_binary_get_extension - (struct sieve_binary *binary, unsigned int index); -int sieve_binary_get_extension_index - (struct sieve_binary *sbin, const struct sieve_extension *extension); - +int sieve_binary_extension_link + (struct sieve_binary *sbin, int ext_id); +const struct sieve_extension *sieve_binary_extension_get_by_index + (struct sieve_binary *sbin, int index, int *ext_id); +int sieve_binary_extension_get_index + (struct sieve_binary *sbin, int ext_id); + /* * Code emission */ diff --git a/src/lib-sieve/sieve-code.c b/src/lib-sieve/sieve-code.c index 9e2efba0ee5136a48468ec6f909ad856e7f67d8e..4cc5eecce1a860199c0cc4f4e30f6c0262e18682 100644 --- a/src/lib-sieve/sieve-code.c +++ b/src/lib-sieve/sieve-code.c @@ -109,8 +109,10 @@ const struct sieve_operand *sieve_operand_read else return NULL; } else { + int ext_id = -1; const struct sieve_extension *ext = - sieve_binary_get_extension(sbin, operand - SIEVE_OPERAND_EXT_OFFSET); + sieve_binary_extension_get_by_index + (sbin, operand - SIEVE_OPERAND_EXT_OFFSET, &ext_id); if ( ext != NULL ) return ext->operand; @@ -554,10 +556,10 @@ inline sieve_size_t sieve_operation_emit_code } inline sieve_size_t sieve_operation_emit_code_ext - (struct sieve_binary *sbin, const struct sieve_extension *extension) + (struct sieve_binary *sbin, int ext_id) { unsigned char op = SIEVE_OPCODE_EXT_OFFSET + - sieve_binary_get_extension_index(sbin, extension); + sieve_binary_extension_get_index(sbin, ext_id); return sieve_binary_emit_byte(sbin, op); } @@ -574,8 +576,10 @@ const struct sieve_opcode *sieve_operation_read else return NULL; } else { + int ext_id = -1; const struct sieve_extension *ext = - sieve_binary_get_extension(sbin, opcode - SIEVE_OPCODE_EXT_OFFSET); + sieve_binary_extension_get_by_index + (sbin, opcode - SIEVE_OPCODE_EXT_OFFSET, &ext_id); if ( ext != NULL ) return ext->opcode; diff --git a/src/lib-sieve/sieve-code.h b/src/lib-sieve/sieve-code.h index e8a50bea40dcc4673d9ea80c55008befc9f17dd3..624aec2878ec7fdeab5476d610c4fb6130d1943c 100644 --- a/src/lib-sieve/sieve-code.h +++ b/src/lib-sieve/sieve-code.h @@ -57,12 +57,12 @@ struct sieve_opr_stringlist_interface { enum sieve_core_operand { SIEVE_OPERAND_OPTIONAL, - SIEVE_OPERAND_NUMBER, - SIEVE_OPERAND_STRING, - SIEVE_OPERAND_STRING_LIST, - SIEVE_OPERAND_COMPARATOR, - SIEVE_OPERAND_MATCH_TYPE, - SIEVE_OPERAND_ADDR_PART + SIEVE_OPERAND_NUMBER, + SIEVE_OPERAND_STRING, + SIEVE_OPERAND_STRING_LIST, + SIEVE_OPERAND_COMPARATOR, + SIEVE_OPERAND_MATCH_TYPE, + SIEVE_OPERAND_ADDRESS_PART }; extern const struct sieve_operand *sieve_operands[]; @@ -125,7 +125,7 @@ extern const unsigned int sieve_opcode_count; inline sieve_size_t sieve_operation_emit_code (struct sieve_binary *sbin, int opcode); inline sieve_size_t sieve_operation_emit_code_ext - (struct sieve_binary *sbin, const struct sieve_extension *extension); + (struct sieve_binary *sbin, int ext_id); const struct sieve_opcode *sieve_operation_read (struct sieve_binary *sbin, sieve_size_t *address); diff --git a/src/lib-sieve/sieve-comparators.c b/src/lib-sieve/sieve-comparators.c index fd93cb72e20ccee037e4fd80eca6dbbd0b7ef591..3847df7f2fcac40699af2083860922e0ae271495 100644 --- a/src/lib-sieve/sieve-comparators.c +++ b/src/lib-sieve/sieve-comparators.c @@ -2,7 +2,10 @@ #include "lib.h" #include "compat.h" +#include "hash.h" +#include "array.h" +#include "sieve-extensions.h" #include "sieve-code.h" #include "sieve-binary.h" #include "sieve-validator.h" @@ -17,16 +20,143 @@ * Predeclarations */ -static struct sieve_interpreter_registry *cmp_registry = NULL; +extern const struct sieve_comparator *sieve_core_comparators[]; +extern const unsigned int sieve_core_comparators_count; static void opr_comparator_emit (struct sieve_binary *sbin, unsigned int code); static void opr_comparator_emit_ext - (struct sieve_binary *sbin, const struct sieve_extension *ext); + (struct sieve_binary *sbin, int ext_id); +static int cmp_i_octet_compare + (const void *val1, size_t val1_size, const void *val2, size_t val2_size); +static int cmp_i_ascii_casemap_compare + (const void *val1, size_t val1_size, const void *val2, size_t val2_size); -static int cmp_i_octet_compare(const void *val1, size_t val1_size, const void *val2, size_t val2_size); -static int cmp_i_ascii_casemap_compare(const void *val1, size_t val1_size, const void *val2, size_t val2_size); +/* + * Comparator 'extension' + */ + +static int ext_my_id = -1; + +static bool cmp_extension_load(int ext_id); +static bool cmp_validator_load(struct sieve_validator *validator); +static bool cmp_interpreter_load(struct sieve_interpreter *interp); + +const struct sieve_extension comparator_extension = { + "@comparator", + cmp_extension_load, + cmp_validator_load, + NULL, + cmp_interpreter_load, + NULL, + NULL +}; + +static bool cmp_extension_load(int ext_id) +{ + ext_my_id = ext_id; + return TRUE; +} + +/* + * Validator context: + * name-based comparator registry. + */ + +struct cmp_validator_context { + struct hash_table *comparators; +}; + +static inline struct cmp_validator_context * + get_validator_context(struct sieve_validator *validator) +{ + return (struct cmp_validator_context *) + sieve_validator_extension_get_context(validator, ext_my_id); +} + +void sieve_comparator_register + (struct sieve_validator *validator, const struct sieve_comparator *cmp) +{ + struct cmp_validator_context *ctx = get_validator_context(validator); + + hash_insert(ctx->comparators, (void *) cmp->identifier, (void *) cmp); +} + +const struct sieve_comparator *sieve_comparator_find + (struct sieve_validator *validator, const char *cmp_name) +{ + struct cmp_validator_context *ctx = get_validator_context(validator); + + return (const struct sieve_comparator *) + hash_lookup(ctx->comparators, cmp_name); +} + +static bool cmp_validator_load(struct sieve_validator *validator) +{ + unsigned int i; + pool_t pool = sieve_validator_pool(validator); + + struct cmp_validator_context *ctx = p_new(pool, struct cmp_validator_context, 1); + + /* Setup comparator registry */ + ctx->comparators = hash_create(pool, pool, 0, str_hash, (hash_cmp_callback_t *)strcmp); + + /* Register core comparators */ + for ( i = 0; i < sieve_core_comparators_count; i++ ) { + const struct sieve_comparator *cmp = sieve_core_comparators[i]; + + hash_insert(ctx->comparators, (void *) cmp->identifier, (void *) cmp); + } + + sieve_validator_extension_set_context(validator, ext_my_id, ctx); + + return TRUE; +} + +/* + * Interpreter context: + */ + +struct cmp_interpreter_context { + ARRAY_DEFINE(cmp_extensions, + const struct sieve_comparator_extension *); +}; + +static inline struct cmp_interpreter_context * + get_interpreter_context(struct sieve_interpreter *interpreter) +{ + return (struct cmp_interpreter_context *) + sieve_interpreter_extension_get_context(interpreter, ext_my_id); +} + +static const struct sieve_comparator_extension *sieve_comparator_extension_get + (struct sieve_interpreter *interpreter, int ext_id) +{ + struct cmp_interpreter_context *ctx = get_interpreter_context(interpreter); + + if ( ext_id > 0 && ext_id < (int) array_count(&ctx->cmp_extensions) ) { + return (const struct sieve_comparator_extension *) + array_idx(&ctx->cmp_extensions, (unsigned int) ext_id); + } + + return NULL; +} + +static bool cmp_interpreter_load(struct sieve_interpreter *interpreter) +{ + pool_t pool = sieve_interpreter_pool(interpreter); + + struct cmp_interpreter_context *ctx = + p_new(pool, struct cmp_interpreter_context, 1); + + /* Setup comparator registry */ + p_array_init(&ctx->cmp_extensions, default_pool, 4); + + sieve_interpreter_extension_set_context(interpreter, ext_my_id, ctx); + + return TRUE; +} /* * Comparator operand @@ -69,7 +199,7 @@ static bool tag_comparator_validate } /* Get comparator from registry */ - cmp = sieve_validator_find_comparator(validator, sieve_ast_argument_strc(*arg)); + cmp = sieve_comparator_find(validator, sieve_ast_argument_strc(*arg)); if ( cmp == NULL ) { sieve_command_validate_error(validator, cmd, @@ -78,15 +208,22 @@ static bool tag_comparator_validate return FALSE; } - /* String argument not needed during code generation, so delete it */ + /* String argument not needed during code generation, so delete it from argument list */ *arg = sieve_ast_arguments_delete(*arg, 1); - + /* Store comparator in context */ tag->context = (void *) cmp; return TRUE; } +void sieve_comparators_link_tag + (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, + unsigned int id_code) +{ + sieve_validator_register_tag(validator, cmd_reg, &comparator_tag, id_code); +} + /* Code generation */ static void opr_comparator_emit @@ -97,10 +234,10 @@ static void opr_comparator_emit } static void opr_comparator_emit_ext - (struct sieve_binary *sbin, const struct sieve_extension *ext) + (struct sieve_binary *sbin, int ext_id) { unsigned char cmp_code = SIEVE_COMPARATOR_CUSTOM + - sieve_binary_get_extension_index(sbin, ext); + sieve_binary_extension_get_index(sbin, ext_id); (void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_COMPARATOR); (void) sieve_binary_emit_byte(sbin, cmp_code); @@ -122,13 +259,15 @@ const struct sieve_comparator *sieve_opr_comparator_read else return NULL; } else { + /*int ext_id = -1; const struct sieve_extension *ext = - sieve_binary_get_extension(sbin, cmp_code - SIEVE_COMPARATOR_CUSTOM); + sieve_binary_extension_get_by_index + (sbin, cmp_code - SIEVE_COMPARATOR_CUSTOM, &ext_id); if ( ext != NULL ) - return (const struct sieve_comparator *) - sieve_interpreter_registry_get(cmp_registry, ext); - else + struct sieve_comparator_extension *cext = + sieve_comparator_extension_get(cmp_registry, ext); + else*/ return NULL; } } @@ -162,7 +301,7 @@ static bool tag_comparator_generate else return FALSE; } else { - opr_comparator_emit_ext(sbin, cmp->extension); + //opr_comparator_emit_ext(sbin, cmp->ext); } *arg = sieve_ast_argument_next(*arg); @@ -195,8 +334,8 @@ const struct sieve_comparator *sieve_core_comparators[] = { const unsigned int sieve_core_comparators_count = (sizeof(sieve_core_comparators) / sizeof(sieve_core_comparators[0])); - -static int cmp_i_octet_compare(const void *val1, size_t val1_size, const void *val2, size_t val2_size) +static int cmp_i_octet_compare(const void *val1, size_t val1_size, + const void *val2, size_t val2_size) { int result; @@ -242,13 +381,3 @@ static int cmp_i_ascii_casemap_compare(const void *val1, size_t val1_size, const return result; } -/* - * Registry - */ - -void sieve_comparators_init_registry(struct sieve_interpreter *interp) -{ - cmp_registry = sieve_interpreter_registry_init(interp, "comparators"); -} - - diff --git a/src/lib-sieve/sieve-comparators.h b/src/lib-sieve/sieve-comparators.h index 77da4c23cb344b5f3ea21d5ca1afe654f4851a6e..e2d8026dd67b9a87d3cabdfdde1c7fdfeabba2c1 100644 --- a/src/lib-sieve/sieve-comparators.h +++ b/src/lib-sieve/sieve-comparators.h @@ -16,25 +16,32 @@ struct sieve_comparator { /* Equality, ordering, prefix and substring match */ /* ( output similar to strncmp ) */ - int (*compare)(const void *val1, size_t val1_size, const void *val2, size_t val2_size); + int (*compare)(const void *val1, size_t val1_size, + const void *val2, size_t val2_size); }; -extern const struct sieve_argument comparator_tag; +struct sieve_comparator_extension { + const struct sieve_comparator *comparator; + const struct sieve_comparator *(*read) + (struct sieve_binary *sbin, sieve_size_t *address); +}; +void sieve_comparators_link_tag + (struct sieve_validator *validator, + struct sieve_command_registration *cmd_reg, + unsigned int id_code); const struct sieve_comparator i_octet_comparator; const struct sieve_comparator i_ascii_casemap_comparator; -extern const struct sieve_comparator *sieve_core_comparators[]; -extern const unsigned int sieve_core_comparators_count; +void sieve_comparator_register + (struct sieve_validator *validator, const struct sieve_comparator *cmp); +const struct sieve_comparator *sieve_comparator_find + (struct sieve_validator *validator, const char *cmp_name); const struct sieve_comparator *sieve_opr_comparator_read (struct sieve_binary *sbin, sieve_size_t *address); bool sieve_opr_comparator_dump (struct sieve_binary *sbin, sieve_size_t *address); -void sieve_comparators_init_registry(struct sieve_interpreter *interp); - - - #endif /* __SIEVE_COMPARATORS_H */ diff --git a/src/lib-sieve/sieve-extensions.c b/src/lib-sieve/sieve-extensions.c index 68d53d1bd4c189d13afed53d8acd77b902c0faad..7b7580c4ff4d0f31c7165778d3b73214caaec2ae 100644 --- a/src/lib-sieve/sieve-extensions.c +++ b/src/lib-sieve/sieve-extensions.c @@ -1,35 +1,162 @@ #include "lib.h" +#include "mempool.h" #include "hash.h" +#include "array.h" #include "sieve-extensions.h" +/* Static pre-declarations */ + +static void sieve_extensions_init_registry(void); +static void sieve_extensions_deinit_registry(void); + +/* Core extensions */ + +extern const struct sieve_extension comparator_extension; +extern const struct sieve_extension address_part_extension; + +/* Base extensions */ + extern const struct sieve_extension fileinto_extension; extern const struct sieve_extension reject_extension; extern const struct sieve_extension envelope_extension; /* Plugins (FIXME: make this dynamic) */ + extern const struct sieve_extension vacation_extension; const struct sieve_extension *sieve_core_extensions[] = { + &comparator_extension, &address_part_extension, &fileinto_extension, &reject_extension, &envelope_extension, &vacation_extension }; const unsigned int sieve_core_extensions_count = (sizeof(sieve_core_extensions) / sizeof(sieve_core_extensions[0])); -const struct sieve_extension *sieve_extension_acquire(const char *extension) { +/* Extension state */ + +bool sieve_extensions_init(const char *sieve_plugins ATTR_UNUSED) +{ unsigned int i; - /* First try to acquire one of the compiled-in extensions */ + sieve_extensions_init_registry(); + + /* Pre-load core extensions */ for ( i = 0; i < sieve_core_extensions_count; i++ ) { - if ( strcasecmp(extension, sieve_core_extensions[i]->name) == 0 ) - return sieve_core_extensions[i]; + int ext_id = + sieve_extension_register(sieve_core_extensions[i]); + + if ( sieve_core_extensions[i]->load != NULL && + !sieve_core_extensions[i]->load(ext_id) ) { + i_error("sieve: failed to load '%s' extension support.", + sieve_core_extensions[i]->name); + return FALSE; + } } - /* Try to load a plugin */ + /* More extensions can be added through plugins */ + /* FIXME */ + + return TRUE; +} + +void sieve_extensions_deinit(void) +{ + sieve_extensions_deinit_registry(); +} + +/* Extension registry */ + +struct sieve_extension_registration { + const struct sieve_extension *extension; + int id; +}; + +static ARRAY_DEFINE(extensions, const struct sieve_extension *); +static struct hash_table *extension_index; + +static void sieve_extensions_init_registry(void) +{ + p_array_init(&extensions, default_pool, 4); + extension_index = hash_create(default_pool, default_pool, 0, NULL, NULL); +} + +int sieve_extension_register(const struct sieve_extension *extension) +{ + int ext_id = array_count(&extensions); + struct sieve_extension_registration *ereg; + + array_append(&extensions, &extension, 1); - // FIXME + ereg = p_new(default_pool, struct sieve_extension_registration, 1); + ereg->extension = extension; + ereg->id = ext_id; + + hash_insert(extension_index, (void *) extension->name, (void *) ereg); + + return ext_id; +} + +int sieve_extensions_get_count(void) +{ + return array_count(&extensions); +} + +const struct sieve_extension *sieve_extension_get_by_id(unsigned int ext_id) +{ + const struct sieve_extension * const *ext; + + if ( ext_id < array_count(&extensions) ) { + ext = array_idx(&extensions, ext_id); + return *ext; + } - /* Not found */ return NULL; } + +int sieve_extension_get_by_name(const char *name, const struct sieve_extension **ext) +{ + struct sieve_extension_registration *ereg = + (struct sieve_extension_registration *) hash_lookup(extension_index, name); + + *ext = NULL; + + if ( ereg == NULL ) + return -1; + + if ( *(ereg->extension->name) == '@' ) + return -1; + + *ext = ereg->extension; + + return ereg->id; +} + +int sieve_extension_get_id(const struct sieve_extension *extension) +{ + struct sieve_extension_registration *ereg = + (struct sieve_extension_registration *) + hash_lookup(extension_index, extension->name); + + if ( ereg == NULL ) + return -1; + + return ereg->id; +} + +static void sieve_extensions_deinit_registry() +{ + struct hash_iterate_context *itx = + hash_iterate_init(extension_index); + void *key; + void *ereg; + + while ( hash_iterate(itx, &key, &ereg) ) { + p_free(default_pool, ereg); + } + + hash_iterate_deinit(&itx); + + array_free(&extensions); + hash_destroy(&extension_index); +} diff --git a/src/lib-sieve/sieve-extensions.h b/src/lib-sieve/sieve-extensions.h index 343b2efc78f1b93caae723eae9fd46581fef1956..0f1d27fe2a786607905927e1ac7057f51ca64279 100644 --- a/src/lib-sieve/sieve-extensions.h +++ b/src/lib-sieve/sieve-extensions.h @@ -7,6 +7,8 @@ struct sieve_extension { const char *name; + bool (*load)(int ext_id); + bool (*validator_load)(struct sieve_validator *validator); bool (*generator_load)(struct sieve_generator *generator); bool (*interpreter_load)(struct sieve_interpreter *interpreter); @@ -17,4 +19,17 @@ struct sieve_extension { const struct sieve_extension *sieve_extension_acquire(const char *extension); +/* Extensions state */ + +bool sieve_extensions_init(const char *sieve_plugins ATTR_UNUSED); +void sieve_extensions_deinit(void); + +/* Extension registry */ + +int sieve_extension_register(const struct sieve_extension *extension); +int sieve_extensions_get_count(void); +const struct sieve_extension *sieve_extension_get_by_id(unsigned int ext_id); +int sieve_extension_get_by_name(const char *name, const struct sieve_extension **ext); +int sieve_extension_get_id(const struct sieve_extension *extension); + #endif /* __SIEVE_EXTENSIONS_H */ diff --git a/src/lib-sieve/sieve-generator.c b/src/lib-sieve/sieve-generator.c index e23f5606cddee6cca71979e51a00d1863bda4518..5594e425dadcbe2d1e0971274439938cbfd42496 100644 --- a/src/lib-sieve/sieve-generator.c +++ b/src/lib-sieve/sieve-generator.c @@ -71,10 +71,10 @@ void sieve_generator_free(struct sieve_generator *generator) pool_unref(&(generator->pool)); } -inline void sieve_generator_register_extension - (struct sieve_generator *gentr, const struct sieve_extension *ext) +inline void sieve_generator_link_extension + (struct sieve_generator *generator, int ext_id) { - (void)sieve_binary_register_extension(gentr->binary, ext); + (void)sieve_binary_extension_link(generator->binary, ext_id); } /* Binary access */ @@ -92,12 +92,11 @@ inline sieve_size_t sieve_generator_emit_opcode } inline sieve_size_t sieve_generator_emit_opcode_ext - (struct sieve_generator *gentr, const struct sieve_extension *ext) + (struct sieve_generator *gentr, int ext_id) { - return sieve_operation_emit_code_ext(gentr->binary, ext); + return sieve_operation_emit_code_ext(gentr->binary, ext_id); } - /* Generator functions */ bool sieve_generate_arguments(struct sieve_generator *generator, diff --git a/src/lib-sieve/sieve-generator.h b/src/lib-sieve/sieve-generator.h index 1fe0e0d39e51d2f486d59ca17bfb3c3b2ec4bd04..8aaa894bbc89be7ddd1cbb3e3a32c8b91ed86446 100644 --- a/src/lib-sieve/sieve-generator.h +++ b/src/lib-sieve/sieve-generator.h @@ -9,8 +9,8 @@ struct sieve_generator; struct sieve_generator *sieve_generator_create(struct sieve_ast *ast); void sieve_generator_free(struct sieve_generator *generator); -inline void sieve_generator_register_extension - (struct sieve_generator *gentr, const struct sieve_extension *ext); +inline void sieve_generator_link_extension + (struct sieve_generator *generator, int ext_id); /* Jump list */ @@ -35,7 +35,7 @@ inline struct sieve_binary *sieve_generator_get_binary inline sieve_size_t sieve_generator_emit_opcode (struct sieve_generator *gentr, int opcode); inline sieve_size_t sieve_generator_emit_opcode_ext - (struct sieve_generator *gentr, const struct sieve_extension *extension); + (struct sieve_generator *gentr, int ext_id); /* Offset emission */ diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c index 21596e8f44056745bad72a3e4de95a3cb1c5f30c..a23d67f84099b74afab4f3b8530eeb572c8d4409 100644 --- a/src/lib-sieve/sieve-interpreter.c +++ b/src/lib-sieve/sieve-interpreter.c @@ -7,10 +7,12 @@ #include "hash.h" #include "mail-storage.h" +#include "sieve-extensions.h" #include "sieve-commands-private.h" #include "sieve-generator.h" #include "sieve-binary.h" #include "sieve-result.h" +#include "sieve-comparators.h" #include "sieve-interpreter.h" @@ -20,7 +22,7 @@ struct sieve_interpreter { struct sieve_binary *binary; /* Object registries */ - struct hash_table *registries; + ARRAY_DEFINE(ext_contexts, void); /* Execution status */ sieve_size_t pc; @@ -46,10 +48,8 @@ struct sieve_interpreter *sieve_interpreter_create(struct sieve_binary *binary) interp->pc = 0; - interp->registries = hash_create(pool, pool, 0, NULL, NULL); - - /* Init core functionalities */ - sieve_comparators_init_registry(interp); + array_create(&interp->ext_contexts, pool, sizeof(void *), + sieve_extensions_get_count()); return interp; } @@ -60,55 +60,27 @@ void sieve_interpreter_free(struct sieve_interpreter *interpreter) pool_unref(&(interpreter->pool)); } -/* Object registry */ - -struct sieve_interpreter_registry { - struct sieve_interpreter *interpreter; - const char *name; - ARRAY_DEFINE(registered, void); -}; - -struct sieve_interpreter_registry * - sieve_interpreter_registry_init(struct sieve_interpreter *interp, const char *name) +inline pool_t sieve_interpreter_pool(struct sieve_interpreter *interp) { - struct sieve_interpreter_registry *reg = (struct sieve_interpreter_registry *) - hash_lookup(interp->registries, name); - - if ( reg == NULL ) { - reg = p_new(interp->pool, struct sieve_interpreter_registry, 1); - reg->interpreter = interp; - reg->name = name; - array_create(®->registered, interp->pool, sizeof(void *), 5); - - hash_insert(interp->registries, (void *) name, (void *) reg); - } - - return reg; + return interp->pool; } -const void *sieve_interpreter_registry_get - (struct sieve_interpreter_registry *reg, const struct sieve_extension *ext) + +/* Extension support */ + +inline void sieve_interpreter_extension_set_context + (struct sieve_interpreter *interpreter, int ext_id, void *context) { - const void *result; - int index = sieve_binary_get_extension_index(reg->interpreter->binary, ext); - - if ( index < 0 || index > (int) array_count(®->registered) ) - return NULL; - - result = array_idx(®->registered, (unsigned int) index); - - return result; + array_idx_set(&interpreter->ext_contexts, (unsigned int) ext_id, context); } -void sieve_interpreter_registry_set - (struct sieve_interpreter_registry *reg, const struct sieve_extension *ext, const void *obj) +inline const void *sieve_interpreter_extension_get_context + (struct sieve_interpreter *interpreter, int ext_id) { - int index = sieve_binary_get_extension_index(reg->interpreter->binary, ext); - - if ( index < 0 || index > (int) array_count(®->registered) ) - return; + if ( ext_id < 0 || ext_id > (int) array_count(&interpreter->ext_contexts) ) + return NULL; - array_idx_set(®->registered, (unsigned int) index, obj); + return array_idx(&interpreter->ext_contexts, (unsigned int) ext_id); } diff --git a/src/lib-sieve/sieve-interpreter.h b/src/lib-sieve/sieve-interpreter.h index d89e85f5e319d1f7cdadf5658813dab43ae7b3ef..0898a708766fc6585f443fd9dcfc6059f867fdae 100644 --- a/src/lib-sieve/sieve-interpreter.h +++ b/src/lib-sieve/sieve-interpreter.h @@ -12,6 +12,7 @@ struct sieve_interpreter; struct sieve_interpreter *sieve_interpreter_create(struct sieve_binary *binary); void sieve_interpreter_free(struct sieve_interpreter *interpreter); +inline pool_t sieve_interpreter_pool(struct sieve_interpreter *interp); inline void sieve_interpreter_reset (struct sieve_interpreter *interpreter); @@ -28,16 +29,12 @@ inline bool sieve_interpreter_get_test_result inline struct sieve_binary *sieve_interpreter_get_binary (struct sieve_interpreter *interp); -/* Object registry */ +/* Extension support */ -struct sieve_interpreter_registry; - -struct sieve_interpreter_registry * - sieve_interpreter_registry_init(struct sieve_interpreter *interp, const char *name); -const void *sieve_interpreter_registry_get - (struct sieve_interpreter_registry *reg, const struct sieve_extension *ext); -void sieve_interpreter_registry_set - (struct sieve_interpreter_registry *reg, const struct sieve_extension *ext, const void *obj); +inline void sieve_interpreter_extension_set_context + (struct sieve_interpreter *interpreter, int ext_id, void *context); +inline const void *sieve_interpreter_extension_get_context + (struct sieve_interpreter *interpreter, int ext_id); /* Opcodes and operands */ diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c index 26f6ac5240a6a5be293c6d9ee31e513700245985..4599de460588f1b967bcbce5f48f5febd02255e9 100644 --- a/src/lib-sieve/sieve-validator.c +++ b/src/lib-sieve/sieve-validator.c @@ -7,7 +7,9 @@ #include "sieve-commands-private.h" #include "sieve-validator.h" #include "sieve-extensions.h" + #include "sieve-comparators.h" +#include "sieve-address-parts.h" /* Context/Semantics checker implementation */ @@ -19,7 +21,8 @@ struct sieve_validator { /* Registries */ struct hash_table *commands; - struct hash_table *comparators; + + ARRAY_DEFINE(ext_contexts, void); }; /* Predeclared statics */ @@ -50,6 +53,9 @@ void sieve_validator_error(struct sieve_validator *validator, struct sieve_ast_n va_end(args); } +extern struct sieve_extension comparator_extension; +extern struct sieve_extension address_part_extension; + struct sieve_validator *sieve_validator_create(struct sieve_ast *ast, struct sieve_error_handler *ehandler) { pool_t pool; @@ -68,24 +74,29 @@ struct sieve_validator *sieve_validator_create(struct sieve_ast *ast, struct sie (pool, pool, 0, str_hash, (hash_cmp_callback_t *)strcmp); sieve_validator_register_core_commands(validator); sieve_validator_register_core_tests(validator); - - /* Setup comparator registry */ - validator->comparators = hash_create - (pool, pool, 0, str_hash, (hash_cmp_callback_t *)strcmp); - sieve_validator_register_core_comparators(validator); - + + array_create(&validator->ext_contexts, pool, sizeof(void *), + sieve_extensions_get_count()); + + (void)comparator_extension.validator_load(validator); + (void)address_part_extension.validator_load(validator); + return validator; } void sieve_validator_free(struct sieve_validator *validator) { hash_destroy(&validator->commands); - hash_destroy(&validator->comparators); sieve_ast_unref(&validator->ast); pool_unref(&(validator->pool)); } +inline pool_t sieve_validator_pool(struct sieve_validator *validator) +{ + return validator->pool; +} + /* Command registry */ struct sieve_command_registration { @@ -234,57 +245,40 @@ static const struct sieve_argument *sieve_validator_find_tag /* Extension support */ -const struct sieve_extension *sieve_validator_load_extension - (struct sieve_validator *validator, struct sieve_command_context *cmd, const char *extension) +int sieve_validator_extension_load + (struct sieve_validator *validator, struct sieve_command_context *cmd, + const char *ext_name) { - const struct sieve_extension *ext = sieve_extension_acquire(extension); + const struct sieve_extension *ext; + int ext_id = sieve_extension_get_by_name(ext_name, &ext); - if ( ext == NULL ) { + if ( ext_id < 0 ) { sieve_command_validate_error(validator, cmd, - "unsupported sieve capability '%s'", extension); - return NULL; + "unsupported sieve capability '%s'", ext_name); + return -1; } if ( ext->validator_load != NULL && !ext->validator_load(validator) ) { sieve_command_validate_error(validator, cmd, - "failed to load sieve capability '%s'", extension); - return NULL; + "failed to load sieve capability '%s'", ext->name); + return -1; } - i_info("loaded extension '%s'", extension); - return ext; + i_info("loaded extension '%s'", ext->name); + return ext_id; } -/* Comparator registry */ - -void sieve_validator_register_comparator - (struct sieve_validator *validator, const struct sieve_comparator *cmp) +inline void sieve_validator_extension_set_context(struct sieve_validator *validator, int ext_id, void *context) { - hash_insert(validator->comparators, (void *) cmp->identifier, (void *) cmp); + array_idx_set(&validator->ext_contexts, (unsigned int) ext_id, context); } -const struct sieve_comparator *sieve_validator_find_comparator - (struct sieve_validator *validator, const char *comparator) +inline const void *sieve_validator_extension_get_context(struct sieve_validator *validator, int ext_id) { - return (const struct sieve_comparator *) hash_lookup(validator->comparators, comparator); -} - -static void sieve_validator_register_core_comparators(struct sieve_validator *validator) -{ - unsigned int i; + if ( ext_id < 0 || ext_id > (int) array_count(&validator->ext_contexts) ) + return NULL; - for ( i = 0; i < sieve_core_comparators_count; i++ ) { - sieve_validator_register_comparator(validator, sieve_core_comparators[i]); - } -} - -/* Comparator validation */ - -void sieve_validator_link_comparator_tag - (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, - unsigned int id_code) -{ - sieve_validator_register_tag(validator, cmd_reg, &comparator_tag, id_code); + return array_idx(&validator->ext_contexts, (unsigned int) ext_id); } /* Match type validation */ @@ -320,39 +314,6 @@ void sieve_validator_link_match_type_tags sieve_validator_register_tag(validator, cmd_reg, &match_matches_tag, id_code); } -/* Address part validation */ - -static bool sieve_validate_address_part_tag - (struct sieve_validator *validator ATTR_UNUSED, - struct sieve_ast_argument **arg, - struct sieve_command_context *cmd ATTR_UNUSED) -{ - /* Syntax: - * ":localpart" / ":domain" / ":all" - */ - - /* Not implemented, so delete it */ - *arg = sieve_ast_arguments_delete(*arg, 1); - - return TRUE; -} - -static const struct sieve_argument address_localpart_tag = - { "localpart", sieve_validate_address_part_tag, NULL }; -static const struct sieve_argument address_domain_tag = - { "domain", sieve_validate_address_part_tag, NULL }; -static const struct sieve_argument address_all_tag = - { "all", sieve_validate_address_part_tag, NULL }; - -void sieve_validator_link_address_part_tags - (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, - unsigned int id_code) -{ - sieve_validator_register_tag(validator, cmd_reg, &address_localpart_tag, id_code); - sieve_validator_register_tag(validator, cmd_reg, &address_domain_tag, id_code); - sieve_validator_register_tag(validator, cmd_reg, &address_all_tag, id_code); -} - /* Tag Validation API */ /* Test validation API */ diff --git a/src/lib-sieve/sieve-validator.h b/src/lib-sieve/sieve-validator.h index 8103faaf3bc930bf49fcf8db13ebe90241d383a2..dab6892d53cea5ff865a71fc3c77618f4d11772f 100644 --- a/src/lib-sieve/sieve-validator.h +++ b/src/lib-sieve/sieve-validator.h @@ -3,7 +3,6 @@ #include "lib.h" -#include "sieve-comparators.h" #include "sieve-common.h" #include "sieve-error.h" @@ -12,6 +11,7 @@ struct sieve_command_registration; struct sieve_validator *sieve_validator_create(struct sieve_ast *ast, struct sieve_error_handler *ehandler); void sieve_validator_free(struct sieve_validator *validator); +inline pool_t sieve_validator_pool(struct sieve_validator *validator); bool sieve_validator_run(struct sieve_validator *validator); @@ -30,23 +30,11 @@ void sieve_validator_register_command void sieve_validator_register_tag (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, const struct sieve_argument *argument, unsigned int id_code); - -/* Comparator registration */ -void sieve_validator_register_comparator - (struct sieve_validator *validator, const struct sieve_comparator *cmp); -const struct sieve_comparator *sieve_validator_find_comparator - (struct sieve_validator *validator, const char *comparator); /* Special test arguments */ -void sieve_validator_link_comparator_tag - (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, - unsigned int id_code); void sieve_validator_link_match_type_tags (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, unsigned int id_code); -void sieve_validator_link_address_part_tags - (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, - unsigned int id_code); /* Argument validation */ bool sieve_validate_command_arguments @@ -62,7 +50,10 @@ bool sieve_validate_command_block(struct sieve_validator *validator, struct siev bool block_allowed, bool block_required); /* Extensions */ -const struct sieve_extension *sieve_validator_load_extension - (struct sieve_validator *validator, struct sieve_command_context *cmd, const char *extension); +int sieve_validator_extension_load + (struct sieve_validator *validator, struct sieve_command_context *cmd, + const char *ext_name); +inline void sieve_validator_extension_set_context(struct sieve_validator *validator, int ext_id, void *context); +inline const void *sieve_validator_extension_get_context(struct sieve_validator *validator, int ext_id); #endif /* __SIEVE_VALIDATOR_H__ */ diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c index 76473cda093dab8f67665d4c957930b1a542c0cd..11fd336c1ed99aa60bb4300c01ddad5e0181d214 100644 --- a/src/lib-sieve/sieve.c +++ b/src/lib-sieve/sieve.c @@ -3,6 +3,7 @@ #include "istream.h" #include "buffer.h" +#include "sieve-extensions.h" #include "sieve-parser.h" #include "sieve-ast.h" #include "sieve-validator.h" @@ -18,6 +19,16 @@ #include <unistd.h> #include <stdio.h> +bool sieve_init(const char *plugins) +{ + return sieve_extensions_init(plugins); +} + +void sieve_deinit(void) +{ + sieve_extensions_deinit(); +} + static struct sieve_ast *sieve_parse(int fd, struct sieve_error_handler *ehandler) { struct sieve_parser *parser; diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h index 42fab8b1dd7b373d55817b3bee306138644e9c74..049b8675d33f10e0841b1bd6924a55259b1a77b8 100644 --- a/src/lib-sieve/sieve.h +++ b/src/lib-sieve/sieve.h @@ -1,7 +1,12 @@ #ifndef __SIEVE_H #define __SIEVE_H -#include "sieve-binary.h" +#include "mail-storage.h" + +struct sieve_binary; + +bool sieve_init(const char *plugins); +void sieve_deinit(void); struct sieve_binary *sieve_compile(int fd); void sieve_dump(struct sieve_binary *binary); diff --git a/src/lib-sieve/tst-address.c b/src/lib-sieve/tst-address.c index c13ca9c6659307c5caece9adde2763cb523ad992..a767e73653733450440ed86f206ad8f0298c6d1b 100644 --- a/src/lib-sieve/tst-address.c +++ b/src/lib-sieve/tst-address.c @@ -2,6 +2,9 @@ #include "sieve-commands.h" #include "sieve-commands-private.h" + +#include "sieve-comparators.h" +#include "sieve-address-parts.h" #include "sieve-validator.h" #include "sieve-generator.h" #include "sieve-interpreter.h" @@ -30,8 +33,8 @@ enum tst_address_optional { bool tst_address_registered(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) { /* The order of these is not significant */ - sieve_validator_link_comparator_tag(validator, cmd_reg, OPT_COMPARATOR ); - sieve_validator_link_address_part_tags(validator, cmd_reg, OPT_ADDRESS_PART); + sieve_comparators_link_tag(validator, cmd_reg, OPT_COMPARATOR ); + sieve_address_parts_link_tags(validator, cmd_reg, OPT_ADDRESS_PART); sieve_validator_link_match_type_tags(validator, cmd_reg, OPT_MATCH_TYPE); return TRUE; diff --git a/src/lib-sieve/tst-header.c b/src/lib-sieve/tst-header.c index 78718568a16e309278ef56b2ee8f302051929a42..2146ae651a0f3b80f2f7c127fc1aa45117fd0c20 100644 --- a/src/lib-sieve/tst-header.c +++ b/src/lib-sieve/tst-header.c @@ -30,7 +30,7 @@ enum tst_header_optional { bool tst_header_registered(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) { /* The order of these is not significant */ - sieve_validator_link_comparator_tag(validator, cmd_reg, OPT_COMPARATOR); + sieve_comparators_link_tag(validator, cmd_reg, OPT_COMPARATOR); sieve_validator_link_match_type_tags(validator, cmd_reg, OPT_MATCH_TYPE); return TRUE; diff --git a/src/sieve-bin/sieve_test.c b/src/sieve-bin/sieve_test.c index e841bf319157c3e2558350c6711fc2e7d1a8a8f0..c8c57d3a8222d8c2494ae14824077a335cd500f8 100644 --- a/src/sieve-bin/sieve_test.c +++ b/src/sieve-bin/sieve_test.c @@ -164,7 +164,7 @@ int main(int argc, char **argv) exit(1); } - /* Compile sieve script */ + /* Compile sieve script */ if ( (fd = open(argv[1], O_RDONLY)) < 0 ) { perror("open()"); @@ -173,9 +173,16 @@ int main(int argc, char **argv) printf("Parsing sieve script '%s'...\n", argv[1]); - if ( (sbin = sieve_compile(fd)) == NULL ) + if ( !sieve_init("") ) { + printf("Failed to initialize sieve implementation\n"); exit(1); - + } + + if ( (sbin = sieve_compile(fd)) == NULL ) { + printf("Failed to compile sieve script\n"); + exit(1); + } + (void) sieve_dump(sbin); close(fd); @@ -225,7 +232,10 @@ int main(int argc, char **argv) /* */ i_stream_seek(input, 0); + sieve_test(sbin, mail); + + sieve_deinit(); //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 583ea07af253f6ebc27331c28d9b192511b17b4c..0292a34b8b8c3aab624e97c853877225ff56e948 100644 --- a/src/sieve-bin/sievec.c +++ b/src/sieve-bin/sievec.c @@ -34,10 +34,16 @@ int main(int argc, char **argv) { printf("Parsing sieve script '%s'...\n", argv[1]); - sbin = sieve_compile(fd); + if ( sieve_init("") ) { + sbin = sieve_compile(fd); - if ( sbin != NULL ) - (void) sieve_dump(sbin); + if ( sbin != NULL ) + (void) sieve_dump(sbin); + + sieve_deinit(); + } else { + printf("Failed to initialize sieve implementation."); + } close(fd); }