diff --git a/doc/man/sieve-filter.1 b/doc/man/sieve-filter.1 index a69710a32b4718828c3762cf1fa2ea92f216ee40..2cac97c46161bafd0676a6f3e402912d389208cd 100644 --- a/doc/man/sieve-filter.1 +++ b/doc/man/sieve-filter.1 @@ -6,7 +6,7 @@ sieve\-filter \- Sieve mailbox filter tool for the Dovecot secure IMAP server features! The behavior described in this manual page represents the design and not necessarily what the tool currently implements. .SH SYNOPSIS -sieve\-filter [\fB\-c\fR \fIconfig-file\fR] [\fIoptions\fR] \fIscript\-file\fR \fIsource\-location\fR \fIsource\-mailbox\fR [\fIinbox\-namespace\fR [\fInamespace\fR ...]] +sieve\-filter [\fB\-c\fR \fIconfig\-file\fR] [\fIoptions\fR] \fIscript\-file\fR \fIsource\-location\fR \fIsource\-mailbox\fR [\fIinbox\-namespace\fR [\fInamespace\fR ...]] .TP \fInamepace\fR = [prefix=]location[;option=value,option=value,...] .TP @@ -66,7 +66,7 @@ Sieve script decides to do so. .SH OPTIONS .TP -\fB\-c\fP \fIconfig-file\fP +\fB\-c\fP \fIconfig\-file\fP Alternative Dovecot configuration file path. .TP \fB\-D\fP \fIsource\-action\fP diff --git a/doc/man/sieve-test.1 b/doc/man/sieve-test.1 index 222abaa60c89cfd48cbe1bb7ee1a2ab6a4248804..4da259539f824d4712e5b25f772dacb259563e5c 100644 --- a/doc/man/sieve-test.1 +++ b/doc/man/sieve-test.1 @@ -3,7 +3,7 @@ sieve\-test \- Sieve script tester for the Dovecot secure IMAP server .SH SYNOPSIS sieve\-test -[\fB\-c\fR \fIconfig-file\fR] +[\fB\-c\fR \fIconfig\-file\fR] [\fB\-C\fR] [\fB\-D\fR] [\fB\-d\fR \fIdump\-file\fR] @@ -13,7 +13,7 @@ sieve\-test [\fB\-m\fR \fIdefault\-mailbox\fR] [\fB\-r\fR \fIrecipient\-address\fR] [\fB\-s\fR \fIscript\-file\fR] -[\fB\-t\fR] +[\fB\-t\fR \fItrace\-option\fR] [\fB\-x\fR "\fIextension extension ...\fR"] \fIscript\-file\fR \fImail\-file\fR .SH DESCRIPTION @@ -45,7 +45,7 @@ with basename and path identical to the specified script. Use the \fB\-C\fP opti behavior by forcing the script to be compiled into a new binary. .SH OPTIONS .TP -\fB\-c\fP \fIconfig-file\fP +\fB\-c\fP \fIconfig\-file\fP Alternative Dovecot configuration file path. .TP \fB\-C\fP @@ -91,9 +91,9 @@ Specify additional scripts to be executed before the main script. Multiple \fB\- allowed and the specified scripts are executed sequentially in the order specified at the command line. .TP -\fB\-t\fP -Enable simple trace debugging; prints all encountered byte code instructions to \fBstdout\fP. This is -currently only intelligible for developers. +\fB\-t\fP \fItrace\-option\fP +Configure runtime trace debugging. Trace debugging provides detailed insight in the operations performed +by the Sieve script. Refer to the trace debugging section below. .TP \fB\-x\fP "\fIextension extension ...\fP" Set the available extensions. The parameter is a space\-separated list of the active extensions. By @@ -105,7 +105,45 @@ or those that are still under development. For example \fB\-x\fP "+imapflags \-enotify" will enable the deprecated imapflags extension along with all extensions that are available by default, except for the enotify extension. -.SH DEBUG SUPPORT + +.SH RUNTIME TRACE DEBUGGING +.PP +Using the \fB-t\fP option, the \fBsieve\-test\fP tool can be configured to print detailed information on +the Sieve script execution. For example, the encountered commands, the performed tests and the matched +values can be printed. +.PP +The \fB\-t\fP option can be specified multiple times. It can be used as follows: + +.TP 2 +\fB\-tlevel=...\fP +Set the verbosity level of the trace debugging. One of the following values can be supplied: +.RS 2 +.TP 3 +\fInone\fP (default) +No trace debugging. +.TP +\fIactions\fP +Only print executed action commands, like keep, fileinto, reject and redirect. +.TP +\fIcommands\fP +Print any command, excluding tests. +.TP +\fItests\fP +Print all commands and performed tests. +.TP +\fImatching\fP +Print all commands, performed tests and the values matched for those tests. +.RE +.TP 2 +\fB\-tdebug\fP +Print debug messages as well. This is usually only useful for developers and produces messy output. +.TP +\fB\-taddresses\fP +Print byte code addresses for the current trace output. Normally, only the current Sieve source code +position is printed. The byte code addresses are equal to those listed in a binary dump produced +using the \fB\-d\fP option or by the \fBsieved(1)\fP command. + +.SH DEBUG SIEVE EXTENSION .PP To improve script debugging, the Sieve command line tools such as \fBsieve\-test\fP support a custom Sieve language extension called 'vnd.dovecot.debug'. It adds the \fBdebug_print\fP command that allows diff --git a/doc/man/sievec.1 b/doc/man/sievec.1 index c89be696a76cf0095a828878e388b2149a5d1979..bce1dc2454b47fef4183c814e52030a77a027c95 100644 --- a/doc/man/sievec.1 +++ b/doc/man/sievec.1 @@ -2,7 +2,7 @@ .SH NAME sievec \- Sieve script compiler for the Dovecot secure IMAP server .SH SYNOPSIS -sievec [\fB\-c\fR \fIconfig-file\fR] [\fB\-d\fR] [\fB\-x\fR "\fIextension extension ...\fR"] \fIscript\-file\fR [\fIout\-file\fR] +sievec [\fB\-c\fR \fIconfig\-file\fR] [\fB\-d\fR] [\fB\-x\fR "\fIextension extension ...\fR"] \fIscript\-file\fR [\fIout\-file\fR] .SH DESCRIPTION .PP The \fBsievec\fP command is part of the Pigeonhole Sieve implementation for the Dovecot secure @@ -43,7 +43,7 @@ for a stored binary file. This output is mainly useful to find bugs in the compi binaries. .SH OPTIONS .TP -\fB\-c\fP \fIconfig-file\fP +\fB\-c\fP \fIconfig\-file\fP Alternative Dovecot configuration file path. .TP \fB\-d\fP diff --git a/doc/man/sieved.1 b/doc/man/sieved.1 index 8bc6143f3832da7c6ee2e233a8ec80fa71de489a..724eea85d0b2097128f1959f3158520a97b61672 100644 --- a/doc/man/sieved.1 +++ b/doc/man/sieved.1 @@ -2,7 +2,7 @@ .SH NAME sieved \- Sieve script binary dump tool for the Dovecot secure IMAP server .SH SYNOPSIS -sieved [\fB\-c\fR \fIconfig-file\fR] [\fB\-x\fR "\fIextension extension ...\fR"] \fIsieve\-binary\fR [\fIout\-file\fR] +sieved [\fB\-c\fR \fIconfig\-file\fR] [\fB\-x\fR "\fIextension extension ...\fR"] \fIsieve\-binary\fR [\fIout\-file\fR] .br .SH DESCRIPTION .PP @@ -34,7 +34,7 @@ new operations and use additional blocks. Therefore, the output of \fBsieved\fP on the language extensions used when compiling the binary. .SH OPTIONS .TP -\fB\-c\fP \fIconfig-file\fP +\fB\-c\fP \fIconfig\-file\fP Alternative Dovecot configuration file path. .TP \fB\-x\fP "\fIextension extension ...\fP" diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c index 9491a270c28e6699c08ce86120699e1a6c3636bc..336685a2c3a863d23322eb2aeb96ead43de949cf 100644 --- a/src/lib-sieve/plugins/include/ext-include-common.c +++ b/src/lib-sieve/plugins/include/ext-include-common.c @@ -566,12 +566,12 @@ int ext_include_execute_include /* If :once modifier is specified, check for duplicate include */ if ( ext_include_runtime_include_mark(ctx, included, once) ) { - sieve_runtime_trace(renv, SIEVE_TRLVL_MINIMUM, + sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, "include: start script '%s' [inc id: %d, block: %d]", sieve_script_name(included->script), include_id, block_id); } else { /* skip */ - sieve_runtime_trace(renv, SIEVE_TRLVL_MINIMUM, + sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, "include: skipped include for script '%s' [inc id: %d, block: %d]; " "already run once", sieve_script_name(included->script), include_id, block_id); @@ -636,7 +636,7 @@ int ext_include_execute_include curctx = curctx->parent; sieve_interpreter_free(&subinterp); - sieve_runtime_trace(renv, SIEVE_TRLVL_MINIMUM, + sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, "include: script '%s' ended [inc id: %d, block: %d]", sieve_script_name(ended_script->script), ended_script->id, sieve_binary_block_get_id(ended_script->block)); @@ -697,7 +697,7 @@ int ext_include_execute_include /* This kills curctx too */ sieve_interpreter_free(&killed_interp); - sieve_runtime_trace(renv, SIEVE_TRLVL_MINIMUM, + sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, "include: script '%s' ended [id: %d, block: %d]", sieve_script_name(ended_script->script), ended_script->id, sieve_binary_block_get_id(ended_script->block)); diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c index d301c266f8f3bf9f616bf9146127fb3ca31d83b2..68260ea5b61f3efc09db91d7a7662ee61915103b 100644 --- a/src/lib-sieve/sieve-interpreter.c +++ b/src/lib-sieve/sieve-interpreter.c @@ -100,7 +100,7 @@ static struct sieve_interpreter *_sieve_interpreter_create interp->runenv.msgdata = msgdata; interp->runenv.scriptenv = senv; interp->runenv.trace_stream = senv->trace_stream; - interp->runenv.trace_level = senv->trace_level; + interp->runenv.trace_config = senv->trace_config; if ( senv->exec_status == NULL ) interp->runenv.exec_status = p_new(interp->pool, struct sieve_exec_status, 1); @@ -509,7 +509,7 @@ int sieve_interpreter_continue ret = sieve_interpreter_operation_execute(interp); if ( ret != SIEVE_EXEC_OK ) { - sieve_runtime_trace(&interp->runenv, SIEVE_TRLVL_MINIMUM, + sieve_runtime_trace(&interp->runenv, SIEVE_TRLVL_NONE, "[[EXECUTION ABORTED]]"); } } diff --git a/src/lib-sieve/sieve-runtime-trace.h b/src/lib-sieve/sieve-runtime-trace.h index e3d427d97300883cda7e429ace4eb3ba0a876ad1..8aa895327f3908c828ce126d29d29500c292b6ae 100644 --- a/src/lib-sieve/sieve-runtime-trace.h +++ b/src/lib-sieve/sieve-runtime-trace.h @@ -13,7 +13,8 @@ static inline bool sieve_runtime_trace_active (const struct sieve_runtime_env *renv, sieve_trace_level_t trace_level) { - return ( renv->trace_stream != NULL && trace_level <= renv->trace_level ); + return ( renv->trace_stream != NULL && + trace_level <= renv->trace_config.level ); } /* Trace errors */ @@ -39,7 +40,8 @@ static inline void sieve_runtime_trace_error va_list args; va_start(args, fmt); - if ( renv->trace_stream != NULL ) + if ( renv->trace_stream != NULL && + renv->trace_config.level > SIEVE_TRLVL_NONE ) _sieve_runtime_trace_error(renv, fmt, args); va_end(args); } @@ -51,7 +53,8 @@ static inline void sieve_runtime_trace_operand_error va_list args; va_start(args, fmt); - if ( renv->trace_stream != NULL ) + if ( renv->trace_stream != NULL && + renv->trace_config.level > SIEVE_TRLVL_NONE ) _sieve_runtime_trace_operand_error(renv, oprnd, field_name, fmt, args); va_end(args); } @@ -73,7 +76,7 @@ static inline void sieve_runtime_trace va_start(args, fmt); - if ( renv->trace_stream != NULL && trace_level <= renv->trace_level ) { + if ( renv->trace_stream != NULL && trace_level <= renv->trace_config.level ) { _sieve_runtime_trace(renv, fmt, args); } @@ -96,7 +99,7 @@ static inline void sieve_runtime_trace_address va_start(args, fmt); - if ( renv->trace_stream != NULL && trace_level <= renv->trace_level ) { + if ( renv->trace_stream != NULL && trace_level <= renv->trace_config.level ) { _sieve_runtime_trace_address(renv, address, fmt, args); } @@ -111,7 +114,7 @@ static inline void sieve_runtime_trace_here va_start(args, fmt); - if ( renv->trace_stream != NULL && trace_level <= renv->trace_level ) { + if ( renv->trace_stream != NULL && trace_level <= renv->trace_config.level ) { _sieve_runtime_trace_address(renv, renv->pc, fmt, args); } @@ -126,14 +129,16 @@ void _sieve_runtime_trace_end(const struct sieve_runtime_env *renv); static inline void sieve_runtime_trace_begin (const struct sieve_runtime_env *renv) { - if ( renv->trace_stream != NULL ) + if ( renv->trace_stream != NULL && + renv->trace_config.level > SIEVE_TRLVL_NONE ) _sieve_runtime_trace_begin(renv); } static inline void sieve_runtime_trace_end (const struct sieve_runtime_env *renv) { - if ( renv->trace_stream != NULL ) + if ( renv->trace_stream != NULL && + renv->trace_config.level > SIEVE_TRLVL_NONE ) _sieve_runtime_trace_end(renv); } diff --git a/src/lib-sieve/sieve-runtime.h b/src/lib-sieve/sieve-runtime.h index ab304dd7b1fabea4fa780f83e0fe59b28b246e6f..26659674ccec313b3b5717537b2cdcd0c2d5ff1d 100644 --- a/src/lib-sieve/sieve-runtime.h +++ b/src/lib-sieve/sieve-runtime.h @@ -37,7 +37,7 @@ struct sieve_runtime_env { /* Runtime tracing */ struct ostream *trace_stream; - sieve_trace_level_t trace_level; + struct sieve_trace_config trace_config; }; #endif /* __SIEVE_RUNTIME_H */ diff --git a/src/lib-sieve/sieve-types.h b/src/lib-sieve/sieve-types.h index 1d026c879464e625349976121f2d571c9310e0e6..205a0e0e6ff9a443a14157f87b9cb5db50542cdd 100644 --- a/src/lib-sieve/sieve-types.h +++ b/src/lib-sieve/sieve-types.h @@ -8,9 +8,6 @@ #include <stdio.h> -/* Enable runtime trace functionality */ -#define SIEVE_RUNTIME_TRACE - /* * Forward declarations */ @@ -49,18 +46,27 @@ struct sieve_message_data { }; /* - * Runtime trace level + * Runtime trace settings */ typedef enum { - SIEVE_TRLVL_MINIMUM, + SIEVE_TRLVL_NONE, SIEVE_TRLVL_ACTIONS, SIEVE_TRLVL_COMMANDS, SIEVE_TRLVL_TESTS, - SIEVE_TRLVL_MATCH, - SIEVE_TRLVL_DEBUG + SIEVE_TRLVL_MATCHING } sieve_trace_level_t; +enum { + SIEVE_TRFLG_DEBUG = (1 << 0), + SIEVE_TRFLG_ADDRESSES = (1 << 1) +}; + +struct sieve_trace_config { + sieve_trace_level_t level; + unsigned int flags; +}; + /* * Script environment * @@ -106,7 +112,7 @@ struct sieve_script_env { /* Runtime trace*/ struct ostream *trace_stream; - sieve_trace_level_t trace_level; + struct sieve_trace_config trace_config; }; #define SIEVE_SCRIPT_DEFAULT_MAILBOX(senv) \ diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c index 166f6ee46140b5a931f504b418917b7a2f57dc2f..fe5aa36e49f542d3f9e9742e5190a354e05c12d2 100644 --- a/src/sieve-tools/sieve-test.c +++ b/src/sieve-tools/sieve-test.c @@ -44,10 +44,10 @@ static void print_help(void) { printf( -"Usage: sieve-test [-c] [-d <dump-filename>] [-e] [-f <envelope-sender>]\n" +"Usage: sieve-test [-C] [-d <dump-filename>] [-e] [-f <envelope-sender>]\n" " [-l <mail-location>] [-m <default-mailbox>]\n" " [-r <recipient-address>] [-s <script-file>]\n" -" [-t] [-P <plugin>] [-x <extensions>]\n" +" [-t <trace-option>] [-P <plugin>] [-x <extensions>]\n" " <script-file> <mail-file>\n" ); } @@ -96,6 +96,38 @@ static void duplicate_mark i_info("marked duplicate for user %s.\n", user); } +/* + * Trace option handling + */ + +static void parse_trace_option +(struct sieve_trace_config *tr_config, const char *tr_option) +{ + if ( strncmp(tr_option, "level=", 6) == 0 ) { + const char *lvl = &tr_option[6]; + + if ( strcmp(lvl, "none") == 0 ) { + tr_config->level = SIEVE_TRLVL_NONE; + } else if ( strcmp(lvl, "actions") == 0 ) { + tr_config->level = SIEVE_TRLVL_ACTIONS; + } else if ( strcmp(lvl, "commands") == 0 ) { + tr_config->level = SIEVE_TRLVL_COMMANDS; + } else if ( strcmp(lvl, "tests") == 0 ) { + tr_config->level = SIEVE_TRLVL_TESTS; + } else if ( strcmp(lvl, "matching") == 0 ) { + tr_config->level = SIEVE_TRLVL_MATCHING; + } else { + i_fatal_status(EX_USAGE, "Unknown -tlevel= trace level: %s", lvl); + } + } else if ( strcmp(tr_option, "debug") == 0 ) { + tr_config->flags = SIEVE_TRFLG_DEBUG; + } else if ( strcmp(tr_option, "addresses") == 0 ) { + tr_config->flags = SIEVE_TRFLG_ADDRESSES; + } else { + i_fatal_status(EX_USAGE, "Unknown -t trace option value: %s", tr_option); + } +} + /* * Tool implementation */ @@ -106,6 +138,7 @@ int main(int argc, char **argv) ARRAY_TYPE (const_string) scriptfiles; const char *scriptfile, *recipient, *sender, *mailbox, *dumpfile, *mailfile, *mailloc; + struct sieve_trace_config tr_config; struct mail *mail; struct sieve_binary *main_sbin, *sbin = NULL; struct sieve_message_data msgdata; @@ -119,12 +152,13 @@ int main(int argc, char **argv) int ret, c; sieve_tool = sieve_tool_init - ("sieve-test", &argc, &argv, "r:f:m:d:l:s:eCtDP:x:u:", FALSE); + ("sieve-test", &argc, &argv, "r:f:m:d:l:s:eCt:DP:x:u:", FALSE); t_array_init(&scriptfiles, 16); /* Parse arguments */ scriptfile = recipient = sender = mailbox = dumpfile = mailfile = mailloc = NULL; + memset(&tr_config, 0, sizeof(tr_config)); while ((c = sieve_tool_getopt(sieve_tool)) > 0) { switch (c) { case 'r': @@ -147,6 +181,9 @@ int main(int argc, char **argv) /* mail location */ mailloc = optarg; break; + case 't': + parse_trace_option(&tr_config, optarg); + break; case 's': /* scriptfile executed before main script */ { @@ -162,9 +199,6 @@ int main(int argc, char **argv) case 'C': force_compile = TRUE; break; - case 't': - trace = TRUE; - break; default: print_help(); i_fatal_status(EX_USAGE, "Unknown argument: %c", c); @@ -253,8 +287,9 @@ int main(int argc, char **argv) scriptenv.smtp_close = sieve_smtp_close; scriptenv.duplicate_mark = duplicate_mark; scriptenv.duplicate_check = duplicate_check; - scriptenv.trace_stream = ( trace ? teststream : NULL ); - scriptenv.trace_level = SIEVE_TRLVL_TESTS; + scriptenv.trace_stream = + ( tr_config.level > SIEVE_TRLVL_NONE ? teststream : NULL ); + scriptenv.trace_config = tr_config; scriptenv.exec_status = &estatus; /* Run the test */ diff --git a/src/testsuite/cmd-test.c b/src/testsuite/cmd-test.c index b60758979ca4a470e4a60bb64bdedb36cc7548f6..00947e75fcceab84f49f0a20b487b954cc0d97d0 100644 --- a/src/testsuite/cmd-test.c +++ b/src/testsuite/cmd-test.c @@ -155,7 +155,7 @@ static int cmd_test_operation_execute if ( !sieve_opr_string_read(renv, address, "test name", &test_name) ) return SIEVE_EXEC_BIN_CORRUPT; - sieve_runtime_trace(renv, SIEVE_TRLVL_MINIMUM, + sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, "** Test start: \"%s\"", str_c(test_name)); testsuite_test_start(test_name); @@ -166,7 +166,7 @@ static int cmd_test_finish_operation_execute (const struct sieve_runtime_env *renv ATTR_UNUSED, sieve_size_t *address ATTR_UNUSED) { - sieve_runtime_trace(renv, SIEVE_TRLVL_MINIMUM, "** Test end"); + sieve_runtime_trace(renv, SIEVE_TRLVL_NONE, "** Test end"); testsuite_test_succeed(NULL); return SIEVE_EXEC_OK; diff --git a/src/testsuite/testsuite-script.c b/src/testsuite/testsuite-script.c index 302734ae1ef9c9fdd5c8c7ef1e391b6eff6c6581..c82031e4022eb1523627460708ee9078e2c452d5 100644 --- a/src/testsuite/testsuite-script.c +++ b/src/testsuite/testsuite-script.c @@ -106,7 +106,7 @@ bool testsuite_script_run(const struct sieve_runtime_env *renv) scriptenv.duplicate_check = NULL; scriptenv.user = renv->scriptenv->user; scriptenv.trace_stream = renv->scriptenv->trace_stream; - scriptenv.trace_level = renv->scriptenv->trace_level; + scriptenv.trace_config = renv->scriptenv->trace_config; result = testsuite_result_get(); diff --git a/src/testsuite/testsuite.c b/src/testsuite/testsuite.c index a1b23f04b3f482c024ebf87323d1c55974ee9196..f4d3eeca96f2e605a8c4a3b28b0b109eacff3019 100644 --- a/src/testsuite/testsuite.c +++ b/src/testsuite/testsuite.c @@ -170,7 +170,7 @@ int main(int argc, char **argv) scriptenv.smtp_open = testsuite_smtp_open; scriptenv.smtp_close = testsuite_smtp_close; scriptenv.trace_stream = ( trace ? o_stream_create_fd(1, 0, FALSE) : NULL ); - scriptenv.trace_level = SIEVE_TRLVL_TESTS; + scriptenv.trace_config.level = SIEVE_TRLVL_TESTS; testsuite_scriptenv = &scriptenv;