From e6379fcc4c597c0b56924daa08fc0ce705962d13 Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Fri, 10 Apr 2009 00:56:15 +0200 Subject: [PATCH] Major rework of the multiscript support for better error handling. --- src/lib-sieve/sieve-error-private.h | 2 +- src/lib-sieve/sieve-error.c | 10 +- src/lib-sieve/sieve-result.c | 24 +- src/lib-sieve/sieve-result.h | 2 + src/lib-sieve/sieve-script.c | 6 +- src/lib-sieve/sieve.c | 37 +- src/lib-sieve/sieve.h | 11 +- src/plugins/lda-sieve/lda-sieve-plugin.c | 496 +++++++++++++---------- src/sieve-tools/sieve-test.c | 10 +- 9 files changed, 347 insertions(+), 251 deletions(-) diff --git a/src/lib-sieve/sieve-error-private.h b/src/lib-sieve/sieve-error-private.h index 0a22c4e73..7746e04c1 100644 --- a/src/lib-sieve/sieve-error-private.h +++ b/src/lib-sieve/sieve-error-private.h @@ -13,7 +13,7 @@ struct sieve_error_handler { pool_t pool; int refcount; - + unsigned int max_errors; unsigned int errors; diff --git a/src/lib-sieve/sieve-error.c b/src/lib-sieve/sieve-error.c index 48605df0d..c2f1e628f 100644 --- a/src/lib-sieve/sieve-error.c +++ b/src/lib-sieve/sieve-error.c @@ -235,9 +235,11 @@ void sieve_error_handler_reset(struct sieve_error_handler *ehandler) */ static void sieve_master_verror -(struct sieve_error_handler *ehandler ATTR_UNUSED, const char *location, +(struct sieve_error_handler *ehandler, const char *location, const char *fmt, va_list args) { + if ( ehandler->log_master ) return; + if ( location == NULL || *location == '\0' ) i_error("sieve: %s", t_strdup_vprintf(fmt, args)); else @@ -248,6 +250,8 @@ static void sieve_master_vwarning (struct sieve_error_handler *ehandler ATTR_UNUSED, const char *location, const char *fmt, va_list args) { + if ( ehandler->log_master ) return; + if ( location == NULL || *location == '\0' ) i_warning("sieve: %s", t_strdup_vprintf(fmt, args)); else @@ -258,6 +262,8 @@ static void sieve_master_vinfo (struct sieve_error_handler *ehandler ATTR_UNUSED, const char *location, const char *fmt, va_list args) { + if ( ehandler->log_master ) return; + if ( location == NULL || *location == '\0' ) i_info("sieve: %s", t_strdup_vprintf(fmt, args)); else @@ -286,7 +292,7 @@ struct sieve_error_handler *sieve_master_ehandler_create } struct sieve_error_handler _sieve_system_ehandler_object = { - NULL, 0, 0, 0, 0, + NULL, 0, 0, 0, 0, FALSE, TRUE, sieve_master_verror, diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c index a9a5c0a4e..b1a3ee964 100644 --- a/src/lib-sieve/sieve-result.c +++ b/src/lib-sieve/sieve-result.c @@ -94,9 +94,10 @@ struct sieve_result *sieve_result_create result->pool = pool; p_array_init(&result->ext_contexts, pool, 4); - + + if ( ehandler != NULL ) + sieve_error_handler_ref(ehandler); result->ehandler = ehandler; - sieve_error_handler_ref(ehandler); result->action_env.result = result; @@ -126,7 +127,8 @@ void sieve_result_unref(struct sieve_result **result) if ( (*result)->action_contexts != NULL ) hash_table_destroy(&(*result)->action_contexts); - sieve_error_handler_unref(&(*result)->ehandler); + if ( (*result)->ehandler != NULL ) + sieve_error_handler_unref(&(*result)->ehandler); pool_unref(&(*result)->pool); @@ -144,6 +146,16 @@ struct sieve_error_handler *sieve_result_get_error_handler return result->ehandler; } +void sieve_result_set_error_handler +(struct sieve_result *result, struct sieve_error_handler *ehandler) +{ + if ( result->ehandler != ehandler ) { + sieve_error_handler_ref(ehandler); + sieve_error_handler_unref(&result->ehandler); + result->ehandler = ehandler; + } +} + /* * Extension support */ @@ -178,6 +190,8 @@ void sieve_result_error { va_list args; + if ( aenv->result->ehandler == NULL ) return; + va_start(args, fmt); sieve_verror(aenv->result->ehandler, sieve_action_get_location(aenv), fmt, args); @@ -188,6 +202,8 @@ void sieve_result_warning (const struct sieve_action_exec_env *aenv, const char *fmt, ...) { va_list args; + + if ( aenv->result->ehandler == NULL ) return; va_start(args, fmt); sieve_vwarning(aenv->result->ehandler, sieve_action_get_location(aenv), fmt, @@ -200,6 +216,8 @@ void sieve_result_log { va_list args; + if ( aenv->result->ehandler == NULL ) return; + va_start(args, fmt); sieve_vinfo(aenv->result->ehandler, sieve_action_get_location(aenv), fmt, args); diff --git a/src/lib-sieve/sieve-result.h b/src/lib-sieve/sieve-result.h index 6692f2b13..48fc5836c 100644 --- a/src/lib-sieve/sieve-result.h +++ b/src/lib-sieve/sieve-result.h @@ -29,6 +29,8 @@ pool_t sieve_result_pool(struct sieve_result *result); struct sieve_error_handler *sieve_result_get_error_handler (struct sieve_result *result); +void sieve_result_set_error_handler + (struct sieve_result *result, struct sieve_error_handler *ehandler); /* * Extension support diff --git a/src/lib-sieve/sieve-script.c b/src/lib-sieve/sieve-script.c index 5ec687434..75908ba30 100644 --- a/src/lib-sieve/sieve-script.c +++ b/src/lib-sieve/sieve-script.c @@ -90,7 +90,11 @@ struct sieve_script *sieve_script_init basename = _sieve_scriptfile_get_basename(filename); binpath = t_strconcat(dirpath, "/", basename, ".svbin", NULL); - if ( name != NULL && *name != '\0' ) { + if ( name == NULL ) { + name = basename; + } else if ( *name == '\0' ) { + name = NULL; + } else { basename = name; } diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c index 474b8a296..d54371d08 100644 --- a/src/lib-sieve/sieve.c +++ b/src/lib-sieve/sieve.c @@ -186,8 +186,10 @@ static int sieve_run /* Create result object */ if ( *result == NULL ) *result = sieve_result_create(ehandler); - else + else { sieve_result_ref(*result); + sieve_result_set_error_handler(*result, ehandler); + } /* Run the interpreter */ ret = sieve_interpreter_run(interp, msgdata, senv, *result); @@ -345,7 +347,6 @@ struct sieve_multiscript { struct sieve_result *result; const struct sieve_message_data *msgdata; const struct sieve_script_env *scriptenv; - struct sieve_error_handler *ehandler; int status; bool active; @@ -355,14 +356,13 @@ struct sieve_multiscript { }; struct sieve_multiscript *sieve_multiscript_start_execute -(const struct sieve_message_data *msgdata, const struct sieve_script_env *senv, - struct sieve_error_handler *ehandler) +(const struct sieve_message_data *msgdata, const struct sieve_script_env *senv) { pool_t pool; struct sieve_result *result; struct sieve_multiscript *mscript; - result = sieve_result_create(ehandler); + result = sieve_result_create(NULL); pool = sieve_result_pool(result); sieve_result_set_keep_action(result, NULL); @@ -371,7 +371,6 @@ struct sieve_multiscript *sieve_multiscript_start_execute mscript->result = result; mscript->msgdata = msgdata; mscript->scriptenv = senv; - mscript->ehandler = ehandler; mscript->status = SIEVE_EXEC_OK; mscript->active = TRUE; @@ -380,10 +379,10 @@ struct sieve_multiscript *sieve_multiscript_start_execute struct sieve_multiscript *sieve_multiscript_start_test (const struct sieve_message_data *msgdata, const struct sieve_script_env *senv, - struct sieve_error_handler *ehandler, struct ostream *stream) + struct ostream *stream) { struct sieve_multiscript *mscript = - sieve_multiscript_start_execute(msgdata, senv, ehandler); + sieve_multiscript_start_execute(msgdata, senv); mscript->teststream = stream; @@ -391,10 +390,12 @@ struct sieve_multiscript *sieve_multiscript_start_test } static void sieve_multiscript_test -(struct sieve_multiscript *mscript) +(struct sieve_multiscript *mscript, struct sieve_error_handler *ehandler) { bool keep = FALSE; + sieve_result_set_error_handler(mscript->result, ehandler); + mscript->status = sieve_result_print (mscript->result, mscript->scriptenv, mscript->teststream, &keep); @@ -404,10 +405,12 @@ static void sieve_multiscript_test } static void sieve_multiscript_execute -(struct sieve_multiscript *mscript) +(struct sieve_multiscript *mscript, struct sieve_error_handler *ehandler) { bool keep = FALSE; + sieve_result_set_error_handler(mscript->result, ehandler); + if ( mscript->status > 0 ) mscript->status = sieve_result_execute (mscript->result, mscript->msgdata, mscript->scriptenv, &keep); @@ -422,7 +425,7 @@ static void sieve_multiscript_execute bool sieve_multiscript_run (struct sieve_multiscript *mscript, struct sieve_binary *sbin, - bool final) + struct sieve_error_handler *ehandler, bool final) { if ( !mscript->active ) return FALSE; @@ -431,13 +434,13 @@ bool sieve_multiscript_run /* Run the script */ mscript->status = sieve_run(sbin, &mscript->result, mscript->msgdata, - mscript->scriptenv, mscript->ehandler); + mscript->scriptenv, ehandler); if ( mscript->status >= 0 ) { if ( mscript->teststream != NULL ) - sieve_multiscript_test(mscript); + sieve_multiscript_test(mscript, ehandler); else - sieve_multiscript_execute(mscript); + sieve_multiscript_execute(mscript, ehandler); if ( final ) mscript->active = FALSE; } @@ -453,11 +456,15 @@ int sieve_multiscript_status(struct sieve_multiscript *mscript) return mscript->status; } -int sieve_multiscript_finish(struct sieve_multiscript **mscript) +int sieve_multiscript_finish(struct sieve_multiscript **mscript, + struct sieve_error_handler *ehandler) { struct sieve_result *result = (*mscript)->result; int ret = (*mscript)->status; + if ( ehandler != NULL ) + sieve_result_set_error_handler((*mscript)->result, ehandler); + if ( (*mscript)->active ) { ret = SIEVE_EXEC_FAILURE; diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h index fa236e6a7..7648e8262 100644 --- a/src/lib-sieve/sieve.h +++ b/src/lib-sieve/sieve.h @@ -121,18 +121,19 @@ int sieve_execute struct sieve_multiscript; struct sieve_multiscript *sieve_multiscript_start_execute - (const struct sieve_message_data *msgdata, const struct sieve_script_env *senv, - struct sieve_error_handler *ehandler); + (const struct sieve_message_data *msgdata, const struct sieve_script_env *senv); struct sieve_multiscript *sieve_multiscript_start_test (const struct sieve_message_data *msgdata, const struct sieve_script_env *senv, - struct sieve_error_handler *ehandler, struct ostream *stream); + struct ostream *stream); bool sieve_multiscript_run - (struct sieve_multiscript *mscript, struct sieve_binary *sbin, bool final); + (struct sieve_multiscript *mscript, struct sieve_binary *sbin, + struct sieve_error_handler *ehandler, bool final); int sieve_multiscript_status(struct sieve_multiscript *mscript); -int sieve_multiscript_finish(struct sieve_multiscript **mscript); +int sieve_multiscript_finish + (struct sieve_multiscript **mscript, struct sieve_error_handler *ehandler); /* * Script directory diff --git a/src/plugins/lda-sieve/lda-sieve-plugin.c b/src/plugins/lda-sieve/lda-sieve-plugin.c index 2ca4527c4..727e4bcbd 100644 --- a/src/plugins/lda-sieve/lda-sieve-plugin.c +++ b/src/plugins/lda-sieve/lda-sieve-plugin.c @@ -22,7 +22,8 @@ #define SIEVE_SCRIPT_PATH "~/.dovecot.sieve" -#define LDA_SIEVE_MAX_ERRORS 10 +#define LDA_SIEVE_MAX_USER_ERRORS 10 +#define LDA_SIEVE_MAX_SYSTEM_ERRORS 100 /* * Global variables @@ -53,6 +54,20 @@ static bool lda_sieve_smtp_close(void *handle) * Plugin implementation */ +struct lda_sieve_run_context { + const char *const *script_files; + unsigned int script_count; + + const char *user_script; + + const struct sieve_message_data *msgdata; + const struct sieve_script_env *scriptenv; + + struct sieve_error_handler *user_ehandler; + struct sieve_error_handler *master_ehandler; + const char *userlog; +}; + static const char *lda_sieve_get_path(void) { const char *script_path, *home; @@ -106,35 +121,77 @@ static const char *lda_sieve_get_path(void) return script_path; } +static void lda_sieve_multiscript_get_scriptfiles +(const char *script_path, ARRAY_TYPE(const_string) *scriptfiles) +{ + struct sieve_directory *sdir = sieve_directory_open(script_path); + + if ( sdir != NULL ) { + const char *file; + + while ( (file=sieve_directory_get_scriptfile(sdir)) != NULL ) { + const char *const *scripts; + unsigned int count, i; + + /* Insert into sorted array */ + + scripts = array_get(scriptfiles, &count); + for ( i = 0; i < count; i++ ) { + if ( strcmp(file, scripts[i]) < 0 ) + break; + } + + if ( i == count ) + array_append(scriptfiles, &file, 1); + else + array_insert(scriptfiles, i, &file, 1); + } + + sieve_directory_close(&sdir); + } +} + static int lda_sieve_open -(const char *script_path, struct sieve_error_handler *ehandler, - const char *scriptlog, struct sieve_binary **sbin) +(struct lda_sieve_run_context *srctx, unsigned int script_index, + struct sieve_binary **sbin) { + const char *script_path = srctx->script_files[script_index]; + struct sieve_error_handler *ehandler; + bool user_script = ( script_path == srctx->user_script ); bool exists = TRUE; int ret = 0; + if ( user_script ) + ehandler = srctx->user_ehandler; + else + ehandler = srctx->master_ehandler; + if ( lda_sieve_debug ) - sieve_sys_info("opening script %s", script_path); + sieve_sys_info("opening script %s", script_path); + + sieve_error_handler_reset(ehandler); - if ( (*sbin=sieve_open(script_path, "main script", ehandler, &exists)) + if ( (*sbin=sieve_open(script_path, user_script ? "main script" : NULL, ehandler, &exists)) == NULL ) { ret = sieve_get_errors(ehandler) > 0 ? -1 : 0; - if ( lda_sieve_debug ) { - if ( !exists && ret == 0 ) - sieve_sys_info - ("script file %s is missing; reverting to default delivery", - script_path); - else - sieve_sys_info + if ( !exists && ret == 0 ) { + if ( lda_sieve_debug ) + sieve_sys_info("script file %s is missing", script_path); + } else { + if ( user_script && srctx->userlog != NULL ) { + sieve_sys_error ("failed to open script %s " - "(view logfile %s for more information); " - "reverting to default delivery", - script_path, scriptlog); + "(view logfile %s for more information)", + script_path, srctx->userlog); + } else { + sieve_sys_error + ("failed to open script %s", + script_path); + } } - sieve_error_handler_unref(&ehandler); return ret; } @@ -142,31 +199,41 @@ static int lda_sieve_open } static struct sieve_binary *lda_sieve_recompile -(const char *script_path, struct sieve_error_handler *ehandler, - const char *scriptlog) +(struct lda_sieve_run_context *srctx, unsigned int script_index) { + const char *script_path = srctx->script_files[script_index]; + struct sieve_error_handler *ehandler; + bool user_script = ( script_path == srctx->user_script ); struct sieve_binary *sbin; /* Warn */ + sieve_sys_warning("encountered corrupt binary: recompiling script %s", script_path); /* Recompile */ - sieve_error_handler_copy_masterlog(ehandler, FALSE); + if ( user_script ) + ehandler = srctx->user_ehandler; + else + ehandler = srctx->master_ehandler; + + if ( (sbin=sieve_compile(script_path, + user_script ? "main script" : NULL, ehandler)) == NULL ) { + + if ( user_script && srctx->userlog != NULL ) { + sieve_sys_error + ("failed to re-compile script %s " + "(view logfile %s for more information)", + script_path, srctx->userlog); + } else { + sieve_sys_error + ("failed to re-compile script %s", script_path); + } - if ( (sbin=sieve_compile(script_path, NULL, ehandler)) == NULL ) { - sieve_sys_error - ("failed to compile script %s " - "(view logfile %s for more information); " - "reverting to default delivery", - script_path, scriptlog); - sieve_error_handler_unref(&ehandler); return NULL; } - sieve_error_handler_copy_masterlog(ehandler, TRUE); - return sbin; } @@ -202,235 +269,220 @@ static int lda_sieve_handle_exec_status(const char *script_path, int status) } static int lda_sieve_singlescript_execute -(const char *script_path, struct sieve_binary **sbin, - const struct sieve_message_data *msgdata, const struct sieve_script_env *senv, - struct sieve_error_handler *ehandler, const char *scriptlog) +(struct lda_sieve_run_context *srctx) { + const char *script_file = srctx->script_files[0]; + bool user_script = ( script_file == srctx->user_script ); + struct sieve_error_handler *ehandler; + struct sieve_binary *sbin; int ret; - if ( lda_sieve_debug ) - sieve_sys_info("executing compiled script %s", script_path); + /* Open the script */ + + if ( (ret=lda_sieve_open(srctx, 0, &sbin)) <= 0 ) + return ret; /* Execute */ - ret = sieve_execute(*sbin, msgdata, senv, ehandler); + if ( lda_sieve_debug ) + sieve_sys_info("executing compiled script %s", script_file); + + if ( user_script ) { + ehandler = srctx->user_ehandler; + sieve_error_handler_copy_masterlog(ehandler, TRUE); + } else { + ehandler = srctx->master_ehandler; + } + + ret = sieve_execute(sbin, srctx->msgdata, srctx->scriptenv, ehandler); + + sieve_error_handler_copy_masterlog(ehandler, FALSE); - /* Recompile corrupt binary */ + /* Recompile if corrupt binary */ if ( ret == SIEVE_EXEC_BIN_CORRUPT ) { /* Close corrupt script */ - sieve_close(sbin); + + sieve_close(&sbin); /* Recompile */ - if ( (*sbin=lda_sieve_recompile(script_path, ehandler, scriptlog)) == NULL ) + + if ( (sbin=lda_sieve_recompile(srctx, 0)) == NULL ) { return -1; + } /* Execute again */ - - ret = sieve_execute(*sbin, msgdata, senv, ehandler); + + if ( user_script ) + sieve_error_handler_copy_masterlog(ehandler, TRUE); + + ret = sieve_execute(sbin, srctx->msgdata, srctx->scriptenv, ehandler); + + sieve_error_handler_copy_masterlog(ehandler, FALSE); /* Save new version */ - + if ( ret != SIEVE_EXEC_BIN_CORRUPT ) - sieve_save(*sbin, NULL); + sieve_save(sbin, NULL); } - /* Report status */ + sieve_close(&sbin); - return lda_sieve_handle_exec_status(script_path, ret); + /* Report status */ + return lda_sieve_handle_exec_status(script_file, ret); } -static int lda_sieve_multiscript_execute_script -(struct sieve_multiscript *mscript, const char *script, bool final, - struct sieve_error_handler *ehandler, const char *scriptlog) +static int lda_sieve_multiscript_execute +(struct lda_sieve_run_context *srctx) { - struct sieve_binary *sbin = NULL; - bool more = FALSE; + const char *const *scripts = srctx->script_files; + unsigned int count = srctx->script_count; + struct sieve_multiscript *mscript; + struct sieve_error_handler *ehandler; + const char *last_script; + bool user_script = FALSE; + unsigned int i; + int ret = 1; + bool more = TRUE; - if ( lda_sieve_open(script, ehandler, scriptlog, &sbin) <= 0 ) - return -1; + /* Start execution */ - if ( !(more=sieve_multiscript_run(mscript, sbin, final)) ) { - if ( sieve_multiscript_status(mscript) == SIEVE_EXEC_BIN_CORRUPT ) { - /* Close corrupt script */ - sieve_close(&sbin); + mscript = sieve_multiscript_start_execute(srctx->msgdata, srctx->scriptenv); - /* Recompile */ + /* Execute scripts before main script */ - if ( (sbin=lda_sieve_recompile(script, ehandler, scriptlog)) == NULL ) - return -1; + for ( i = 0; i < count && more; i++ ) { + struct sieve_binary *sbin = NULL; + const char *script_file = scripts[i]; + bool final = ( i == count - 1 ); - /* Execute again */ + user_script = ( script_file == srctx->user_script ); + last_script = script_file; - more = sieve_multiscript_run(mscript, sbin, final); + if ( user_script ) + ehandler = srctx->user_ehandler; + else + ehandler = srctx->master_ehandler; - /* Save new version */ + /* Open */ - if ( more && - sieve_multiscript_status(mscript) != SIEVE_EXEC_BIN_CORRUPT ) - sieve_save(sbin, NULL); - } - } + if ( (ret=lda_sieve_open(srctx, i, &sbin)) <= 0 ) + break; - return (int) more; -} + /* Execute */ -static void lda_sieve_multiscript_get_scriptfiles -(const char *script_path, ARRAY_TYPE(const_string) *scriptfiles) -{ - struct sieve_directory *sdir = sieve_directory_open(script_path); + if ( user_script ) + sieve_error_handler_copy_masterlog(ehandler, TRUE); - if ( sdir != NULL ) { - const char *file; + more = sieve_multiscript_run(mscript, sbin, ehandler, final); - while ( (file=sieve_directory_get_scriptfile(sdir)) != NULL ) { - const char *const *scripts; - unsigned int count, i; - - /* Insert into sorted array */ + sieve_error_handler_copy_masterlog(ehandler, FALSE); - scripts = array_get(scriptfiles, &count); - for ( i = 0; i < count; i++ ) { - if ( strcmp(file, scripts[i]) < 0 ) - break; - } - - if ( i == count ) - array_append(scriptfiles, &file, 1); - else - array_insert(scriptfiles, i, &file, 1); - } - - sieve_directory_close(&sdir); - } -} - -static int lda_sieve_multiscript_execute_scripts -(struct sieve_multiscript *mscript, ARRAY_TYPE(const_string) *scripts, - bool final, struct sieve_error_handler *ehandler, const char *scriptlog, - const char **last_script_r) -{ - const char *const *scriptfiles; - unsigned int count, i; - int ret = 0; - - scriptfiles = array_get(scripts, &count); - for ( i = 0; i < count; i++ ) { - *last_script_r = scriptfiles[i]; - - if ( (ret=lda_sieve_multiscript_execute_script - (mscript, scriptfiles[i], ( final && i == count - 1 ), ehandler, - scriptlog)) <= 0 ) - return ret; - } + if ( !more ) { + if ( sieve_multiscript_status(mscript) == SIEVE_EXEC_BIN_CORRUPT ) { + /* Close corrupt script */ - return 1; -} + sieve_close(&sbin); -static int lda_sieve_multiscript_execute -(const char *script_path, struct sieve_binary **main_sbin, - ARRAY_TYPE (const_string) *scripts_before, - ARRAY_TYPE (const_string) *scripts_after, - const struct sieve_message_data *msgdata, const struct sieve_script_env *senv, - struct sieve_error_handler *ehandler, const char *scriptlog) -{ - /* Multiple scripts */ - struct sieve_multiscript *mscript = sieve_multiscript_start_execute - (msgdata, senv, ehandler); - bool final = (*main_sbin == NULL ) && ( array_count(scripts_after) == 0 ); - const char *last_script = NULL; - int ret = 1; + /* Recompile */ - /* Execute scripts before main script */ - ret = lda_sieve_multiscript_execute_scripts - (mscript, scripts_before, final, ehandler, scriptlog, &last_script); + if ( (sbin=lda_sieve_recompile(srctx, i)) + == NULL ) { + ret = -1; + break; + } - /* Execute main script */ - if ( *main_sbin != NULL && ret > 0 ) { - final = ( array_count(scripts_after) == 0 ); + /* Execute again */ - last_script = script_path; + if ( user_script ) + sieve_error_handler_copy_masterlog(ehandler, TRUE); - if ( !(ret=sieve_multiscript_run(mscript, *main_sbin, final)) ) { + more = sieve_multiscript_run(mscript, sbin, ehandler, final); - if ( sieve_multiscript_status(mscript) == SIEVE_EXEC_BIN_CORRUPT ) { - /* Close corrupt script */ - sieve_close(main_sbin); + sieve_error_handler_copy_masterlog(ehandler, FALSE); - /* Recompile */ - if ( (*main_sbin=lda_sieve_recompile(script_path, ehandler, scriptlog)) - == NULL ) { - ret = -1; - } else { + /* Save new version */ - /* Execute again */ - - ret = sieve_multiscript_run(mscript, *main_sbin, final); - - /* Save new version */ - - if ( sieve_multiscript_status(mscript) != SIEVE_EXEC_BIN_CORRUPT ) - sieve_save(*main_sbin, NULL); - } + if ( more && + sieve_multiscript_status(mscript) != SIEVE_EXEC_BIN_CORRUPT ) + sieve_save(sbin, NULL); } } - } - /* Execute scripts after main script */ - if ( ret > 0 ) - ret = lda_sieve_multiscript_execute_scripts - (mscript, scripts_after, TRUE, ehandler, scriptlog, &last_script); + sieve_close(&sbin); + } /* Finish execution */ - ret = sieve_multiscript_finish(&mscript); + + if ( user_script ) + sieve_error_handler_copy_masterlog(ehandler, TRUE); + + ret = sieve_multiscript_finish(&mscript, ehandler); + + sieve_error_handler_copy_masterlog(ehandler, FALSE); return lda_sieve_handle_exec_status(last_script, ret); } static int lda_sieve_run -(struct mail_namespace *namespaces, struct mail *mail, const char *script_path, - ARRAY_TYPE (const_string) *scripts_before, - ARRAY_TYPE (const_string) *scripts_after, - const char *destaddr, const char *username, const char *mailbox, +(struct mail_namespace *namespaces, struct mail *mail, const char *user_script, + const ARRAY_TYPE (const_string) *scripts_before, + const ARRAY_TYPE (const_string) *scripts_after, + const char *destaddr, const char *username, const char *mailbox, struct mail_storage **storage_r) { + ARRAY_TYPE (const_string) scripts; + + struct lda_sieve_run_context srctx; struct sieve_message_data msgdata; struct sieve_script_env scriptenv; struct sieve_exec_status estatus; - struct sieve_error_handler *ehandler; - struct sieve_binary *sbin = NULL; - const char *scriptlog; int ret = 0; *storage_r = NULL; - /* Create error handler */ + /* Initialize */ - scriptlog = t_strconcat(script_path, ".log", NULL); - ehandler = sieve_logfile_ehandler_create(scriptlog, LDA_SIEVE_MAX_ERRORS); + memset(&srctx, 0, sizeof(srctx)); - /* Open the script */ + /* Compose execution sequence */ + + t_array_init(&scripts, 32); + + array_append_array(&scripts, scripts_before); + + if ( user_script != NULL ) + array_append(&scripts, &user_script, 1); + srctx.user_script = user_script; + + array_append_array(&scripts, scripts_after); - if ( script_path != NULL ) { - if ( (ret=lda_sieve_open(script_path, ehandler, scriptlog, &sbin)) <= 0 ) - return ret; + /* Create error handlers */ + + if ( user_script != NULL ) { + srctx.userlog = t_strconcat(user_script, ".log", NULL); + srctx.user_ehandler = sieve_logfile_ehandler_create(srctx.userlog, LDA_SIEVE_MAX_USER_ERRORS); } - - /* Log the messages to the system error handlers as well from this moment - * on. - */ - sieve_error_handler_copy_masterlog(ehandler, TRUE); + + srctx.master_ehandler = sieve_master_ehandler_create(LDA_SIEVE_MAX_SYSTEM_ERRORS); + sieve_error_handler_accept_infolog(srctx.master_ehandler, TRUE); /* Collect necessary message data */ + memset(&msgdata, 0, sizeof(msgdata)); + msgdata.mail = mail; msgdata.return_path = deliver_get_return_address(mail); msgdata.to_address = destaddr; msgdata.auth_user = username; (void)mail_get_first_header(mail, "Message-ID", &msgdata.id); + srctx.msgdata = &msgdata; + /* Compose script execution environment */ + memset(&scriptenv, 0, sizeof(scriptenv)); + scriptenv.default_mailbox = mailbox; scriptenv.mailbox_autocreate = deliver_set->mailbox_autocreate; scriptenv.mailbox_autosubscribe = deliver_set->mailbox_autosubscribe; @@ -444,13 +496,18 @@ static int lda_sieve_run scriptenv.duplicate_check = duplicate_check; scriptenv.exec_status = &estatus; - if ( array_count(scripts_before) == 0 && array_count(scripts_after) == 0 ) - ret = lda_sieve_singlescript_execute - (script_path, &sbin, &msgdata, &scriptenv, ehandler, scriptlog); + srctx.scriptenv = &scriptenv; + + /* Assign script sequence */ + + srctx.script_files = array_get(&scripts, &srctx.script_count); + + /* Execute script(s) */ + + if ( srctx.script_count == 1 ) + ret = lda_sieve_singlescript_execute(&srctx); else - ret = lda_sieve_multiscript_execute - (script_path, &sbin, scripts_before, scripts_after, &msgdata, - &scriptenv, ehandler, scriptlog); + ret = lda_sieve_multiscript_execute(&srctx); /* Record status */ @@ -458,9 +515,10 @@ static int lda_sieve_run *storage_r = estatus.last_storage; /* Clean up */ - if ( sbin != NULL ) - sieve_close(&sbin); - sieve_error_handler_unref(&ehandler); + + if ( srctx.user_ehandler != NULL ) + sieve_error_handler_unref(&srctx.user_ehandler); + sieve_error_handler_unref(&srctx.master_ehandler); return ret; } @@ -469,7 +527,7 @@ static int lda_sieve_deliver_mail (struct mail_namespace *namespaces, struct mail_storage **storage_r, struct mail *mail, const char *destaddr, const char *mailbox) { - const char *script_path, *sieve_before, *sieve_after; + const char *user_script, *sieve_before, *sieve_after; ARRAY_TYPE (const_string) scripts_before; ARRAY_TYPE (const_string) scripts_after; int ret = 0; @@ -478,59 +536,59 @@ static int lda_sieve_deliver_mail /* Find the personal script to execute */ - script_path = lda_sieve_get_path(); + user_script = lda_sieve_get_path(); + + if ( lda_sieve_debug ) { + if ( user_script == NULL ) + sieve_sys_info("user has no valid personal script"); + else + sieve_sys_info("using sieve path for user's script: %s", user_script); + } /* Check for multiscript */ - t_array_init(&scripts_after, 16); t_array_init(&scripts_before, 16); + t_array_init(&scripts_after, 16); sieve_before = getenv("SIEVE_BEFORE"); sieve_after = getenv("SIEVE_AFTER"); - if ( sieve_before != NULL && *sieve_before != '\0' ) + if ( sieve_before != NULL && *sieve_before != '\0' ) { lda_sieve_multiscript_get_scriptfiles(sieve_before, &scripts_before); + } - if ( sieve_after != NULL && *sieve_after != '\0' ) + if ( sieve_after != NULL && *sieve_after != '\0' ) { lda_sieve_multiscript_get_scriptfiles(sieve_after, &scripts_after); + } + + if ( lda_sieve_debug ) { + const char *const *scriptfiles; + unsigned int count, i; + + scriptfiles = array_get(&scripts_before, &count); + for ( i = 0; i < count; i ++ ) { + sieve_sys_info("executed before user's script(%d): %s", i+1, scriptfiles[i]); + } + + scriptfiles = array_get(&scripts_after, &count); + for ( i = 0; i < count; i ++ ) { + sieve_sys_info("executed after user's script(%d): %s", i+1, scriptfiles[i]); + } + } /* Check whether there are any scripts to execute */ - if ( script_path == NULL && array_count(&scripts_before) == 0 && - array_count(&scripts_after) == 0 ) { - + if ( array_count(&scripts_before) == 0 && array_count(&scripts_before) == 0 && + user_script == NULL ) { if ( lda_sieve_debug ) sieve_sys_info("no scripts to execute: reverting to default delivery."); ret = 0; } else { - - /* Show configuration */ - - if ( lda_sieve_debug ) { - const char *const *scripts; - unsigned int count, i; - - if ( script_path == NULL ) - sieve_sys_info("user has no valid personal script"); - else - sieve_sys_info("using sieve path for user's script: %s", script_path); - - scripts = array_get(&scripts_before, &count); - for ( i = 0; i < count; i ++ ) { - sieve_sys_info("executed before user's script(%d): %s", i+1, scripts[i]); - } - - scripts = array_get(&scripts_after, &count); - for ( i = 0; i < count; i ++ ) { - sieve_sys_info("executed after user's script(%d): %s", i+1, scripts[i]); - } - } - /* Run the script(s) */ - + ret = lda_sieve_run - (namespaces, mail, script_path, &scripts_before, &scripts_after, destaddr, + (namespaces, mail, user_script, &scripts_before, &scripts_after, destaddr, getenv("USER"), mailbox, storage_r); } diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c index 828361ba7..08083d907 100644 --- a/src/sieve-tools/sieve-test.c +++ b/src/sieve-tools/sieve-test.c @@ -305,10 +305,10 @@ int main(int argc, char **argv) if ( execute ) mscript = sieve_multiscript_start_execute - (&msgdata, &scriptenv, ehandler); + (&msgdata, &scriptenv); else mscript = sieve_multiscript_start_test - (&msgdata, &scriptenv, ehandler, teststream); + (&msgdata, &scriptenv, teststream); /* Execute scripts sequentially */ sfiles = array_get(&scriptfiles, &count); @@ -335,7 +335,7 @@ int main(int argc, char **argv) } /* Execute/Test script */ - more = sieve_multiscript_run(mscript, sbin, FALSE); + more = sieve_multiscript_run(mscript, sbin, ehandler, FALSE); } /* Execute/Test main script */ @@ -351,10 +351,10 @@ int main(int argc, char **argv) sbin = main_sbin; main_sbin = NULL; - sieve_multiscript_run(mscript, sbin, TRUE); + sieve_multiscript_run(mscript, sbin, ehandler, TRUE); } - result = sieve_multiscript_finish(&mscript); + result = sieve_multiscript_finish(&mscript, ehandler); ret = ret > 0 ? result : ret; } -- GitLab