From 64fb240c676eb1d01bcc8bc7da4528da0944acf3 Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Sat, 28 Jun 2008 20:04:54 +0200 Subject: [PATCH] Added support for limits on the maximum number of errors collected during compilation. --- TODO | 1 - src/lib-sieve/sieve-error-private.h | 54 ++++++++++--------- src/lib-sieve/sieve-error.c | 67 ++++++++++++++---------- src/lib-sieve/sieve-error.h | 11 ++-- src/lib-sieve/sieve-parser.c | 19 +++++-- src/lib-sieve/sieve-validator.c | 52 ++++++++++-------- src/plugins/lda-sieve/lda-sieve-plugin.c | 8 +-- src/sieve-bin/bin-common.c | 4 +- src/sieve-bin/sieve-exec.c | 2 +- src/sieve-bin/sieve-test.c | 2 +- src/testsuite/testsuite.c | 4 +- 11 files changed, 129 insertions(+), 95 deletions(-) diff --git a/TODO b/TODO index 45762ddde..639bb5b2e 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,4 @@ Next (in order of descending priority/precedence): -* Limit the maximum number of errors. * Finish implementing all extensions supported by cmusieve, except notify. * Make this implementation conform section 2.7.2 of RFC3028 (Comparisons Across Character Sets). diff --git a/src/lib-sieve/sieve-error-private.h b/src/lib-sieve/sieve-error-private.h index c81332c8e..401869a25 100644 --- a/src/lib-sieve/sieve-error-private.h +++ b/src/lib-sieve/sieve-error-private.h @@ -4,35 +4,37 @@ #include "sieve-error.h" struct sieve_error_handler { - pool_t pool; + pool_t pool; int refcount; - - int errors; - int warnings; - - /* Should we copy log to i_error, i_warning and i_info? */ - bool log_master; - - /* Should the errorhandler handle or discard info log? - * (This does not influence the previous setting) - */ - bool log_info; - - void (*verror) - (struct sieve_error_handler *ehandler, const char *location, - const char *fmt, va_list args); - void (*vwarning) - (struct sieve_error_handler *ehandler, const char *location, - const char *fmt, va_list args); - void (*vinfo) - (struct sieve_error_handler *ehandler, const char *location, - const char *fmt, va_list args); - - void (*free) - (struct sieve_error_handler *ehandler); + + unsigned int max_errors; + + unsigned int errors; + unsigned int warnings; + + /* Should we copy log to i_error, i_warning and i_info? */ + bool log_master; + + /* Should the errorhandler handle or discard info log? + * (This does not influence the previous setting) + */ + bool log_info; + + void (*verror) + (struct sieve_error_handler *ehandler, const char *location, + const char *fmt, va_list args); + void (*vwarning) + (struct sieve_error_handler *ehandler, const char *location, + const char *fmt, va_list args); + void (*vinfo) + (struct sieve_error_handler *ehandler, const char *location, + const char *fmt, va_list args); + + void (*free) + (struct sieve_error_handler *ehandler); }; void sieve_error_handler_init - (struct sieve_error_handler *ehandler, pool_t pool); + (struct sieve_error_handler *ehandler, pool_t pool, unsigned int max_errors); #endif /* __SIEVE_ERROR_PRIVATE_H */ diff --git a/src/lib-sieve/sieve-error.c b/src/lib-sieve/sieve-error.c index 616213097..bb7ea165f 100644 --- a/src/lib-sieve/sieve-error.c +++ b/src/lib-sieve/sieve-error.c @@ -25,8 +25,10 @@ void sieve_verror if ( ehandler->log_master ) i_error("sieve: %s: %s", location, t_strdup_vprintf(fmt, args)); - ehandler->verror(ehandler, location, fmt, args); - ehandler->errors++; + if ( sieve_errors_more_allowed(ehandler) ) { + ehandler->verror(ehandler, location, fmt, args); + ehandler->errors++; + } } void sieve_vwarning @@ -85,6 +87,10 @@ unsigned int sieve_get_warnings(struct sieve_error_handler *ehandler) { return ehandler->errors; } +bool sieve_errors_more_allowed(struct sieve_error_handler *ehandler) { + return ehandler->max_errors == 0 || ehandler->errors < ehandler->max_errors; +} + void sieve_error_handler_accept_infolog (struct sieve_error_handler *ehandler, bool enable) { @@ -98,10 +104,12 @@ void sieve_error_handler_copy_masterlog } void sieve_error_handler_init - (struct sieve_error_handler *ehandler, pool_t pool) + (struct sieve_error_handler *ehandler, pool_t pool, unsigned int max_errors) { ehandler->pool = pool; ehandler->refcount = 1; + ehandler->max_errors = max_errors; + ehandler->errors = 0; ehandler->warnings = 0; } @@ -153,7 +161,8 @@ static void sieve_stderr_vinfo fprintf(stderr, "%s: info: %s.\n", location, t_strdup_vprintf(fmt, args)); } -struct sieve_error_handler *sieve_stderr_ehandler_create( void ) +struct sieve_error_handler *sieve_stderr_ehandler_create +(unsigned int max_errors) { pool_t pool; struct sieve_error_handler *ehandler; @@ -163,9 +172,8 @@ struct sieve_error_handler *sieve_stderr_ehandler_create( void ) */ pool = pool_alloconly_create ("stderr_error_handler", sizeof(struct sieve_error_handler)); -// ("stderr_error_handler", 128); ehandler = p_new(pool, struct sieve_error_handler, 1); - sieve_error_handler_init(ehandler, pool); + sieve_error_handler_init(ehandler, pool, max_errors); ehandler->verror = sieve_stderr_verror; ehandler->vwarning = sieve_stderr_vwarning; @@ -177,7 +185,7 @@ struct sieve_error_handler *sieve_stderr_ehandler_create( void ) /* Output errors to a string buffer */ struct sieve_strbuf_ehandler { - struct sieve_error_handler handler; + struct sieve_error_handler handler; string_t *errors; }; @@ -186,8 +194,8 @@ static void sieve_strbuf_verror (struct sieve_error_handler *ehandler, const char *location, const char *fmt, va_list args) { - struct sieve_strbuf_ehandler *handler = - (struct sieve_strbuf_ehandler *) ehandler; + struct sieve_strbuf_ehandler *handler = + (struct sieve_strbuf_ehandler *) ehandler; str_printfa(handler->errors, "%s: error: ", location); str_vprintfa(handler->errors, fmt, args); @@ -198,43 +206,43 @@ static void sieve_strbuf_vwarning (struct sieve_error_handler *ehandler, const char *location, const char *fmt, va_list args) { - struct sieve_strbuf_ehandler *handler = - (struct sieve_strbuf_ehandler *) ehandler; + struct sieve_strbuf_ehandler *handler = + (struct sieve_strbuf_ehandler *) ehandler; str_printfa(handler->errors, "%s: warning: ", location); - str_vprintfa(handler->errors, fmt, args); - str_append(handler->errors, ".\n"); + str_vprintfa(handler->errors, fmt, args); + str_append(handler->errors, ".\n"); } static void sieve_strbuf_vinfo (struct sieve_error_handler *ehandler, const char *location, const char *fmt, va_list args) { - struct sieve_strbuf_ehandler *handler = - (struct sieve_strbuf_ehandler *) ehandler; + struct sieve_strbuf_ehandler *handler = + (struct sieve_strbuf_ehandler *) ehandler; str_printfa(handler->errors, "%s: info: ", location); - str_vprintfa(handler->errors, fmt, args); - str_append(handler->errors, ".\n"); + str_vprintfa(handler->errors, fmt, args); + str_append(handler->errors, ".\n"); } struct sieve_error_handler *sieve_strbuf_ehandler_create -(string_t *strbuf) +(string_t *strbuf, unsigned int max_errors) { - pool_t pool; - struct sieve_strbuf_ehandler *ehandler; + pool_t pool; + struct sieve_strbuf_ehandler *ehandler; - pool = pool_alloconly_create("strbuf_error_handler", 256); - ehandler = p_new(pool, struct sieve_strbuf_ehandler, 1); + pool = pool_alloconly_create("strbuf_error_handler", 256); + ehandler = p_new(pool, struct sieve_strbuf_ehandler, 1); ehandler->errors = strbuf; - sieve_error_handler_init(&ehandler->handler, pool); + sieve_error_handler_init(&ehandler->handler, pool, max_errors); - ehandler->handler.verror = sieve_strbuf_verror; - ehandler->handler.vwarning = sieve_strbuf_vwarning; - ehandler->handler.vinfo = sieve_strbuf_vinfo; + ehandler->handler.verror = sieve_strbuf_verror; + ehandler->handler.vwarning = sieve_strbuf_vwarning; + ehandler->handler.vinfo = sieve_strbuf_vinfo; - return &(ehandler->handler); + return &(ehandler->handler); } /* Output errors to a log file */ @@ -368,14 +376,15 @@ static void sieve_logfile_free } } -struct sieve_error_handler *sieve_logfile_ehandler_create(const char *logfile) +struct sieve_error_handler *sieve_logfile_ehandler_create +(const char *logfile, unsigned int max_errors) { pool_t pool; struct sieve_logfile_ehandler *ehandler; pool = pool_alloconly_create("logfile_error_handler", 256); ehandler = p_new(pool, struct sieve_logfile_ehandler, 1); - sieve_error_handler_init(&ehandler->handler, pool); + sieve_error_handler_init(&ehandler->handler, pool, max_errors); ehandler->handler.verror = sieve_logfile_verror; ehandler->handler.vwarning = sieve_logfile_vwarning; diff --git a/src/lib-sieve/sieve-error.h b/src/lib-sieve/sieve-error.h index 12d462873..4da337d0b 100644 --- a/src/lib-sieve/sieve-error.h +++ b/src/lib-sieve/sieve-error.h @@ -105,13 +105,18 @@ void sieve_error_handler_copy_masterlog unsigned int sieve_get_errors(struct sieve_error_handler *ehandler); unsigned int sieve_get_warnings(struct sieve_error_handler *ehandler); +bool sieve_errors_more_allowed(struct sieve_error_handler *ehandler); + void sieve_error_handler_ref(struct sieve_error_handler *ehandler); void sieve_error_handler_unref(struct sieve_error_handler **ehandler); /* Error handlers */ -struct sieve_error_handler *sieve_stderr_ehandler_create(void); -struct sieve_error_handler *sieve_strbuf_ehandler_create(string_t *strbuf); -struct sieve_error_handler *sieve_logfile_ehandler_create(const char *logfile); +struct sieve_error_handler *sieve_stderr_ehandler_create + (unsigned int max_errors); +struct sieve_error_handler *sieve_strbuf_ehandler_create + (string_t *strbuf, unsigned int max_errors); +struct sieve_error_handler *sieve_logfile_ehandler_create + (const char *logfile, unsigned int max_errors); #endif /* __SIEVE_ERROR_H */ diff --git a/src/lib-sieve/sieve-parser.c b/src/lib-sieve/sieve-parser.c index cb52f0be7..8241ec86b 100644 --- a/src/lib-sieve/sieve-parser.c +++ b/src/lib-sieve/sieve-parser.c @@ -17,6 +17,8 @@ struct sieve_parser { pool_t pool; + bool valid; + struct sieve_script *script; struct sieve_error_handler *ehandler; @@ -48,6 +50,8 @@ inline static void sieve_parser_error } T_END; } + parser->valid = FALSE; + va_end(args); } @@ -85,6 +89,7 @@ struct sieve_parser *sieve_parser_create parser = p_new(pool, struct sieve_parser, 1); parser->pool = pool; + parser->valid = TRUE; parser->ehandler = ehandler; sieve_error_handler_ref(ehandler); @@ -132,7 +137,8 @@ static bool sieve_parse_arguments bool argument = TRUE, result = TRUE; /* Parse arguments */ - while ( argument && result ) { + while ( argument && result && + (parser->valid || sieve_errors_more_allowed(parser->ehandler)) ) { struct sieve_ast_argument *arg; switch ( sieve_lexer_current_token(lexer) ) { @@ -148,7 +154,8 @@ static bool sieve_parse_arguments (arg, sieve_lexer_token_str(lexer), sieve_lexer_current_line(parser->lexer)); sieve_lexer_skip_token(lexer); - while ( sieve_lexer_current_token(lexer) == STT_COMMA ) { + while ( sieve_lexer_current_token(lexer) == STT_COMMA && + (parser->valid || sieve_errors_more_allowed(parser->ehandler)) ) { sieve_lexer_skip_token(lexer); if ( sieve_lexer_current_token(lexer) == STT_STRING ) { @@ -247,7 +254,8 @@ static bool sieve_parse_arguments if ( sieve_parse_arguments(parser, test) ) { /* More tests ? */ - while ( sieve_lexer_current_token(lexer) == STT_COMMA ) { + while ( sieve_lexer_current_token(lexer) == STT_COMMA && + (parser->valid && sieve_errors_more_allowed(parser->ehandler)) ) { sieve_lexer_skip_token(lexer); /* Test starts with identifier */ @@ -316,7 +324,8 @@ static bool sieve_parse_commands struct sieve_lexer *lexer = parser->lexer; bool result = TRUE; - while ( sieve_lexer_current_token(lexer) == STT_IDENTIFIER ) { + while ( sieve_lexer_current_token(lexer) == STT_IDENTIFIER && + (parser->valid || sieve_errors_more_allowed(parser->ehandler)) ) { struct sieve_ast_node *command = sieve_ast_command_create (block, sieve_lexer_token_ident(lexer), sieve_lexer_current_line(parser->lexer)); @@ -407,7 +416,7 @@ bool sieve_parser_run return FALSE; } - return TRUE; + return parser->valid; } parser->ast = NULL; diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c index 12abcb13d..505d9703a 100644 --- a/src/lib-sieve/sieve-validator.c +++ b/src/lib-sieve/sieve-validator.c @@ -819,7 +819,7 @@ static bool sieve_validate_command (struct sieve_validator *validator, struct sieve_ast_node *cmd_node); static bool sieve_validate_command - (struct sieve_validator *validator, struct sieve_ast_node *cmd_node) + (struct sieve_validator *valdtr, struct sieve_ast_node *cmd_node) { enum sieve_ast_type ast_type = sieve_ast_node_type(cmd_node); bool result = TRUE; @@ -830,7 +830,7 @@ static bool sieve_validate_command /* Verify the command specified by this node */ cmd_reg = sieve_validator_find_command_registration - (validator, cmd_node->identifier); + (valdtr, cmd_node->identifier); if ( cmd_reg != NULL && cmd_reg->command != NULL ) { const struct sieve_command *command = cmd_reg->command; @@ -841,7 +841,7 @@ static bool sieve_validate_command (command->type == SCT_TEST && ast_type == SAT_COMMAND) ) { sieve_validator_error( - validator, cmd_node, "attempted to use %s '%s' as %s", + valdtr, cmd_node, "attempted to use %s '%s' as %s", sieve_command_type_name(command), cmd_node->identifier, sieve_ast_type_name(ast_type)); @@ -857,77 +857,85 @@ static bool sieve_validate_command * further error reporting anyway */ if ( command->pre_validate == NULL || - command->pre_validate(validator, ctx) ) { + command->pre_validate(valdtr, ctx) ) { /* Check syntax */ if ( - !sieve_validate_command_arguments(validator, ctx) || + !sieve_validate_command_arguments(valdtr, ctx) || !sieve_validate_command_subtests - (validator, ctx, command->subtests) || + (valdtr, ctx, command->subtests) || (ast_type == SAT_COMMAND && !sieve_validate_command_block - (validator, ctx, command->block_allowed, + (valdtr, ctx, command->block_allowed, command->block_required)) ) { result = FALSE; } else { /* Call command validation function if specified */ if ( command->validate != NULL ) - result = command->validate(validator, ctx) && result; + result = command->validate(valdtr, ctx) && result; } } else result = FALSE; - if ( result ) - result = sieve_validate_arguments_context(validator, ctx); + result = result && sieve_validate_arguments_context(valdtr, ctx); } else result = FALSE; } else { sieve_validator_error( - validator, cmd_node, + valdtr, cmd_node, "unknown %s '%s' (only reported once at first occurence)", sieve_ast_type_name(ast_type), cmd_node->identifier); - sieve_validator_register_unknown_command(validator, cmd_node->identifier); + sieve_validator_register_unknown_command(valdtr, cmd_node->identifier); result = FALSE; } - /* Descend further into the AST */ + /* + * Descend further into the AST + */ - result = sieve_validate_test_list(validator, cmd_node) && result; + /* Tests */ + if ( result || sieve_errors_more_allowed(valdtr->ehandler) ) + result = sieve_validate_test_list(valdtr, cmd_node) && result; - if ( ast_type == SAT_COMMAND ) - result = sieve_validate_block(validator, cmd_node) && result; + /* Command block */ + if ( ast_type == SAT_COMMAND && + (result || sieve_errors_more_allowed(valdtr->ehandler)) ) + result = sieve_validate_block(valdtr, cmd_node) && result; return result; } static bool sieve_validate_test_list - (struct sieve_validator *validator, struct sieve_ast_node *test_list) + (struct sieve_validator *valdtr, struct sieve_ast_node *test_list) { bool result = TRUE; struct sieve_ast_node *test; test = sieve_ast_test_first(test_list); - while ( test != NULL ) { - result = sieve_validate_command(validator, test) && result; + while ( test != NULL && (result || + sieve_errors_more_allowed(valdtr->ehandler))) { + result = sieve_validate_command(valdtr, test) && result; test = sieve_ast_test_next(test); } return result; } -static bool sieve_validate_block(struct sieve_validator *validator, struct sieve_ast_node *block) +static bool sieve_validate_block +(struct sieve_validator *valdtr, struct sieve_ast_node *block) { bool result = TRUE; struct sieve_ast_node *command; T_BEGIN { command = sieve_ast_command_first(block); - while ( command != NULL ) { - result = sieve_validate_command(validator, command) && result; + while ( command != NULL && (result || + sieve_errors_more_allowed(valdtr->ehandler)) ) { + result = sieve_validate_command(valdtr, command) && result; command = sieve_ast_command_next(command); } } T_END; diff --git a/src/plugins/lda-sieve/lda-sieve-plugin.c b/src/plugins/lda-sieve/lda-sieve-plugin.c index 465a0c208..cfc749b59 100644 --- a/src/plugins/lda-sieve/lda-sieve-plugin.c +++ b/src/plugins/lda-sieve/lda-sieve-plugin.c @@ -14,6 +14,8 @@ #define SIEVE_SCRIPT_PATH "~/.dovecot.sieve" +#define LDA_SIEVE_MAX_ERRORS 10 + static deliver_mail_func_t *next_deliver_mail; static const char *lda_sieve_get_path(void) @@ -89,14 +91,14 @@ static int lda_sieve_run int ret = 0; scriptlog = t_strconcat(script_path, ".log", NULL); - ehandler = sieve_logfile_ehandler_create(scriptlog); + ehandler = sieve_logfile_ehandler_create(scriptlog, LDA_SIEVE_MAX_ERRORS); if ( debug ) i_info("sieve: Opening script %s", script_path); if ( (sbin=sieve_open(script_path, ehandler)) == NULL ) { - i_error("sieve: Failed to open script. " - "Log should be available as %s", scriptlog); + i_error("sieve: Failed to open script %s. " + "Log should be available as %s", script_path, scriptlog); sieve_error_handler_unref(&ehandler); return -1; diff --git a/src/sieve-bin/bin-common.c b/src/sieve-bin/bin-common.c index 850f79ade..cfcf717bc 100644 --- a/src/sieve-bin/bin-common.c +++ b/src/sieve-bin/bin-common.c @@ -72,7 +72,7 @@ struct sieve_binary *bin_compile_sieve_script(const char *filename) struct sieve_error_handler *ehandler; struct sieve_binary *sbin; - ehandler = sieve_stderr_ehandler_create(); + ehandler = sieve_stderr_ehandler_create(0); sieve_error_handler_accept_infolog(ehandler, TRUE); if ( (sbin = sieve_compile(filename, ehandler)) == NULL ) { @@ -90,7 +90,7 @@ struct sieve_binary *bin_open_sieve_script(const char *filename) struct sieve_error_handler *ehandler; struct sieve_binary *sbin; - ehandler = sieve_stderr_ehandler_create(); + ehandler = sieve_stderr_ehandler_create(0); sieve_error_handler_accept_infolog(ehandler, TRUE); if ( (sbin = sieve_open(filename, ehandler)) == NULL ) { diff --git a/src/sieve-bin/sieve-exec.c b/src/sieve-bin/sieve-exec.c index 1f927319f..17754310f 100644 --- a/src/sieve-bin/sieve-exec.c +++ b/src/sieve-bin/sieve-exec.c @@ -185,7 +185,7 @@ int main(int argc, char **argv) scriptenv.duplicate_mark = duplicate_mark; scriptenv.duplicate_check = duplicate_check; - ehandler = sieve_stderr_ehandler_create(); + ehandler = sieve_stderr_ehandler_create(0); sieve_error_handler_accept_infolog(ehandler, TRUE); /* Run */ diff --git a/src/sieve-bin/sieve-test.c b/src/sieve-bin/sieve-test.c index 1f75a3a6f..35ac5a398 100644 --- a/src/sieve-bin/sieve-test.c +++ b/src/sieve-bin/sieve-test.c @@ -127,7 +127,7 @@ int main(int argc, char **argv) scriptenv.inbox = "INBOX"; scriptenv.username = user; - ehandler = sieve_stderr_ehandler_create(); + ehandler = sieve_stderr_ehandler_create(0); /* Run the test */ (void) sieve_test(sbin, &msgdata, &scriptenv, ehandler); diff --git a/src/testsuite/testsuite.c b/src/testsuite/testsuite.c index a0c4a5ab7..1d9c2e918 100644 --- a/src/testsuite/testsuite.c +++ b/src/testsuite/testsuite.c @@ -81,7 +81,7 @@ static struct sieve_binary *_compile_sieve_script(const char *filename) struct sieve_error_handler *ehandler; struct sieve_binary *sbin; - ehandler = sieve_stderr_ehandler_create(); + ehandler = sieve_stderr_ehandler_create(0); sieve_error_handler_accept_infolog(ehandler, TRUE); if ( (sbin = sieve_compile(filename, ehandler)) == NULL ) { @@ -178,7 +178,7 @@ int main(int argc, char **argv) scriptenv.inbox = "INBOX"; scriptenv.username = user; - ehandler = sieve_stderr_ehandler_create(); + ehandler = sieve_stderr_ehandler_create(0); /* Run the test */ (void) sieve_test(sbin, &testsuite_msgdata, &scriptenv, ehandler); -- GitLab