diff --git a/src/lib-sieve/plugins/include/cmd-include.c b/src/lib-sieve/plugins/include/cmd-include.c index 75c95e00b8f297765944807673aa29ae6e5c4d56..c9eca4896768de8b8fe0ad091592d8e9b7e49f01 100644 --- a/src/lib-sieve/plugins/include/cmd-include.c +++ b/src/lib-sieve/plugins/include/cmd-include.c @@ -68,7 +68,7 @@ const struct sieve_operation include_operation = { struct cmd_include_context_data { enum ext_include_script_location location; bool location_assigned; - const char *script_name; + struct sieve_script *script; }; /* Tags */ @@ -122,23 +122,34 @@ static bool cmd_include_validate_location_tag /* Command registration */ -enum cmd_include_optional { - OPT_END, - OPT_LOCATION -}; - static bool cmd_include_registered (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) { sieve_validator_register_tag - (validator, cmd_reg, &include_personal_tag, OPT_LOCATION); + (validator, cmd_reg, &include_personal_tag, 0); sieve_validator_register_tag - (validator, cmd_reg, &include_global_tag, OPT_LOCATION); + (validator, cmd_reg, &include_global_tag, 0); return TRUE; } -/* Command validation */ +/* + * Command validation + */ + +static void cmd_include_ast_destroy +(struct sieve_ast *ast ATTR_UNUSED, struct sieve_ast_node *node) +{ + struct sieve_command_context *cmd = node->context; + struct cmd_include_context_data *ctx_data = + (struct cmd_include_context_data *) cmd->data; + + sieve_script_unref(&ctx_data->script); +} + +static const struct sieve_ast_node_object cmd_include_ast_object = { + cmd_include_ast_destroy +}; static bool cmd_include_pre_validate (struct sieve_validator *validator ATTR_UNUSED, @@ -160,15 +171,28 @@ static bool cmd_include_validate(struct sieve_validator *validator, struct sieve_ast_argument *arg = cmd->first_positional; struct cmd_include_context_data *ctx_data = (struct cmd_include_context_data *) cmd->data; + struct sieve_script *script; + const char *script_path, *script_name; if ( !sieve_validate_positional_argument (validator, cmd, arg, "value", 1, SAAT_STRING) ) { return FALSE; } + + /* Find the script */ + script_name = sieve_ast_argument_strc(arg); + script_path = ext_include_get_script_path(ctx_data->location, script_name); + if ( script_path == NULL ) + return FALSE; - /* Get script path */ - - ctx_data->script_name = sieve_ast_argument_strc(arg); + /* Create script object */ + if ( (script = sieve_script_create(script_path, script_name, + sieve_validator_error_handler(validator), NULL)) == NULL ) + return FALSE; + + sieve_ast_link_object(cmd->ast_node, &cmd_include_ast_object); + ctx_data->script = script; + sieve_script_ref(script); arg = sieve_ast_arguments_detach(arg, 1); @@ -191,7 +215,7 @@ static bool cmd_include_generate * This yields the id of the binary block containing the compiled byte code. */ if ( !ext_include_generate_include - (gentr, cmd, ctx_data->location, ctx_data->script_name, &block_id) ) + (gentr, cmd, ctx_data->location, ctx_data->script, &block_id) ) return FALSE; sieve_generator_emit_operation_ext diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c index ddb874b6f9e5ce7f9e94ec250cad41dd4803f20f..67aedc331c87141770a06731ee73022e16233d7d 100644 --- a/src/lib-sieve/plugins/include/ext-include-common.c +++ b/src/lib-sieve/plugins/include/ext-include-common.c @@ -423,12 +423,10 @@ void ext_include_register_interpreter_context bool ext_include_generate_include (struct sieve_generator *gentr, struct sieve_command_context *cmd, - enum ext_include_script_location location, const char *script_name, + enum ext_include_script_location location, struct sieve_script *script, unsigned *blk_id_r) { bool result = TRUE; - const char *script_path; - struct sieve_script *script; struct sieve_ast *ast; struct sieve_binary *sbin = sieve_generator_get_binary(gentr); struct ext_include_binary_context *binctx; @@ -455,23 +453,12 @@ bool ext_include_generate_include return FALSE; } - /* Find the script */ - script_path = ext_include_get_script_path(location, script_name); - if ( script_path == NULL ) - return FALSE; - - /* Create script object */ - if ( (script = sieve_script_create(script_path, script_name, ehandler, NULL)) - == NULL ) - return FALSE; - /* Check for circular include */ pctx = ctx; while ( pctx != NULL ) { if ( sieve_script_equals(pctx->script, script) ) { sieve_command_generate_error(gentr, cmd, "circular include"); - sieve_script_unref(&script); return FALSE; } @@ -488,14 +475,13 @@ bool ext_include_generate_include /* Is the script already compiled into the current binary? */ if ( !ext_include_script_is_included(binctx, script, &inc_block_id) ) { + const char *script_name = sieve_script_name(script); + /* No, allocate a new block in the binary and mark the script as included. */ inc_block_id = sieve_binary_block_create(sbin); ext_include_script_include(binctx, script, location, inc_block_id); - /* Include list now holds a reference, so we can release it here safely */ - sieve_script_unref(&script); - /* Parse */ if ( (ast = sieve_parse(script, ehandler)) == NULL ) { sieve_command_generate_error(gentr, cmd, @@ -532,9 +518,7 @@ bool ext_include_generate_include /* Cleanup */ sieve_ast_unref(&ast); - } else - /* Yes, aready compiled and included, so release script object right away */ - sieve_script_unref(&script); + } if ( result ) *blk_id_r = inc_block_id; diff --git a/src/lib-sieve/plugins/include/ext-include-common.h b/src/lib-sieve/plugins/include/ext-include-common.h index 4c924a7486354c6ed0299555e7e95540bbd0b021..3440e209a0e5b7e5a8a8661bb633f7ebe78af96f 100644 --- a/src/lib-sieve/plugins/include/ext-include-common.h +++ b/src/lib-sieve/plugins/include/ext-include-common.h @@ -55,7 +55,7 @@ void ext_include_register_generator_context bool ext_include_generate_include (struct sieve_generator *gentr, struct sieve_command_context *cmd, - enum ext_include_script_location location, const char *script_name, + enum ext_include_script_location location, struct sieve_script *script, unsigned *blk_id_r); /* Binary */ diff --git a/src/lib-sieve/plugins/include/include-error.sieve b/src/lib-sieve/plugins/include/include-error.sieve new file mode 100644 index 0000000000000000000000000000000000000000..2da67e58152e1dad7724cf8fcff64f380d4204b5 --- /dev/null +++ b/src/lib-sieve/plugins/include/include-error.sieve @@ -0,0 +1,3 @@ +require "include"; + +include "frop.sieve"; diff --git a/src/lib-sieve/sieve-ast.c b/src/lib-sieve/sieve-ast.c index 0b02aacd12a282b62735db094225e7411a277217..5ab6edde176abd6f185c709d60d8a8f74fdefbdc 100644 --- a/src/lib-sieve/sieve-ast.c +++ b/src/lib-sieve/sieve-ast.c @@ -3,6 +3,7 @@ #include "lib.h" #include "str.h" #include "mempool.h" +#include "array.h" #include "sieve-script.h" @@ -14,6 +15,13 @@ static struct sieve_ast_node *sieve_ast_node_create (struct sieve_ast *ast, struct sieve_ast_node *parent, enum sieve_ast_type type, unsigned int source_line); +/* Links to other objects (notified if AST is destroyed) */ + +struct sieve_ast_node_link { + struct sieve_ast_node *node; + const struct sieve_ast_node_object *object; +}; + /* The AST object */ struct sieve_ast { @@ -23,6 +31,8 @@ struct sieve_ast { struct sieve_script *script; struct sieve_ast_node *root; + + ARRAY_DEFINE(node_links, struct sieve_ast_node_link); }; struct sieve_ast *sieve_ast_create(struct sieve_script *script) @@ -41,21 +51,46 @@ struct sieve_ast *sieve_ast_create(struct sieve_script *script) ast->root = sieve_ast_node_create(ast, NULL, SAT_ROOT, 0); ast->root->identifier = "ROOT"; + p_array_init(&ast->node_links, pool, 4); + return ast; } -void sieve_ast_ref(struct sieve_ast *ast) { +void sieve_ast_link_object +(struct sieve_ast_node *node, const struct sieve_ast_node_object *obj) +{ + struct sieve_ast_node_link link; + + link.node = node; + link.object = obj; + array_append(&node->ast->node_links, &link, 1); +} + +void sieve_ast_ref(struct sieve_ast *ast) +{ ast->refcount++; } -void sieve_ast_unref(struct sieve_ast **ast) { +void sieve_ast_unref(struct sieve_ast **ast) +{ + unsigned int i, lcount; + const struct sieve_ast_node_link *node_links; + i_assert((*ast)->refcount > 0); if (--(*ast)->refcount != 0) return; + /* Release script reference */ sieve_script_unref(&(*ast)->script); + /* Signal linked objects that the AST is being destroyed */ + node_links = array_get(&(*ast)->node_links, &lcount); + for ( i = 0; i < lcount; i++ ) { + node_links[i].object->ast_destroy(*ast, node_links[i].node); + } + + /* Destroy AST */ pool_unref(&(*ast)->pool); *ast = NULL; diff --git a/src/lib-sieve/sieve-ast.h b/src/lib-sieve/sieve-ast.h index 76262be5441d18c1ffc4fdd4a3c5cd831d505957..cfd638b2fa6299d055f49446e991213f5f1e3437 100644 --- a/src/lib-sieve/sieve-ast.h +++ b/src/lib-sieve/sieve-ast.h @@ -147,6 +147,10 @@ struct sieve_ast_node { struct sieve_command_context *context; }; +struct sieve_ast_node_object { + void (*ast_destroy)(struct sieve_ast *ast, struct sieve_ast_node *node); +}; + struct sieve_ast; /* sieve_ast */ @@ -154,6 +158,9 @@ struct sieve_ast *sieve_ast_create(struct sieve_script *script); void sieve_ast_ref(struct sieve_ast *ast); void sieve_ast_unref(struct sieve_ast **ast); +void sieve_ast_link_object + (struct sieve_ast_node *node, const struct sieve_ast_node_object *obj); + inline struct sieve_ast_node *sieve_ast_root(struct sieve_ast *ast); inline pool_t sieve_ast_pool(struct sieve_ast *ast); inline struct sieve_script *sieve_ast_script(struct sieve_ast *ast);