diff --git a/src/lib-sieve/sieve-error.c b/src/lib-sieve/sieve-error.c index 79b68208dc260e4071a7030f99d51219f6d7d6e5..2bdb8c422921b5097103f7e2eb878a70427dea5c 100644 --- a/src/lib-sieve/sieve-error.c +++ b/src/lib-sieve/sieve-error.c @@ -12,8 +12,6 @@ #include <stdlib.h> #include <unistd.h> -/* FIXME: There is some overlap with dovecot/src/lib/failures.c */ - /* This should be moved to a sieve-errors-private.h when the need for other * types of (externally defined) error handlers arises. */ @@ -23,12 +21,24 @@ struct sieve_error_handler { 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); }; @@ -37,6 +47,9 @@ void sieve_verror (struct sieve_error_handler *ehandler, const char *location, const char *fmt, va_list args) { + if ( ehandler->log_master ) + i_error("%s: %s", location, t_strdup_vprintf(fmt, args)); + ehandler->verror(ehandler, location, fmt, args); ehandler->errors++; } @@ -45,10 +58,24 @@ void sieve_vwarning (struct sieve_error_handler *ehandler, const char *location, const char *fmt, va_list args) { + if ( ehandler->log_master ) + i_warning("%s: %s", location, t_strdup_vprintf(fmt, args)); + ehandler->vwarning(ehandler, location, fmt, args); ehandler->warnings++; } +void sieve_vinfo + (struct sieve_error_handler *ehandler, const char *location, + const char *fmt, va_list args) +{ + if ( ehandler->log_master ) + i_info("%s: %s", location, t_strdup_vprintf(fmt, args)); + + if ( ehandler->log_info ) + ehandler->vinfo(ehandler, location, fmt, args); +} + unsigned int sieve_get_errors(struct sieve_error_handler *ehandler) { return ehandler->errors; } @@ -57,6 +84,18 @@ unsigned int sieve_get_warnings(struct sieve_error_handler *ehandler) { return ehandler->errors; } +void sieve_error_handler_accept_infolog + (struct sieve_error_handler *ehandler, bool enable) +{ + ehandler->log_info = enable; +} + +void sieve_error_handler_copy_masterlog + (struct sieve_error_handler *ehandler, bool enable) +{ + ehandler->log_master = enable; +} + void sieve_error_handler_free(struct sieve_error_handler **ehandler) { pool_t pool; @@ -89,6 +128,13 @@ static void sieve_stderr_vwarning fprintf(stderr, "%s: warning: %s.\n", location, t_strdup_vprintf(fmt, args)); } +static void sieve_stderr_vinfo +(struct sieve_error_handler *ehandler ATTR_UNUSED, const char *location, + const char *fmt, va_list args) +{ + fprintf(stderr, "%s: info: %s.\n", location, t_strdup_vprintf(fmt, args)); +} + struct sieve_error_handler *sieve_stderr_ehandler_create( void ) { pool_t pool; @@ -105,6 +151,7 @@ struct sieve_error_handler *sieve_stderr_ehandler_create( void ) ehandler->warnings = 0; ehandler->verror = sieve_stderr_verror; ehandler->vwarning = sieve_stderr_vwarning; + ehandler->vinfo = sieve_stderr_vinfo; return ehandler; } @@ -216,6 +263,19 @@ static void sieve_logfile_vwarning sieve_logfile_vprintf(handler, location, "warning", fmt, args); } +static void sieve_logfile_vinfo +(struct sieve_error_handler *ehandler, const char *location, + const char *fmt, va_list args) +{ + struct sieve_logfile_ehandler *handler = + (struct sieve_logfile_ehandler *) ehandler; + + if ( !handler->started ) sieve_logfile_start(handler); + + sieve_logfile_vprintf(handler, location, "info", fmt, args); +} + + static void sieve_logfile_free (struct sieve_error_handler *ehandler) { @@ -241,6 +301,7 @@ struct sieve_error_handler *sieve_logfile_ehandler_create(const char *logfile) ehandler->handler.warnings = 0; ehandler->handler.verror = sieve_logfile_verror; ehandler->handler.vwarning = sieve_logfile_vwarning; + ehandler->handler.vinfo = sieve_logfile_vinfo; ehandler->handler.free = sieve_logfile_free; /* Don't open logfile until something is actually logged. diff --git a/src/lib-sieve/sieve-error.h b/src/lib-sieve/sieve-error.h index db53b4f85f25e03ee5f63646b26182fcad6770e4..5085d7f41fb99b67ccac494ac4824b4a60ac53c7 100644 --- a/src/lib-sieve/sieve-error.h +++ b/src/lib-sieve/sieve-error.h @@ -11,6 +11,9 @@ void sieve_verror void sieve_vwarning (struct sieve_error_handler *ehandler, const char *location, const char *fmt, va_list args); +void sieve_vinfo + (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, @@ -36,6 +39,23 @@ inline static void sieve_warning va_end(args); } +inline static void sieve_info +(struct sieve_error_handler *ehandler, const char *location, + const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + sieve_vinfo(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 + (struct sieve_error_handler *ehandler, bool enable); + unsigned int sieve_get_errors(struct sieve_error_handler *ehandler); unsigned int sieve_get_warnings(struct sieve_error_handler *ehandler); diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c index 623474e5ca3edbbe6d8f3ab6269b7d183686a38e..338ccbe2584069f496b4f9f307cf8b23e2ad0a7f 100644 --- a/src/lib-sieve/sieve-interpreter.c +++ b/src/lib-sieve/sieve-interpreter.c @@ -7,6 +7,7 @@ #include "hash.h" #include "mail-storage.h" +#include "sieve-error.h" #include "sieve-extensions.h" #include "sieve-commands-private.h" #include "sieve-actions.h" @@ -20,6 +21,8 @@ struct sieve_interpreter { pool_t pool; + struct sieve_error_handler *ehandler; + /* Runtime data for extensions */ ARRAY_DEFINE(ext_contexts, void *); @@ -36,7 +39,8 @@ struct sieve_interpreter { struct sieve_runtime_env runenv; }; -struct sieve_interpreter *sieve_interpreter_create(struct sieve_binary *sbin) +struct sieve_interpreter *sieve_interpreter_create +(struct sieve_binary *sbin, struct sieve_error_handler *ehandler) { unsigned int i; int idx; @@ -46,6 +50,7 @@ struct sieve_interpreter *sieve_interpreter_create(struct sieve_binary *sbin) pool = pool_alloconly_create("sieve_interpreter", 4096); interp = p_new(pool, struct sieve_interpreter, 1); interp->pool = pool; + interp->ehandler = ehandler; interp->runenv.interp = interp; interp->runenv.sbin = sbin; @@ -88,40 +93,46 @@ inline pool_t sieve_interpreter_pool(struct sieve_interpreter *interp) /* Error handling */ -/* FIXME: Add support to send errors elsewhere */ - -void sieve_runtime_log - (const struct sieve_runtime_env *runenv, const char *fmt, ...) +/* This is not particularly user friendly, so we might want to consider storing + * the original line numbers of the script in the binary somewhere... + */ +static const char *_get_location(const struct sieve_runtime_env *runenv) { const char *op = runenv->interp->current_op == NULL ? "<<NOOP>>" : runenv->interp->current_op->mnemonic; + return t_strdup_printf("#%08x: %s", runenv->interp->current_op_addr, op); +} + +void sieve_runtime_error + (const struct sieve_runtime_env *runenv, const char *fmt, ...) +{ va_list args; + va_start(args, fmt); + sieve_vinfo(runenv->interp->ehandler, _get_location(runenv), fmt, args); + va_end(args); +} +void sieve_runtime_warning + (const struct sieve_runtime_env *runenv, const char *fmt, ...) +{ + va_list args; - /* Kludgy, needs explict support from liblib.a (something like i_vinfo) */ - i_info("%s at #%08x: %s", op, runenv->interp->current_op_addr, - t_strdup_vprintf(fmt, args)); - + va_start(args, fmt); + sieve_vwarning(runenv->interp->ehandler, _get_location(runenv), fmt, args); va_end(args); } -void sieve_runtime_error +void sieve_runtime_log (const struct sieve_runtime_env *runenv, const char *fmt, ...) -{ - const char *op = runenv->interp->current_op == NULL ? - "<<NOOP>>" : runenv->interp->current_op->mnemonic; +{ va_list args; - va_start(args, fmt); - - /* Kludgy, needs explict support from liblib.a (something like i_vinfo) */ - i_error("%s at #%08x: %s", op, runenv->interp->current_op_addr, - t_strdup_vprintf(fmt, args)); + va_start(args, fmt); + sieve_vinfo(runenv->interp->ehandler, _get_location(runenv), fmt, args); va_end(args); } - /* Extension support */ inline void sieve_interpreter_extension_set_context @@ -265,7 +276,7 @@ bool sieve_interpreter_run sieve_interpreter_reset(interp); if ( is_topmost ) - *result = sieve_result_create(); + *result = sieve_result_create(interp->ehandler); else { sieve_result_ref(*result); } diff --git a/src/lib-sieve/sieve-interpreter.h b/src/lib-sieve/sieve-interpreter.h index 756569e16f3ffcad845e9a632fe6ec27545501a4..6bbc045d3ebe86e363917b5bb9a0f095e4a77966 100644 --- a/src/lib-sieve/sieve-interpreter.h +++ b/src/lib-sieve/sieve-interpreter.h @@ -21,7 +21,8 @@ struct sieve_runtime_env { struct sieve_result *result; }; -struct sieve_interpreter *sieve_interpreter_create(struct sieve_binary *sbin); +struct sieve_interpreter *sieve_interpreter_create + (struct sieve_binary *sbin, struct sieve_error_handler *ehandler); void sieve_interpreter_free(struct sieve_interpreter *interp); inline pool_t sieve_interpreter_pool(struct sieve_interpreter *interp); @@ -41,10 +42,12 @@ inline bool sieve_interpreter_get_test_result /* Error handling */ -void sieve_runtime_log - (const struct sieve_runtime_env *runenv, const char *fmt, ...); void sieve_runtime_error (const struct sieve_runtime_env *runenv, const char *fmt, ...); +void sieve_runtime_warning + (const struct sieve_runtime_env *runenv, const char *fmt, ...); +void sieve_runtime_log + (const struct sieve_runtime_env *runenv, const char *fmt, ...); /* Extension support */ diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c index 57e2a2025dcb34ebbfff080522cf5ae02d7ba7ea..356d97d53b575adb177ce1338a16b58f057cd07e 100644 --- a/src/lib-sieve/sieve-result.c +++ b/src/lib-sieve/sieve-result.c @@ -4,6 +4,7 @@ #include "str-sanitize.h" #include "sieve-common.h" +#include "sieve-error.h" #include "sieve-interpreter.h" #include "sieve-actions.h" #include "sieve-result.h" @@ -37,20 +38,23 @@ struct sieve_result_side_effect { struct sieve_result { pool_t pool; - + struct sieve_error_handler *ehandler; + struct sieve_action_exec_env action_env; struct sieve_result_action *first_action; struct sieve_result_action *last_action; }; -struct sieve_result *sieve_result_create(void) +struct sieve_result *sieve_result_create +(struct sieve_error_handler *ehandler) { pool_t pool; struct sieve_result *result; - + pool = pool_alloconly_create("sieve_result", 4096); result = p_new(pool, struct sieve_result, 1); result->pool = pool; + result->ehandler = ehandler; result->action_env.result = result; result->first_action = NULL; @@ -81,33 +85,29 @@ inline pool_t sieve_result_pool(struct sieve_result *result) /* Logging of result */ -void sieve_result_log +static const char *_get_location(const struct sieve_action_exec_env *aenv) +{ + return t_strdup_printf("msgid=%s", aenv->msgdata->id == NULL ? + "unspecified" : str_sanitize(aenv->msgdata->id, 80)); +} + +void sieve_result_error (const struct sieve_action_exec_env *aenv, const char *fmt, ...) { va_list args; - va_start(args, fmt); - - /* Kludgy, needs explict support from liblib.a (something like i_vinfo) */ - - i_info("msgid=%s: %s", aenv->msgdata->id == NULL ? - "unspecified" : str_sanitize(aenv->msgdata->id, 80), - t_strdup_vprintf(fmt, args)); + va_start(args, fmt); + sieve_verror(aenv->result->ehandler, _get_location(aenv), fmt, args); va_end(args); } -void sieve_result_error +void sieve_result_log (const struct sieve_action_exec_env *aenv, const char *fmt, ...) { va_list args; - va_start(args, fmt); - - /* Kludgy, needs explict support from liblib.a (something like i_vinfo) */ - - i_error("msgid=%s: %s", aenv->msgdata->id == NULL ? - "unspecified" : str_sanitize(aenv->msgdata->id, 80), - t_strdup_vprintf(fmt, args)); + va_start(args, fmt); + sieve_vinfo(aenv->result->ehandler, _get_location(aenv), fmt, args); va_end(args); } diff --git a/src/lib-sieve/sieve-result.h b/src/lib-sieve/sieve-result.h index 166a4b8bff309f4487f70d5b41d7b464ba05866d..ab38bb53d851aa019c138285d98769b0a746275f 100644 --- a/src/lib-sieve/sieve-result.h +++ b/src/lib-sieve/sieve-result.h @@ -7,7 +7,8 @@ struct sieve_result; struct sieve_result_action; struct sieve_side_effects_list; -struct sieve_result *sieve_result_create(void); +struct sieve_result *sieve_result_create + (struct sieve_error_handler *ehandler); void sieve_result_ref(struct sieve_result *result); void sieve_result_unref(struct sieve_result **result); inline pool_t sieve_result_pool(struct sieve_result *result); diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c index 51fef4a831ffaad2d5f40ffbac346d9df260e2a9..5bffec481f6ebe4dedd37ac1a29312d1aba0fb02 100644 --- a/src/lib-sieve/sieve.c +++ b/src/lib-sieve/sieve.c @@ -142,9 +142,9 @@ struct sieve_binary *sieve_compile return sbin; } -void sieve_dump(struct sieve_binary *binary, struct ostream *stream) +void sieve_dump(struct sieve_binary *sbin, struct ostream *stream) { - struct sieve_code_dumper *dumpr = sieve_code_dumper_create(binary); + struct sieve_code_dumper *dumpr = sieve_code_dumper_create(sbin); sieve_code_dumper_run(dumpr, stream); @@ -152,11 +152,13 @@ void sieve_dump(struct sieve_binary *binary, struct ostream *stream) } bool sieve_test - (struct sieve_binary *binary, const struct sieve_message_data *msgdata, - const struct sieve_mail_environment *menv) + (struct sieve_binary *sbin, const struct sieve_message_data *msgdata, + const struct sieve_mail_environment *menv, + struct sieve_error_handler *ehandler) { - struct sieve_result *sres = sieve_result_create(); - struct sieve_interpreter *interp = sieve_interpreter_create(binary); + struct sieve_result *sres = sieve_result_create(ehandler); + struct sieve_interpreter *interp = + sieve_interpreter_create(sbin, ehandler); bool result = TRUE; result = sieve_interpreter_run(interp, msgdata, menv, &sres); @@ -170,11 +172,13 @@ bool sieve_test } bool sieve_execute - (struct sieve_binary *binary, const struct sieve_message_data *msgdata, - const struct sieve_mail_environment *menv) + (struct sieve_binary *sbin, const struct sieve_message_data *msgdata, + const struct sieve_mail_environment *menv, + struct sieve_error_handler *ehandler) { struct sieve_result *sres = NULL; - struct sieve_interpreter *interp = sieve_interpreter_create(binary); + struct sieve_interpreter *interp = + sieve_interpreter_create(sbin, ehandler); bool result = TRUE; result = sieve_interpreter_run(interp, msgdata, menv, &sres); diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h index b66dd33bc3999b3945d0497cce0706e83ef9d17e..e4f755b131cc6034f18ca29c7d73ed390e3b9ef3 100644 --- a/src/lib-sieve/sieve.h +++ b/src/lib-sieve/sieve.h @@ -49,13 +49,16 @@ void sieve_deinit(void); struct sieve_binary *sieve_compile (const char *scriptpath, struct sieve_error_handler *ehandler); -void sieve_dump(struct sieve_binary *binary, struct ostream *stream); + +void sieve_dump(struct sieve_binary *sbin, struct ostream *stream); bool sieve_test - (struct sieve_binary *binary, const struct sieve_message_data *msgdata, - const struct sieve_mail_environment *menv); + (struct sieve_binary *sbin, const struct sieve_message_data *msgdata, + const struct sieve_mail_environment *menv, + struct sieve_error_handler *ehandler); bool sieve_execute - (struct sieve_binary *binary, const struct sieve_message_data *msgdata, - const struct sieve_mail_environment *menv); + (struct sieve_binary *sbin, const struct sieve_message_data *msgdata, + const struct sieve_mail_environment *menv, + struct sieve_error_handler *ehandler); #endif diff --git a/src/plugins/lda-sieve/lda-sieve-plugin.c b/src/plugins/lda-sieve/lda-sieve-plugin.c index 558246b82ddf8a73d2f841e528ac656036ceed5f..fa3580092b26679554e43a1056d9e6c2aa8065c4 100644 --- a/src/plugins/lda-sieve/lda-sieve-plugin.c +++ b/src/plugins/lda-sieve/lda-sieve-plugin.c @@ -95,14 +95,17 @@ static int lda_sieve_run if ( (sbin=sieve_compile(script_path, ehandler)) == NULL ) { i_error("sieve: Failed to compile script. " - "Log should be available as %s.", scriptlog); + "Log should be available as %s", scriptlog); sieve_error_handler_free(&ehandler); t_pop(); return -1; } - sieve_error_handler_free(&ehandler); + /* Log the messages to the system error handlers as well from this moment + * on. + */ + sieve_error_handler_copy_masterlog(ehandler, TRUE); /* Collect necessary message data */ memset(&msgdata, 0, sizeof(msgdata)); @@ -126,12 +129,15 @@ static int lda_sieve_run if ( debug ) i_info("sieve: Executing (in-memory) script %s", script_path); - if ( sieve_execute(sbin, &msgdata, &mailenv) ) { + if ( sieve_execute(sbin, &msgdata, &mailenv, ehandler) ) { i_error("sieve: Failed to execute script"); + + sieve_error_handler_free(&ehandler); t_pop(); return 1; } + sieve_error_handler_free(&ehandler); t_pop(); return -1; } diff --git a/src/sieve-bin/sieve-exec.c b/src/sieve-bin/sieve-exec.c index 19a4c21818495370d6f95b16e1a04e3f53baf8d0..172d81907b6d3cae3d4a821b4e34136ce08f5fc5 100644 --- a/src/sieve-bin/sieve-exec.c +++ b/src/sieve-bin/sieve-exec.c @@ -75,6 +75,7 @@ int main(int argc, char **argv) struct sieve_binary *sbin; struct sieve_message_data msgdata; struct sieve_mail_environment mailenv; + struct sieve_error_handler *ehandler; bin_init(); @@ -184,8 +185,12 @@ int main(int argc, char **argv) mailenv.duplicate_mark = duplicate_mark; mailenv.duplicate_check = duplicate_check; + ehandler = sieve_stderr_ehandler_create(); + /* Run */ - sieve_execute(sbin, &msgdata, &mailenv); + sieve_execute(sbin, &msgdata, &mailenv, ehandler); + + sieve_error_handler_free(&ehandler); bin_close_mail_file(mfd); mail_raw_close(mailr); diff --git a/src/sieve-bin/sieve-test.c b/src/sieve-bin/sieve-test.c index e27b5adea8e2af7dec3aaa5578e11ee22bd17526..8061c9cf2da8eaa1434e24fa437ee0842ddad6e7 100644 --- a/src/sieve-bin/sieve-test.c +++ b/src/sieve-bin/sieve-test.c @@ -35,6 +35,7 @@ int main(int argc, char **argv) struct sieve_binary *sbin; struct sieve_message_data msgdata; struct sieve_mail_environment mailenv; + struct sieve_error_handler *ehandler; bin_init(); @@ -116,9 +117,13 @@ int main(int argc, char **argv) memset(&mailenv, 0, sizeof(mailenv)); mailenv.inbox = "INBOX"; mailenv.username = user; + + ehandler = sieve_stderr_ehandler_create(); /* Run the test */ - (void) sieve_test(sbin, &msgdata, &mailenv); + (void) sieve_test(sbin, &msgdata, &mailenv, ehandler); + + sieve_error_handler_free(&ehandler); bin_close_mail_file(mfd);