diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c index ca87b2e5788052d558226e79b7159fd85ec0ad9a..e21020495b38fee7c06be8630cc7cb1db6ca720d 100644 --- a/src/lib-sieve/plugins/include/ext-include-common.c +++ b/src/lib-sieve/plugins/include/ext-include-common.c @@ -8,7 +8,27 @@ #include "ext-include-common.h" -/* Generator context management */ +/* Generator context */ + +struct ext_include_generator_context { + unsigned int nesting_level; + struct sieve_script *script; + struct ext_include_main_context *main; + struct ext_include_generator_context *parent; +}; + +static inline struct ext_include_generator_context * + ext_include_get_generator_context + (struct sieve_generator *gentr); + +/* Binary context */ + +struct ext_include_binary_context { + struct sieve_binary *binary; + struct hash_table *included_scripts; +}; + +/* Main context management */ static struct ext_include_main_context *ext_include_create_main_context (struct sieve_generator *gentr) @@ -19,12 +39,12 @@ static struct ext_include_main_context *ext_include_create_main_context p_new(pool, struct ext_include_main_context, 1); ctx->generator = gentr; - ctx->included_scripts = hash_create - (pool, pool, 0, str_hash, (hash_cmp_callback_t *)strcmp); return ctx; } +/* Generator context management */ + static struct ext_include_generator_context * ext_include_create_generator_context (struct sieve_generator *gentr, struct ext_include_generator_context *parent, @@ -47,14 +67,24 @@ static struct ext_include_generator_context * return ctx; } -inline struct ext_include_generator_context *ext_include_get_generator_context +static inline struct ext_include_generator_context * + ext_include_get_generator_context (struct sieve_generator *gentr) { return (struct ext_include_generator_context *) sieve_generator_extension_get_context(gentr, ext_include_my_id); } -void ext_include_register_generator_context(struct sieve_generator *gentr) +static inline void ext_include_initialize_generator_context +(struct sieve_generator *gentr, struct ext_include_generator_context *parent, + struct sieve_script *script) +{ + sieve_generator_extension_set_context(gentr, ext_include_my_id, + ext_include_create_generator_context(gentr, parent, script)); +} + +void ext_include_register_generator_context +(struct sieve_generator *gentr) { struct ext_include_generator_context *ctx = ext_include_get_generator_context(gentr); @@ -68,6 +98,82 @@ void ext_include_register_generator_context(struct sieve_generator *gentr) } } +/* Binary context functions */ + +struct _included_script { + struct sieve_script *script; + unsigned int block_id; +}; + +static struct ext_include_binary_context *ext_include_create_binary_context +(struct sieve_binary *sbin) +{ + pool_t pool = sieve_binary_pool(sbin); + + struct ext_include_binary_context *ctx = + p_new(pool, struct ext_include_binary_context, 1); + + ctx->binary = sbin; + ctx->included_scripts = hash_create(pool, pool, 0, + (hash_callback_t *) sieve_script_hash, + (hash_cmp_callback_t *) sieve_script_cmp); + + return ctx; +} + +static inline struct ext_include_binary_context *ext_include_get_binary_context +(struct sieve_binary *sbin) +{ + struct ext_include_binary_context *ctx = (struct ext_include_binary_context *) + sieve_binary_extension_get_context(sbin, ext_include_my_id); + + if ( ctx == NULL ) { + ctx = ext_include_create_binary_context(sbin); + sieve_binary_extension_set_context(sbin, ext_include_my_id, ctx); + }; + + return ctx; +} + +static void ext_include_script_include +(struct ext_include_binary_context *binctx, struct sieve_script *script, + unsigned int block_id) +{ + pool_t pool = sieve_binary_pool(binctx->binary); + struct _included_script *incscript; + + incscript = p_new(pool, struct _included_script, 1); + incscript->script = script; + incscript->block_id = block_id; + + printf("INCLUDE: %s\n", sieve_script_path(script)); + + /* FIXME: NOWW!! + * THIS WILL CAUSE A MEMORY LEAK!! + */ + sieve_script_ref(script); + + hash_insert(binctx->included_scripts, (void *) script, (void *) incscript); +} + +static bool ext_include_script_is_included +(struct ext_include_binary_context *binctx, struct sieve_script *script, + unsigned int *block_id) +{ + struct _included_script *incscript = (struct _included_script *) + hash_lookup(binctx->included_scripts, script); + + if ( incscript == 0 ) + return FALSE; + + printf("ALREADY INCLUDED: %s\n", sieve_script_path(incscript->script)); + + *block_id = incscript->block_id; + return TRUE; +} + +/* Including a script during generation */ + bool ext_include_generate_include (struct sieve_generator *gentr, struct sieve_command_context *cmd, const char *script_path, const char *script_name) @@ -76,12 +182,13 @@ bool ext_include_generate_include struct sieve_script *script; struct sieve_ast *ast; struct sieve_binary *sbin = sieve_generator_get_binary(gentr); + struct ext_include_binary_context *binctx; struct sieve_generator *subgentr; - struct ext_include_generator_context *parent = + struct ext_include_generator_context *ctx = ext_include_get_generator_context(gentr); - struct ext_include_generator_context *ctx; + struct ext_include_generator_context *pctx; struct sieve_error_handler *ehandler = sieve_generator_error_handler(gentr); - unsigned this_block_id, new_block_id; + unsigned this_block_id, inc_block_id; /* Do not include more scripts when errors have occured already. */ if ( sieve_get_errors(ehandler) > 0 ) @@ -94,51 +201,65 @@ bool ext_include_generate_include /* Check for circular include */ - ctx = parent; - while ( ctx != NULL ) { - if ( sieve_script_equals(ctx->script, script) ) { + 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; } - ctx = ctx->parent; + pctx = pctx->parent; } - - /* Parse */ - if ( (ast = sieve_parse(script, ehandler)) == NULL ) { - sieve_command_generate_error(gentr, cmd, - "failed to parse included script '%s'", script_name); - return FALSE; - } - /* Validate */ - if ( !sieve_validate(ast, ehandler) ) { - sieve_command_generate_error(gentr, cmd, - "failed to validate included script '%s'", script_name); + binctx = ext_include_get_binary_context(sbin); + + /* Is the script already compiled into the current binary? */ + if ( !ext_include_script_is_included(binctx, script, &inc_block_id) ) { + /* Allocate a new block in the binary and mark the script as included + * already. + */ + inc_block_id = sieve_binary_block_create(sbin); + ext_include_script_include(binctx, script, inc_block_id); - sieve_ast_unref(&ast); - return FALSE; - } - - new_block_id = sieve_binary_block_create(sbin); - this_block_id = sieve_binary_block_set_active(sbin, new_block_id); - subgentr = sieve_generator_create(ast, ehandler); - - sieve_generator_extension_set_context(subgentr, ext_include_my_id, - ext_include_create_generator_context(subgentr, parent, script)); + /* Include list now holds a reference */ + sieve_script_unref(&script); - if ( !sieve_generator_run(subgentr, &sbin) ) { - sieve_command_generate_error(gentr, cmd, - "failed to validate included script '%s'", script_name); - result = FALSE; - } - - (void) sieve_binary_block_set_active(sbin, this_block_id); - sieve_generator_free(&subgentr); - sieve_ast_unref(&ast); + /* Parse */ + if ( (ast = sieve_parse(script, ehandler)) == NULL ) { + sieve_command_generate_error(gentr, cmd, + "failed to parse included script '%s'", script_name); + return FALSE; + } + + /* Validate */ + if ( !sieve_validate(ast, ehandler) ) { + sieve_command_generate_error(gentr, cmd, + "failed to validate included script '%s'", script_name); + sieve_ast_unref(&ast); + return FALSE; + } + + /* Generate */ + this_block_id = sieve_binary_block_set_active(sbin, inc_block_id); + subgentr = sieve_generator_create(ast, ehandler); + ext_include_initialize_generator_context(subgentr, ctx, script); + + if ( !sieve_generator_run(subgentr, &sbin) ) { + sieve_command_generate_error(gentr, cmd, + "failed to validate included script '%s'", script_name); + result = FALSE; + } + + (void) sieve_binary_block_set_active(sbin, this_block_id); + sieve_generator_free(&subgentr); + /* Cleanup */ + sieve_ast_unref(&ast); + } else + sieve_script_unref(&script); + return result; } diff --git a/src/lib-sieve/plugins/include/ext-include-common.h b/src/lib-sieve/plugins/include/ext-include-common.h index 958e25fd42b8b1d63fa7905e5cb5ff370fd7761d..c260138a96ec63d7c532cc587d6ed7181eb873ac 100644 --- a/src/lib-sieve/plugins/include/ext-include-common.h +++ b/src/lib-sieve/plugins/include/ext-include-common.h @@ -11,20 +11,12 @@ extern int ext_include_my_id; extern const struct sieve_extension include_extension; +/* Main context, currently not used for anything and might be removed */ + struct ext_include_main_context { struct sieve_generator *generator; - struct hash_table *included_scripts; -}; - -struct ext_include_generator_context { - unsigned int nesting_level; - struct sieve_script *script; - struct ext_include_main_context *main; - struct ext_include_generator_context *parent; }; -inline struct ext_include_generator_context *ext_include_get_generator_context - (struct sieve_generator *gentr); void ext_include_register_generator_context (struct sieve_generator *gentr); diff --git a/src/lib-sieve/plugins/include/ext-include.c b/src/lib-sieve/plugins/include/ext-include.c index ea1156cdf715ba5edeb6a3c42f8c406d336b574e..d4c25330e3c1831579851de342fe3fef051863ae 100644 --- a/src/lib-sieve/plugins/include/ext-include.c +++ b/src/lib-sieve/plugins/include/ext-include.c @@ -3,10 +3,15 @@ * * Authors: Stephan Bosch * Specification: draft-daboo-sieve-include-05 - * Implementation: skeleton + * Implementation: basic include functionality starts to emerge. * Status: under development * */ + +/* FIXME: Current include implementation does not allow for parts of the script + * to be located in external binaries; all included scripts are recompiled and + * the resulting byte code is imported into the main binary in separate blocks. + */ #include "lib.h" diff --git a/src/lib-sieve/sieve-script.c b/src/lib-sieve/sieve-script.c index 11e4639dd9162a8c7eb4695c5d75b4f0c76f02b8..d4a5233b14664e0f43cb3d8c82fa0b071b170a77 100644 --- a/src/lib-sieve/sieve-script.c +++ b/src/lib-sieve/sieve-script.c @@ -136,10 +136,15 @@ void sieve_script_close(struct sieve_script *script) /* Comparison */ -bool sieve_script_equals +int sieve_script_cmp (struct sieve_script *script1, struct sieve_script *script2) { - return ( script1->st.st_ino == script2->st.st_ino ); + return ( script1->st.st_ino == script2->st.st_ino ) ? 0 : -1; +} + +unsigned int sieve_script_hash(struct sieve_script *script) +{ + return (unsigned int) script->st.st_ino; } /* Inline accessors */ diff --git a/src/lib-sieve/sieve-script.h b/src/lib-sieve/sieve-script.h index e0651b5bc10602163f3275a81112e4767f88f831..fb03531967c04ad4aab65d9e8e1a713cb5ef96f6 100644 --- a/src/lib-sieve/sieve-script.h +++ b/src/lib-sieve/sieve-script.h @@ -18,8 +18,15 @@ void sieve_script_unref(struct sieve_script **script); struct istream *sieve_script_open(struct sieve_script *script); void sieve_script_close(struct sieve_script *script); -bool sieve_script_equals -(struct sieve_script *script1, struct sieve_script *script2); +int sieve_script_cmp + (struct sieve_script *script1, struct sieve_script *script2); +unsigned int sieve_script_hash(struct sieve_script *script); + +static inline bool sieve_script_equals + (struct sieve_script *script1, struct sieve_script *script2) +{ + return ( sieve_script_cmp(script1, script2) == 0 ); +} inline const char *sieve_script_name(struct sieve_script *script); inline const char *sieve_script_path(struct sieve_script *script);