diff --git a/src/lib-sieve/Makefile.am b/src/lib-sieve/Makefile.am index 0ca84586e979c58f38268499487c598aaa436c95..3bab6db66f0f356348784418d7aee8757afba655 100644 --- a/src/lib-sieve/Makefile.am +++ b/src/lib-sieve/Makefile.am @@ -45,6 +45,7 @@ libsieve_la_LIBADD = $(plugins) libsieve_la_SOURCES = \ sieve-lexer.c \ + sieve-script.c \ sieve-ast.c \ sieve-binary.c \ sieve-parser.c \ diff --git a/src/lib-sieve/plugins/include/Makefile.am b/src/lib-sieve/plugins/include/Makefile.am index 54e8fd0b5d96f39c4a0189ec498ba93379b82efb..89e93524b1d6eaaa8316d1086c119cf8ec82128c 100644 --- a/src/lib-sieve/plugins/include/Makefile.am +++ b/src/lib-sieve/plugins/include/Makefile.am @@ -13,6 +13,7 @@ cmds = \ libsieve_ext_include_la_SOURCES = \ $(cmds) \ + ext-include-common.c \ ext-include.c noinst_HEADERS = \ diff --git a/src/lib-sieve/plugins/include/cmd-include.c b/src/lib-sieve/plugins/include/cmd-include.c index ca09ec5a997ce706c6091787c89a619a127becdc..cffd608dcb1c49aef08f0c6bd3b96dac11206114 100644 --- a/src/lib-sieve/plugins/include/cmd-include.c +++ b/src/lib-sieve/plugins/include/cmd-include.c @@ -2,6 +2,7 @@ #include "sieve-common.h" +#include "sieve-script.h" #include "sieve-code.h" #include "sieve-extensions.h" #include "sieve-commands.h" @@ -22,7 +23,11 @@ static bool opc_include_execute const struct sieve_runtime_env *renv, sieve_size_t *address); static bool cmd_include_registered - (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg); + (struct sieve_validator *validator, + struct sieve_command_registration *cmd_reg); +static bool cmd_include_pre_validate + (struct sieve_validator *validator ATTR_UNUSED, + struct sieve_command_context *cmd); static bool cmd_include_validate (struct sieve_validator *validator, struct sieve_command_context *cmd); static bool cmd_include_generate @@ -41,7 +46,7 @@ const struct sieve_command cmd_include = { SCT_COMMAND, 1, 0, FALSE, FALSE, cmd_include_registered, - NULL, + cmd_include_pre_validate, cmd_include_validate, cmd_include_generate, NULL @@ -58,20 +63,20 @@ const struct sieve_opcode include_opcode = { opc_include_execute }; -/* Tag validation */ +/* Context structures */ -static bool cmd_include_validate_location_tag - (struct sieve_validator *validator, - struct sieve_ast_argument **arg, - struct sieve_command_context *cmd) -{ - /* SKELETON: Self destruct */ - *arg = sieve_ast_arguments_detach(*arg,1); - - return TRUE; -} +struct cmd_include_context_data { + enum { LOCATION_PERSONAL, LOCATION_GLOBAL } location; + bool location_assigned; + struct sieve_script *script; + struct sieve_ast *ast; +}; -/* Command registration */ +/* Tags */ + +static bool cmd_include_validate_location_tag + (struct sieve_validator *validator, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd); static const struct sieve_argument include_personal_tag = { "personal", NULL, @@ -85,6 +90,39 @@ static const struct sieve_argument include_global_tag = { NULL, NULL }; +/* Tag validation */ + +static bool cmd_include_validate_location_tag +(struct sieve_validator *validator, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd) +{ + struct cmd_include_context_data *ctx_data = + (struct cmd_include_context_data *) cmd->data; + + if ( ctx_data->location_assigned) { + sieve_command_validate_error(validator, cmd, + "cannot use location tags ':personal' and ':global' multiple times " + "for the include command"); + return FALSE; + } + + if ( (*arg)->argument == &include_personal_tag ) + ctx_data->location = LOCATION_PERSONAL; + else if ( (*arg)->argument == &include_global_tag ) + ctx_data->location = LOCATION_GLOBAL; + else + return FALSE; + + ctx_data->location_assigned = TRUE; + + /* Delete this tag (for now) */ + *arg = sieve_ast_arguments_detach(*arg, 1); + + return TRUE; +} + +/* Command registration */ + enum cmd_include_optional { OPT_END, OPT_LOCATION @@ -103,22 +141,69 @@ static bool cmd_include_registered /* Command validation */ +static bool cmd_include_pre_validate + (struct sieve_validator *validator ATTR_UNUSED, + struct sieve_command_context *cmd) +{ + struct cmd_include_context_data *ctx_data; + + /* Assign context */ + ctx_data = p_new(sieve_command_pool(cmd), struct cmd_include_context_data, 1); + ctx_data->location = LOCATION_PERSONAL; + cmd->data = ctx_data; + + return TRUE; +} + static bool cmd_include_validate(struct sieve_validator *validator, struct sieve_command_context *cmd) { struct sieve_ast_argument *arg = cmd->first_positional; + struct cmd_include_context_data *ctx_data = + (struct cmd_include_context_data *) cmd->data; + const char *script_name, *script_path; + struct sieve_script *script; + struct sieve_ast *ast; if ( !sieve_validate_positional_argument (validator, cmd, arg, "value", 1, SAAT_STRING) ) { return FALSE; } + + /* Get script path */ + + script_name = sieve_ast_argument_strc(arg); + + /* FIXME: Hardcoded */ +#define HARDCODED_DIR "src/lib-sieve/plugins/include/" + if ( ctx_data->location == LOCATION_PERSONAL ) + script_path = t_strconcat + (HARDCODED_DIR, script_name, ".sieve", NULL); + else if ( ctx_data->location == LOCATION_GLOBAL ) + script_path = t_strconcat + (HARDCODED_DIR, script_name, ".sieve", NULL); + else + return FALSE; + + script = sieve_script_create(script_path, script_name); + + /* Validate */ + if ( !ext_include_validate_include + (validator, cmd, script, &ast) ) { + sieve_script_unref(&script); + return FALSE; + } + + sieve_script_unref(&script); + + ctx_data->ast = ast; sieve_validator_argument_activate(validator, arg); return TRUE; } /* - * Generation + * Code Generation */ static bool cmd_include_generate diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c new file mode 100644 index 0000000000000000000000000000000000000000..4e6394ffaafbcc41dec352119f681c2de38972f2 --- /dev/null +++ b/src/lib-sieve/plugins/include/ext-include-common.c @@ -0,0 +1,125 @@ +#include "sieve-common.h" +#include "sieve-script.h" +#include "sieve-ast.h" +#include "sieve-commands.h" +#include "sieve-error.h" +#include "sieve-validator.h" + +#include "ext-include-common.h" + +/* Validator context management */ + +static struct ext_include_main_context *ext_include_create_main_context +(struct sieve_validator *validator) +{ + pool_t pool = sieve_validator_pool(validator); + + struct ext_include_main_context *ctx = + p_new(pool, struct ext_include_main_context, 1); + + ctx->validator = validator; + ctx->included_scripts = hash_create + (pool, pool, 0, str_hash, (hash_cmp_callback_t *)strcmp); + + return ctx; +} + +static struct ext_include_validator_context * + ext_include_create_validator_context +(struct sieve_validator *validator, + struct ext_include_validator_context *parent, struct sieve_script *script) +{ + struct ext_include_validator_context *ctx; + + pool_t pool = sieve_validator_pool(validator); + ctx = p_new(pool, struct ext_include_validator_context, 1); + ctx->parent = parent; + ctx->script = script; + if ( parent == NULL ) { + ctx->nesting_level = 0; + ctx->main = ext_include_create_main_context(validator); + } else { + ctx->nesting_level = parent->nesting_level + 1; + ctx->main = parent->main; + } + + return ctx; +} + +inline struct ext_include_validator_context * + ext_include_get_validator_context +(struct sieve_validator *validator) +{ + return (struct ext_include_validator_context *) + sieve_validator_extension_get_context(validator, ext_include_my_id); +} + +void ext_include_register_validator_context +(struct sieve_validator *validator, struct sieve_script *script) +{ + struct ext_include_validator_context *ctx = + ext_include_get_validator_context(validator); + + if ( ctx == NULL ) { + ctx = ext_include_create_validator_context(validator, NULL, script); + + sieve_validator_extension_set_context + (validator, ext_include_my_id, (void *) ctx); + } +} + +bool ext_include_validate_include +(struct sieve_validator *validator, struct sieve_command_context *cmd, + struct sieve_script *script, struct sieve_ast **ast_r) +{ + bool result = TRUE; + struct sieve_validator *subvalid; + struct ext_include_validator_context *parent = + ext_include_get_validator_context(validator); + struct ext_include_validator_context *ctx; + struct sieve_error_handler *ehandler = + sieve_validator_get_error_handler(validator); + + *ast_r = NULL; + + /* Check for circular include */ + + ctx = parent; + while ( ctx != NULL ) { + if ( sieve_script_equals(ctx->script, script) ) { + sieve_command_validate_error + (validator, cmd, "circular include"); + return FALSE; + } + + ctx = ctx->parent; + } + + /* Parse script */ + + if ( (*ast_r = sieve_parse(script, ehandler)) == NULL ) { + sieve_command_validate_error + (validator, cmd, "parse failed for included script '%s'", + sieve_script_name(script)); + return FALSE; + } + + /* Validate script */ + + subvalid = sieve_validator_create(*ast_r, ehandler); + ctx = ext_include_create_validator_context(subvalid, parent, script); + sieve_validator_extension_set_context(subvalid, ext_include_my_id, ctx); + + if ( !sieve_validator_run(subvalid) || sieve_get_errors(ehandler) > 0 ) { + sieve_command_validate_error + (validator, cmd, "validation failed for included script '%s'", + sieve_script_name(script)); + sieve_ast_unref(ast_r); + result = FALSE; + } + + sieve_validator_free(&subvalid); + + 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 7a95aaf9a98c395c93cdf2747cec087c76322c1e..f7e89a3fa491d167134aafaa06997b81b65c13a1 100644 --- a/src/lib-sieve/plugins/include/ext-include-common.h +++ b/src/lib-sieve/plugins/include/ext-include-common.h @@ -1,6 +1,35 @@ #ifndef __EXT_INCLUDE_COMMON_H -#define __EXT_INCLIDE_COMMON_H +#define __EXT_INCLUDE_COMMON_H +#include "lib.h" +#include "hash.h" + +#include "sieve-common.h" + +#define EXT_INCLUDE_MAX_NESTING_LEVEL 10 + +extern int ext_include_my_id; extern const struct sieve_extension include_extension; +struct ext_include_main_context { + struct sieve_validator *validator; + struct hash_table *included_scripts; +}; + +struct ext_include_validator_context { + unsigned int nesting_level; + struct sieve_script *script; + struct ext_include_main_context *main; + struct ext_include_validator_context *parent; +}; + +inline struct ext_include_validator_context *ext_include_get_validator_context + (struct sieve_validator *validator); +void ext_include_register_validator_context + (struct sieve_validator *validator, struct sieve_script *script); + +bool ext_include_validate_include +(struct sieve_validator *validator, struct sieve_command_context *cmd, + struct sieve_script *script, struct sieve_ast **ast_r); + #endif /* __EXT_INCLUDE_COMMON_H */ diff --git a/src/lib-sieve/plugins/include/ext-include.c b/src/lib-sieve/plugins/include/ext-include.c index 5148fe98182d111e4f1262adfc9c9a79279b7429..6e3b02efb1f8533a48b2320355c1db6d246529b7 100644 --- a/src/lib-sieve/plugins/include/ext-include.c +++ b/src/lib-sieve/plugins/include/ext-include.c @@ -40,7 +40,7 @@ static const struct sieve_opcode *ext_include_opcodes[] = /* Extension definitions */ -int ext_my_id; +int ext_include_my_id; const struct sieve_extension include_extension = { "include", @@ -53,7 +53,7 @@ const struct sieve_extension include_extension = { static bool ext_include_load(int ext_id) { - ext_my_id = ext_id; + ext_include_my_id = ext_id; return TRUE; } @@ -65,6 +65,9 @@ static bool ext_include_validator_load(struct sieve_validator *validator) /* Register new commands */ sieve_validator_register_command(validator, &cmd_include); sieve_validator_register_command(validator, &cmd_return); + + ext_include_register_validator_context(validator, + sieve_validator_get_script(validator)); return TRUE; } diff --git a/src/lib-sieve/plugins/include/include.sieve b/src/lib-sieve/plugins/include/include.sieve index 17a92222bd9d9bda917d84431c33728a156ee266..294754cc450821e0523df5ce0a25daac9197e693 100644 --- a/src/lib-sieve/plugins/include/include.sieve +++ b/src/lib-sieve/plugins/include/include.sieve @@ -1,5 +1,5 @@ require "include"; -include "frop.sieve"; -include :global "friep.sieve"; -include :personal "frml.sieve"; +include "included1"; +include :global "included2"; +include :personal "included3"; diff --git a/src/lib-sieve/plugins/include/included1.sieve b/src/lib-sieve/plugins/include/included1.sieve new file mode 100644 index 0000000000000000000000000000000000000000..41e84c2dd55cd8cad0014048576bca7a2e9f35c4 --- /dev/null +++ b/src/lib-sieve/plugins/include/included1.sieve @@ -0,0 +1,3 @@ +require "fileinto"; + +fileinto "INBOX.frop"; diff --git a/src/lib-sieve/plugins/include/included2.sieve b/src/lib-sieve/plugins/include/included2.sieve new file mode 100644 index 0000000000000000000000000000000000000000..178e1d37b36552ae2b20f8db48eb525d5bec7bf0 --- /dev/null +++ b/src/lib-sieve/plugins/include/included2.sieve @@ -0,0 +1,3 @@ +require "vacation"; + +vacation "Ik ben er ff niet."; diff --git a/src/lib-sieve/plugins/include/included3.sieve b/src/lib-sieve/plugins/include/included3.sieve new file mode 100644 index 0000000000000000000000000000000000000000..08a6621edf5892cf2f0dce58e9abdb7984cc8a04 --- /dev/null +++ b/src/lib-sieve/plugins/include/included3.sieve @@ -0,0 +1 @@ +discard diff --git a/src/lib-sieve/sieve-ast.c b/src/lib-sieve/sieve-ast.c index 47af4aef00d3cd7ad47ee77b6f17a39e43bbf805..95a4db158299c9b53b9b408219ab9d13db4ace49 100644 --- a/src/lib-sieve/sieve-ast.c +++ b/src/lib-sieve/sieve-ast.c @@ -4,6 +4,8 @@ #include "str.h" #include "mempool.h" +#include "sieve-script.h" + #include "sieve-ast.h" /* Very simplistic linked list implementation @@ -354,14 +356,17 @@ struct sieve_ast_node *sieve_ast_command_create } /* The AST */ -struct sieve_ast *sieve_ast_create(const char *scriptname) { +struct sieve_ast *sieve_ast_create(struct sieve_script *script) { pool_t pool; struct sieve_ast *ast; pool = pool_alloconly_create("sieve_ast", 4096); ast = p_new(pool, struct sieve_ast, 1); ast->pool = pool; - ast->scriptname = p_strdup(pool, scriptname); + ast->refcount = 1; + + ast->script = script; + sieve_script_ref(script); ast->root = sieve_ast_node_create(ast, NULL, SAT_ROOT, 0); @@ -371,14 +376,20 @@ struct sieve_ast *sieve_ast_create(const char *scriptname) { } void sieve_ast_ref(struct sieve_ast *ast) { - pool_ref(ast->pool); + ast->refcount++; } void sieve_ast_unref(struct sieve_ast **ast) { - if ( ast != NULL && *ast != NULL ) { - pool_unref(&((*ast)->pool)); - *ast = NULL; - } + i_assert((*ast)->refcount > 0); + + if (--(*ast)->refcount != 0) + return; + + sieve_script_unref(&(*ast)->script); + + pool_unref(&(*ast)->pool); + + *ast = NULL; } const char *sieve_ast_type_name(enum sieve_ast_type ast_type) { diff --git a/src/lib-sieve/sieve-ast.h b/src/lib-sieve/sieve-ast.h index 0a8f024f198df7f8e0c0337f786dcbc9da2fcc1f..aeac21da901a46bfb021309a7533412f4ed7095b 100644 --- a/src/lib-sieve/sieve-ast.h +++ b/src/lib-sieve/sieve-ast.h @@ -153,9 +153,10 @@ struct sieve_ast_node { struct sieve_ast { pool_t pool; + int refcount; - const char *scriptname; - + struct sieve_script *script; + struct sieve_ast_node *root; }; @@ -193,7 +194,7 @@ struct sieve_ast_node *sieve_ast_command_create (struct sieve_ast_node *parent, const char *identifier, unsigned int source_line); /* sieve_ast */ -struct sieve_ast *sieve_ast_create(const char *scriptname); +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); @@ -213,7 +214,7 @@ void sieve_ast_unparse(struct sieve_ast *ast); /* AST macros */ #define sieve_ast_root(ast) (ast->root) -#define sieve_ast_scriptname(ast) (ast->scriptname) +#define sieve_ast_script(ast) (ast->script) #define sieve_ast_pool(ast) (ast->pool) /* AST node macros */ diff --git a/src/lib-sieve/sieve-commands.h b/src/lib-sieve/sieve-commands.h index 79255f9680f5b8fdc38c37260f33eede684afee3..1bfd5bfce5402b64ee7a0a167ae3fbcc6fe1aca7 100644 --- a/src/lib-sieve/sieve-commands.h +++ b/src/lib-sieve/sieve-commands.h @@ -87,6 +87,9 @@ const char *sieve_command_type_name(const struct sieve_command *command); #define sieve_command_validate_error(validator, context, ...) \ sieve_validator_error(validator, (context)->ast_node, __VA_ARGS__) +#define sieve_command_validate_critical(validator, context, ...) \ + sieve_validator_critical(validator, (context)->ast_node, __VA_ARGS__) + #define sieve_command_pool(context) \ sieve_ast_node_pool((context)->ast_node) diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h index 2d49d79b3d25f52a0b30e06aab4e7b5cf7330d78..be312ad3a0df8af49eb0c37f0b13856b7de7ca62 100644 --- a/src/lib-sieve/sieve-common.h +++ b/src/lib-sieve/sieve-common.h @@ -16,6 +16,9 @@ typedef uint64_t sieve_number_t; * Predeclarations */ +/* sieve-error.h */ +struct sieve_error_handler; + /* sieve-ast.h */ enum sieve_ast_argument_type; @@ -84,4 +87,12 @@ struct sieve_action_exec_env; struct sieve_action; struct sieve_side_effect; +/* sieve-script.h */ +struct sieve_script; + +/* sieve.c */ +struct sieve_ast *sieve_parse + (struct sieve_script *script, struct sieve_error_handler *ehandler); + + #endif /* __SIEVE_COMMON_H */ diff --git a/src/lib-sieve/sieve-error.c b/src/lib-sieve/sieve-error.c index 4cfec4fefa23c5d12f8a405b07d674bcf8b628a9..f8091cbd6b0d6164d04d5d4161728d7b8c17dcbd 100644 --- a/src/lib-sieve/sieve-error.c +++ b/src/lib-sieve/sieve-error.c @@ -12,6 +12,10 @@ #include <stdlib.h> #include <unistd.h> +#define CRITICAL_MSG \ + "internal error occurred: refer to server log for more information." +#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]" + /* This should be moved to a sieve-errors-private.h when the need for other * types of (externally defined) error handlers arises. */ @@ -76,6 +80,22 @@ void sieve_vinfo ehandler->vinfo(ehandler, location, fmt, args); } +void sieve_vcritical + (struct sieve_error_handler *ehandler, const char *location, + const char *fmt, va_list args) +{ + char str[256]; + struct tm *tm; + + tm = localtime(&ioloop_time); + + i_error("sieve: %s: %s", location, t_strdup_vprintf(fmt, args)); + + sieve_error(ehandler, location, "%s", + strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ? + str : CRITICAL_MSG ); +} + unsigned int sieve_get_errors(struct sieve_error_handler *ehandler) { return ehandler->errors; } diff --git a/src/lib-sieve/sieve-error.h b/src/lib-sieve/sieve-error.h index 2a095abcf26f84df2d169200bfdb5c2fc4a26479..37ab8d23ef538e801e8bb5d404aa214245e75d42 100644 --- a/src/lib-sieve/sieve-error.h +++ b/src/lib-sieve/sieve-error.h @@ -20,6 +20,9 @@ void sieve_vwarning void sieve_vinfo (struct sieve_error_handler *ehandler, const char *location, const char *fmt, va_list args); +void sieve_vcritical + (struct sieve_error_handler *ehandler, const char *location, + const char *fmt, va_list args); inline static void sieve_error (struct sieve_error_handler *ehandler, const char *location, @@ -28,6 +31,9 @@ inline static void sieve_warning (struct sieve_error_handler *ehandler, const char *location, const char *fmt, ...) ATTR_FORMAT(3, 4); inline static void sieve_info +(struct sieve_error_handler *ehandler, const char *location, + const char *fmt, ...) ATTR_FORMAT(3, 4); +inline static void sieve_critical (struct sieve_error_handler *ehandler, const char *location, const char *fmt, ...) ATTR_FORMAT(3, 4); @@ -67,6 +73,18 @@ inline static void sieve_info va_end(args); } +inline static void sieve_critical +(struct sieve_error_handler *ehandler, const char *location, + const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + T_FRAME(sieve_vcritical(ehandler, location, fmt, args)); + + va_end(args); +} + void sieve_error_handler_accept_infolog (struct sieve_error_handler *ehandler, bool enable); void sieve_error_handler_copy_masterlog diff --git a/src/lib-sieve/sieve-lexer.c b/src/lib-sieve/sieve-lexer.c index c0e1e66144fdbfb3dc56906c199153333ab844bc..f6e87ac232456e1780435bdabfebe8c94018a86a 100644 --- a/src/lib-sieve/sieve-lexer.c +++ b/src/lib-sieve/sieve-lexer.c @@ -1,17 +1,19 @@ -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <stdlib.h> -#include <unistd.h> - #include "lib.h" #include "compat.h" #include "str.h" #include "istream.h" -#include "sieve-lexer.h" #include "sieve-error.h" +#include "sieve-script.h" + +#include "sieve-lexer.h" + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> #define IS_DIGIT(c) ( c >= '0' && c <= '9' ) #define DIGIT_VAL(c) ( c - '0' ) @@ -20,7 +22,8 @@ struct sieve_lexer { pool_t pool; - const char *scriptname; + + struct sieve_script *script; struct istream *input; int current_line; @@ -42,7 +45,6 @@ inline static void sieve_lexer_error inline static void sieve_lexer_warning (struct sieve_lexer *lexer, const char *fmt, ...) ATTR_FORMAT(2, 3); - inline static void sieve_lexer_error (struct sieve_lexer *lexer, const char *fmt, ...) { @@ -50,7 +52,8 @@ inline static void sieve_lexer_error va_start(args, fmt); T_FRAME(sieve_verror(lexer->ehandler, - t_strdup_printf("%s:%d", lexer->scriptname, lexer->current_line), + t_strdup_printf("%s:%d", sieve_script_name(lexer->script), + lexer->current_line), fmt, args)); va_end(args); @@ -63,22 +66,33 @@ inline static void sieve_lexer_warning va_start(args, fmt); T_FRAME(sieve_vwarning(lexer->ehandler, - t_strdup_printf("%s:%d", lexer->scriptname, lexer->current_line), + t_strdup_printf("%s:%d", sieve_script_name(lexer->script), + lexer->current_line), fmt, args)); va_end(args); } struct sieve_lexer *sieve_lexer_create -(struct istream *stream, const char *scriptname, - struct sieve_error_handler *ehandler) +(struct sieve_script *script, struct sieve_error_handler *ehandler) { - pool_t pool = pool_alloconly_create("sieve_lexer", 1024); - struct sieve_lexer *lexer = p_new(pool, struct sieve_lexer, 1); - + pool_t pool; + struct sieve_lexer *lexer; + struct istream *stream; + + stream = sieve_script_open(script, ehandler); + if ( stream == NULL ) + return NULL; + + pool = pool_alloconly_create("sieve_lexer", 1024); + lexer = p_new(pool, struct sieve_lexer, 1); lexer->pool = pool; - lexer->scriptname = p_strdup(pool, scriptname); + lexer->input = stream; + i_stream_ref(lexer->input); + + lexer->script = script; + sieve_script_ref(script); lexer->buffer = NULL; lexer->buffer_size = 0; @@ -94,11 +108,20 @@ struct sieve_lexer *sieve_lexer_create return lexer; } -void sieve_lexer_free(struct sieve_lexer *lexer ATTR_UNUSED) { - pool_unref(&(lexer->pool)); /* This frees any allocated string value as well */ +void sieve_lexer_free(struct sieve_lexer **lexer) +{ + i_stream_unref(&(*lexer)->input); + + sieve_script_close((*lexer)->script); + sieve_script_unref(&(*lexer)->script); + + pool_unref(&(*lexer)->pool); + + *lexer = NULL; } -static void sieve_lexer_shift(struct sieve_lexer *lexer) { +static void sieve_lexer_shift(struct sieve_lexer *lexer) +{ if ( lexer->buffer != NULL && lexer->buffer[lexer->buffer_pos] == '\n' ) lexer->current_line++; diff --git a/src/lib-sieve/sieve-lexer.h b/src/lib-sieve/sieve-lexer.h index aa092d6d7d6e053f3bdf207d89be9d305dcdcc4a..e33b19577fef205f079f31858ab5e543e5828123 100644 --- a/src/lib-sieve/sieve-lexer.h +++ b/src/lib-sieve/sieve-lexer.h @@ -3,7 +3,7 @@ #include "lib.h" -#include "sieve-error.h" +#include "sieve-common.h" enum sieve_token_type { STT_NONE, @@ -41,9 +41,8 @@ struct sieve_token; struct sieve_lexer; struct sieve_lexer *sieve_lexer_create - (struct istream *stream, const char *scriptname, - struct sieve_error_handler *ehandler); -void sieve_lexer_free(struct sieve_lexer *lexer); + (struct sieve_script *script, struct sieve_error_handler *ehandler); +void sieve_lexer_free(struct sieve_lexer **lexer); bool sieve_lexer_scan_raw_token(struct sieve_lexer *lexer); bool sieve_lexer_skip_token(struct sieve_lexer *lexer); diff --git a/src/lib-sieve/sieve-parser.c b/src/lib-sieve/sieve-parser.c index f7df7a480ad604b6afb23511f27474ef70ad2576..0b06796b4cbc196ccfbaf9a141d3a767fdc0400d 100644 --- a/src/lib-sieve/sieve-parser.c +++ b/src/lib-sieve/sieve-parser.c @@ -4,6 +4,7 @@ #include "istream.h" #include "failures.h" +#include "sieve-script.h" #include "sieve-lexer.h" #include "sieve-parser.h" #include "sieve-error.h" @@ -15,18 +16,15 @@ struct sieve_parser { pool_t pool; - const char *scriptname; - - struct istream *input; + struct sieve_script *script; + struct sieve_error_handler *ehandler; struct sieve_lexer *lexer; struct sieve_ast *ast; }; -#define SIEVE_READ_BLOCK_SIZE (1024*8) - inline static void sieve_parser_error (struct sieve_parser *parser, const char *fmt, ...) ATTR_FORMAT(2, 3); inline static void sieve_parser_warning @@ -42,7 +40,8 @@ inline static void sieve_parser_error if ( sieve_lexer_current_token(parser->lexer) != STT_ERROR ) { T_FRAME(sieve_verror(parser->ehandler, - t_strdup_printf("%s:%d", parser->scriptname, + t_strdup_printf("%s:%d", + sieve_script_name(parser->script), sieve_lexer_current_line(parser->lexer)), fmt, args)); } @@ -57,7 +56,8 @@ inline static void sieve_parser_warning va_start(args, fmt); T_FRAME(sieve_vwarning(parser->ehandler, - t_strdup_printf("%s:%d", parser->scriptname, + t_strdup_printf("%s:%d", + sieve_script_name(parser->script), sieve_lexer_current_line(parser->lexer)), fmt, args)); @@ -69,23 +69,23 @@ static bool sieve_parser_recover (struct sieve_parser *parser, enum sieve_token_type end_token); struct sieve_parser *sieve_parser_create -(int fd, const char *scriptname, struct sieve_error_handler *ehandler) +(struct sieve_script *script, struct sieve_error_handler *ehandler) { struct sieve_parser *parser; - struct istream *stream; + struct sieve_lexer *lexer; + + lexer = sieve_lexer_create(script, ehandler); - stream = i_stream_create_fd - (fd, SIEVE_READ_BLOCK_SIZE, TRUE); - - if ( stream != NULL ) { + if ( lexer != NULL ) { pool_t pool = pool_alloconly_create("sieve_parser", 4096); parser = p_new(pool, struct sieve_parser, 1); parser->pool = pool; - parser->scriptname = p_strdup(pool, scriptname); - parser->input = stream; - parser->lexer = sieve_lexer_create(stream, scriptname, ehandler); + parser->script = script; + sieve_script_ref(script); + + parser->lexer = lexer; parser->ast = NULL; parser->ehandler = ehandler; @@ -96,17 +96,17 @@ struct sieve_parser *sieve_parser_create return NULL; } -void sieve_parser_free(struct sieve_parser *parser) +void sieve_parser_free(struct sieve_parser **parser) { - if (parser->input != NULL ) - i_stream_unref(&parser->input); + if ((*parser)->ast != NULL) + sieve_ast_unref(&(*parser)->ast); - if (parser->ast != NULL) - sieve_ast_unref(&parser->ast); + sieve_lexer_free(&(*parser)->lexer); + sieve_script_unref(&(*parser)->script); - sieve_lexer_free(parser->lexer); - - pool_unref(&(parser->pool)); + pool_unref(&(*parser)->pool); + + *parser = NULL; } /* arguments = *argument [test / test-list] @@ -380,7 +380,7 @@ bool sieve_parser_run sieve_ast_unref(&parser->ast); *ast = NULL; - parser->ast = sieve_ast_create(parser->scriptname); + parser->ast = sieve_ast_create(parser->script); /* Scan first token */ sieve_lexer_skip_token(parser->lexer); diff --git a/src/lib-sieve/sieve-parser.h b/src/lib-sieve/sieve-parser.h index b0c81e28190a2c1c064b2f365c91c62739ab3b90..b06854f7857a6ca81c966200441fee6878255028 100644 --- a/src/lib-sieve/sieve-parser.h +++ b/src/lib-sieve/sieve-parser.h @@ -8,8 +8,8 @@ struct sieve_parser; struct sieve_parser *sieve_parser_create - (int fd, const char *scriptname, struct sieve_error_handler *ehandler); -void sieve_parser_free(struct sieve_parser *parser); + (struct sieve_script *script, struct sieve_error_handler *ehandler); +void sieve_parser_free(struct sieve_parser **parser); bool sieve_parser_run(struct sieve_parser *parser, struct sieve_ast **ast); #endif /* __SIEVE_PARSER_H */ diff --git a/src/lib-sieve/sieve-script.c b/src/lib-sieve/sieve-script.c new file mode 100644 index 0000000000000000000000000000000000000000..55ba5fa39a12973167e641b4307244cb241a00fb --- /dev/null +++ b/src/lib-sieve/sieve-script.c @@ -0,0 +1,131 @@ +#include "lib.h" +#include "compat.h" +#include "istream.h" + +#include "sieve-common.h" +#include "sieve-error.h" + +#include "sieve-script.h" + +#define SIEVE_READ_BLOCK_SIZE (1024*8) + +struct sieve_script { + pool_t pool; + unsigned int refcount; + + /* Parameters */ + const char *name; + const char *path; + + /* Stream */ + int fd; /* FIXME: we could use the stream's autoclose facility */ + struct istream *stream; +}; + +/* Script object */ + +struct sieve_script *sieve_script_create + (const char *path, const char *name) +{ + pool_t pool; + struct sieve_script *script; + + pool = pool_alloconly_create("sieve_script", 1024); + script = p_new(pool, struct sieve_script, 1); + script->pool = pool; + script->refcount = 1; + + script->path = p_strdup(pool, path); + + if ( name == NULL || *name == '\0' ) { + const char *filename, *ext; + + T_FRAME( + /* Extract filename from path */ + filename = strrchr(path, '/'); + if ( filename == NULL ) + filename = path; + else + filename++; + + /* Extract the script name */ + ext = strrchr(filename, '.'); + if ( ext == NULL || ext == filename || strncmp(ext,".sieve",6) != 0 ) + script->name = p_strdup(pool, filename); + else + script->name = p_strdup_until(pool, filename, ext); + ); + } else { + script->name = p_strdup(pool, name); + } + + return script; +} + +void sieve_script_ref(struct sieve_script *script) +{ + script->refcount++; +} + +void sieve_script_unref(struct sieve_script **script) +{ + i_assert((*script)->refcount > 0); + + if (--(*script)->refcount != 0) + return; + + if ( (*script)->stream != NULL ) + i_stream_destroy(&(*script)->stream); + + pool_unref(&(*script)->pool); + + *script = NULL; +} + +/* Stream manageement */ + +struct istream *sieve_script_open(struct sieve_script *script, + struct sieve_error_handler *ehandler) +{ + int fd; + + if ( (fd=open(script->path, O_RDONLY)) < 0 ) { + if ( errno == ENOENT ) + sieve_error(ehandler, script->path, "sieve script '%s' does not exist", + script->name); + else + sieve_critical(ehandler, script->path, "failed to open sieve script: %m"); + return NULL; + } + + script->stream = i_stream_create_fd(fd, SIEVE_READ_BLOCK_SIZE, TRUE); + + return script->stream; +} + +void sieve_script_close(struct sieve_script *script) +{ + i_stream_destroy(&script->stream); +} + +/* Comparison */ + +bool sieve_script_equals +(struct sieve_script *script1, struct sieve_script *script2) +{ + return ( strcmp(script1->path, script2->path) == 0 ); +} + +/* Inline accessors */ + +inline const char *sieve_script_name(struct sieve_script *script) +{ + return script->name; +} + +inline const char *sieve_script_path(struct sieve_script *script) +{ + return script->path; +} + + diff --git a/src/lib-sieve/sieve-script.h b/src/lib-sieve/sieve-script.h new file mode 100644 index 0000000000000000000000000000000000000000..1266d17576b524845156477aee7fa938a182ec04 --- /dev/null +++ b/src/lib-sieve/sieve-script.h @@ -0,0 +1,27 @@ +#ifndef __SIEVE_SCRIPT_H +#define __SIEVE_SCRIPT_H + +#include "sieve-common.h" + +/* FIXME: This conflicts with the managesieve implementation */ + +struct sieve_script; + +struct sieve_script *sieve_script_create(const char *path, const char *name); + +void sieve_script_ref(struct sieve_script *script); +void sieve_script_unref(struct sieve_script **script); + +/* Stream manageement */ + +struct istream *sieve_script_open(struct sieve_script *script, + struct sieve_error_handler *ehandler); +void sieve_script_close(struct sieve_script *script); + +bool sieve_script_equals +(struct sieve_script *script1, struct sieve_script *script2); + +inline const char *sieve_script_name(struct sieve_script *script); +inline const char *sieve_script_path(struct sieve_script *script); + +#endif /* __SIEVE_SCRIPT_H */ diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c index 370cdfb490bf7cd240dcd48e7a191c14ad0fb25a..6ca58191e98bee0bd159371ad5381e91b78a322e 100644 --- a/src/lib-sieve/sieve-validator.c +++ b/src/lib-sieve/sieve-validator.c @@ -2,6 +2,7 @@ #include "mempool.h" #include "hash.h" +#include "sieve-script.h" #include "sieve-ast.h" #include "sieve-commands.h" #include "sieve-commands-private.h" @@ -15,15 +16,16 @@ struct sieve_validator { pool_t pool; - const char *scriptname; + struct sieve_ast *ast; + struct sieve_script *script; struct sieve_error_handler *ehandler; /* Registries */ struct hash_table *commands; - ARRAY_DEFINE(ext_contexts, void); + ARRAY_DEFINE(ext_contexts, void *); }; /* Predeclared statics */ @@ -41,7 +43,7 @@ void sieve_validator_warning va_start(args, fmt); T_FRAME(sieve_vwarning(validator->ehandler, - t_strdup_printf("%s:%d", sieve_ast_scriptname(validator->ast), + t_strdup_printf("%s:%d", sieve_script_name(validator->script), sieve_ast_node_line(node)), fmt, args)); va_end(args); @@ -55,12 +57,28 @@ void sieve_validator_error va_start(args, fmt); T_FRAME(sieve_verror(validator->ehandler, - t_strdup_printf("%s:%d", sieve_ast_scriptname(validator->ast), + t_strdup_printf("%s:%d", sieve_script_name(validator->script), + sieve_ast_node_line(node)), fmt, args)); + + va_end(args); +} + +void sieve_validator_critical +(struct sieve_validator *validator, struct sieve_ast_node *node, + const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + T_FRAME(sieve_vcritical(validator->ehandler, + t_strdup_printf("%s:%d", sieve_script_name(validator->script), sieve_ast_node_line(node)), fmt, args)); va_end(args); } +/* Validator object */ + struct sieve_validator *sieve_validator_create (struct sieve_ast *ast, struct sieve_error_handler *ehandler) { @@ -71,9 +89,11 @@ struct sieve_validator *sieve_validator_create pool = pool_alloconly_create("sieve_validator", 4096); validator = p_new(pool, struct sieve_validator, 1); validator->pool = pool; + validator->ehandler = ehandler; validator->ast = ast; + validator->script = sieve_ast_script(ast); sieve_ast_ref(ast); /* Setup storage for extension contexts */ @@ -97,12 +117,14 @@ struct sieve_validator *sieve_validator_create return validator; } -void sieve_validator_free(struct sieve_validator *validator) +void sieve_validator_free(struct sieve_validator **validator) { - hash_destroy(&validator->commands); - - sieve_ast_unref(&validator->ast); - pool_unref(&(validator->pool)); + hash_destroy(&(*validator)->commands); + sieve_ast_unref(&(*validator)->ast); + + pool_unref(&(*validator)->pool); + + *validator = NULL; } inline pool_t sieve_validator_pool(struct sieve_validator *validator) @@ -110,6 +132,24 @@ inline pool_t sieve_validator_pool(struct sieve_validator *validator) return validator->pool; } +inline struct sieve_error_handler *sieve_validator_get_error_handler + (struct sieve_validator *validator) +{ + return validator->ehandler; +} + +inline struct sieve_ast *sieve_validator_get_ast + (struct sieve_validator *validator) +{ + return validator->ast; +} + +inline struct sieve_script *sieve_validator_get_script + (struct sieve_validator *validator) +{ + return validator->script; +} + /* Command registry */ struct sieve_tag_registration; @@ -342,17 +382,23 @@ int sieve_validator_extension_load return ext_id; } -inline void sieve_validator_extension_set_context(struct sieve_validator *validator, int ext_id, void *context) +inline void sieve_validator_extension_set_context + (struct sieve_validator *validator, int ext_id, void *context) { - array_idx_set(&validator->ext_contexts, (unsigned int) ext_id, context); + array_idx_set(&validator->ext_contexts, (unsigned int) ext_id, &context); } -inline const void *sieve_validator_extension_get_context(struct sieve_validator *validator, int ext_id) +inline const void *sieve_validator_extension_get_context + (struct sieve_validator *validator, int ext_id) { - if ( ext_id < 0 || ext_id > (int) array_count(&validator->ext_contexts) ) + void * const *ctx; + + if ( ext_id < 0 || ext_id >= (int) array_count(&validator->ext_contexts) ) return NULL; - return array_idx(&validator->ext_contexts, (unsigned int) ext_id); + ctx = array_idx(&validator->ext_contexts, (unsigned int) ext_id); + + return *ctx; } /* Argument Validation API */ diff --git a/src/lib-sieve/sieve-validator.h b/src/lib-sieve/sieve-validator.h index 78f789f55e97eecef17f7e22ef621c5889fab6bd..dbeb709898f2bdc9c6467eaaf49b615b6befbe9d 100644 --- a/src/lib-sieve/sieve-validator.h +++ b/src/lib-sieve/sieve-validator.h @@ -9,10 +9,18 @@ struct sieve_validator; 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); +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); +inline struct sieve_error_handler *sieve_validator_get_error_handler + (struct sieve_validator *validator); +inline struct sieve_ast *sieve_validator_get_ast + (struct sieve_validator *validator); +inline struct sieve_script *sieve_validator_get_script + (struct sieve_validator *validator); + bool sieve_validator_run(struct sieve_validator *validator); void sieve_validator_warning @@ -21,6 +29,9 @@ void sieve_validator_warning void sieve_validator_error (struct sieve_validator *validator, struct sieve_ast_node *node, const char *fmt, ...) ATTR_FORMAT(3, 4); +void sieve_validator_critical + (struct sieve_validator *validator, struct sieve_ast_node *node, + const char *fmt, ...) ATTR_FORMAT(3, 4); /* Command Programmers Interface */ @@ -33,13 +44,9 @@ void sieve_validator_register_external_tag /* Argument registration */ void sieve_validator_register_tag - (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, - const struct sieve_argument *argument, int id_code); - -/* Special test arguments */ -void sieve_validator_link_match_type_tags - (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, - unsigned int id_code); + (struct sieve_validator *validator, + struct sieve_command_registration *cmd_reg, + const struct sieve_argument *argument, int id_code); /* Argument validation */ @@ -58,7 +65,9 @@ bool sieve_validate_tag_parameter 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); +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 8e9c560fd8cfe1cf3eb5a079b07d42bf0e56b7ce..ebbbd89d045db6906aa90bb6b637f755cbff0946 100644 --- a/src/lib-sieve/sieve.c +++ b/src/lib-sieve/sieve.c @@ -7,6 +7,7 @@ #include "sieve-extensions.h" +#include "sieve-script.h" #include "sieve-ast.h" #include "sieve-binary.h" #include "sieve-result.h" @@ -18,6 +19,7 @@ #include "sieve-code-dumper.h" #include "sieve.h" +#include "sieve-common.h" #include <sys/types.h> #include <sys/stat.h> @@ -36,14 +38,14 @@ void sieve_deinit(void) sieve_extensions_deinit(); } -static struct sieve_ast *sieve_parse - (int fd, const char *scriptname, struct sieve_error_handler *ehandler) +struct sieve_ast *sieve_parse + (struct sieve_script *script, struct sieve_error_handler *ehandler) { struct sieve_parser *parser; struct sieve_ast *ast; /* Parse */ - parser = sieve_parser_create(fd, scriptname, ehandler); + parser = sieve_parser_create(script, ehandler); if ( !sieve_parser_run(parser, &ast) || sieve_get_errors(ehandler) > 0 ) { if ( ast != NULL ) @@ -53,7 +55,7 @@ static struct sieve_ast *sieve_parse } else sieve_ast_ref(ast); - sieve_parser_free(parser); + sieve_parser_free(&parser); return ast; } @@ -66,7 +68,7 @@ static bool sieve_validate(struct sieve_ast *ast, struct sieve_error_handler *eh if ( !sieve_validator_run(validator) || sieve_get_errors(ehandler) > 0 ) result = FALSE; - sieve_validator_free(validator); + sieve_validator_free(&validator); return result; } @@ -83,29 +85,29 @@ static struct sieve_binary *sieve_generate(struct sieve_ast *ast) return result; } -static struct sieve_binary *sieve_compile_fd -(int fd, const char *scriptname, struct sieve_error_handler *ehandler) +static struct sieve_binary *sieve_compile_script +(struct sieve_script *script, struct sieve_error_handler *ehandler) { - struct sieve_binary *result; struct sieve_ast *ast; + struct sieve_binary *sbin; /* Parse */ - if ( (ast = sieve_parse(fd, scriptname, ehandler)) == NULL ) { - sieve_error(ehandler, scriptname, "failed to parse script"); + if ( (ast = sieve_parse(script, ehandler)) == NULL ) { + sieve_error(ehandler, sieve_script_name(script), "parse failed"); return NULL; } /* Validate */ if ( !sieve_validate(ast, ehandler) ) { - sieve_error(ehandler, scriptname, "failed to validate script"); + sieve_error(ehandler, sieve_script_name(script), "validation failed"); sieve_ast_unref(&ast); return NULL; } /* Generate */ - if ( (result=sieve_generate(ast)) == NULL ) { - sieve_error(ehandler, scriptname, "failed to generate script"); + if ( (sbin=sieve_generate(ast)) == NULL ) { + sieve_error(ehandler, sieve_script_name(script), "code generation failed"); sieve_ast_unref(&ast); return NULL; @@ -114,31 +116,21 @@ static struct sieve_binary *sieve_compile_fd /* Cleanup */ sieve_ast_unref(&ast); - return result; + return sbin; } struct sieve_binary *sieve_compile - (const char *scriptpath, struct sieve_error_handler *ehandler) + (const char *script_path, struct sieve_error_handler *ehandler) { - int sfd; - const char *scriptname; + struct sieve_script *script; struct sieve_binary *sbin; + + script = sieve_script_create(script_path, NULL); + sbin = sieve_compile_script(script, ehandler); - if ( (sfd = open(scriptpath, O_RDONLY)) < 0 ) { - sieve_error(ehandler, scriptpath, "failed to open sieve script: %m"); - return NULL; - } - - scriptname = strrchr(scriptpath, '/'); - if ( scriptname == NULL ) - scriptname = scriptpath; - else - scriptname++; + sieve_script_unref(&script); - sbin = sieve_compile_fd(sfd, scriptname, ehandler); - - close(sfd); return sbin; } diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h index aa9840e0e77bc5f08937936e036659cd6a24b3ba..3647ee7adb59e5bcc99dfdce0b6fa1f8c0eeee64 100644 --- a/src/lib-sieve/sieve.h +++ b/src/lib-sieve/sieve.h @@ -24,13 +24,15 @@ struct sieve_message_data { }; struct sieve_script_env { + /* Mail-related */ const char *inbox; struct mail_namespace *namespaces; + /* System-related */ const char *username; const char *hostname; const char *postmaster_address; - + /* Callbacks */ /* Interface for sending mail */