diff --git a/TODO b/TODO
index 16492e0046d80e47e46ebdd2935d14323298b66a..5b936e9616cb58b5cfc2dca7b7e9a92284df7ac6 100644
--- a/TODO
+++ b/TODO
@@ -2,8 +2,6 @@ Current activities:
 
 * Improve debugging support in the sieve-test tool:
 	- Improve trace debugging towards something more intuitively readable.
-	- Give trace debugging multiple levels of verbosity (e.g. to include more 
-    messy output like value matching).
 
 Next (in order of descending priority/precedence):
 
diff --git a/src/lib-sieve/cmd-discard.c b/src/lib-sieve/cmd-discard.c
index 1d43cb26c7924966930885e3bd764f62e9b0021e..69a6821a6577a6b7915b9dfe18d8f1bba720adb3 100644
--- a/src/lib-sieve/cmd-discard.c
+++ b/src/lib-sieve/cmd-discard.c
@@ -110,7 +110,7 @@ static int cmd_discard_operation_execute
 	/* Source line */
 	source_line = sieve_runtime_get_command_location(renv);
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "discard action");
+	sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "discard action; cancel implicit keep");
 
 	return ( sieve_result_add_action
 		(renv, NULL, &act_discard, NULL, source_line, NULL, 0) >= 0 );
diff --git a/src/lib-sieve/cmd-keep.c b/src/lib-sieve/cmd-keep.c
index 2838fd892a969240b1f6a0ba416dbc65423723d7..27f3782c98a0f03f783e8a103a91f2bfc4ec0990 100644
--- a/src/lib-sieve/cmd-keep.c
+++ b/src/lib-sieve/cmd-keep.c
@@ -102,7 +102,8 @@ static int cmd_keep_operation_execute
 	 * Perform operation
 	 */
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "keep action");
+	sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, 
+		"keep action; store message in default mailbox");
 	
 	/* Add keep action to result. 
 	 */
diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c
index 98f26ae9e4a9f85d751480a151ab005ed0794d76..7f77b0fe9cb677943b22efa568d9e11d06dfe2cb 100644
--- a/src/lib-sieve/cmd-redirect.c
+++ b/src/lib-sieve/cmd-redirect.c
@@ -219,7 +219,8 @@ static int cmd_redirect_operation_execute
 	/* FIXME: perform address normalization if the string is not a string literal
 	 */
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "redirect action (\"%s\")",
+	sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, 
+		"redirect action; forward message to address `%s'",
 		str_sanitize(str_c(redirect), 64));
 	
 	/* Add redirect action to the result */
diff --git a/src/lib-sieve/cmd-stop.c b/src/lib-sieve/cmd-stop.c
index f908285e78df2c87a829fa47eb22cc64b7eca294..a28f9c2ca5e50ac780eaa7eedacaa6b880487363 100644
--- a/src/lib-sieve/cmd-stop.c
+++ b/src/lib-sieve/cmd-stop.c
@@ -77,7 +77,7 @@ static bool cmd_stop_generate
 static int opc_stop_execute
 (const struct sieve_runtime_env *renv,  sieve_size_t *address ATTR_UNUSED)
 {	
-	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "STOP");
+	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "stop");
 	
 	sieve_interpreter_interrupt(renv->interp);
 
diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c
index e81cdbc74e59dfed0697c80f781bef566c85b3ad..97f8fe4726d441b92d6adb1a7bc75ade0bdf326a 100644
--- a/src/lib-sieve/ext-envelope.c
+++ b/src/lib-sieve/ext-envelope.c
@@ -458,6 +458,9 @@ static int ext_envelope_operation_execute
 		(result=sieve_coded_stringlist_next_item(envp_list, &envp_item)) 
 		&& envp_item != NULL ) {
 		const struct sieve_envelope_part *epart;
+
+		sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+            "  matching envelope part `%s'", str_sanitize(str_c(envp_item), 80));
 			
 		if ( (epart=_envelope_part_find(str_c(envp_item))) != NULL ) {
 			const struct sieve_address * const *addresses = NULL;
diff --git a/src/lib-sieve/ext-fileinto.c b/src/lib-sieve/ext-fileinto.c
index 0197c55033a65c6c5703ac75df7040dd6a3576b7..9a1b453ca6f2374549942e2d8a668d17fcf897ee 100644
--- a/src/lib-sieve/ext-fileinto.c
+++ b/src/lib-sieve/ext-fileinto.c
@@ -179,7 +179,7 @@ static int ext_fileinto_operation_execute
 
 	mailbox = str_sanitize(str_c(folder), 64);
 	sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, 
-		"fileinto action (\"%s\")", mailbox);
+		"fileinto action; store message in mailbox `%s'", mailbox);
 		
 	/* Add action to result */	
 	ret = sieve_act_store_add_to_result
diff --git a/src/lib-sieve/ext-reject.c b/src/lib-sieve/ext-reject.c
index 8736b65375b7afc8b9fda49ab5cb8dfd7b291f7c..7251ebffeccfddf99a78efaeee64ced70c07e45a 100644
--- a/src/lib-sieve/ext-reject.c
+++ b/src/lib-sieve/ext-reject.c
@@ -292,10 +292,10 @@ static int ext_reject_operation_execute
 
 	if ( sieve_operation_is(oprtn, ereject_operation) )
 		sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS,
-			"ereject action (\"%s\")", str_sanitize(str_c(reason), 64));
+			"ereject action; reject message with reason `%s'", str_sanitize(str_c(reason), 64));
 	else
 		sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS,
-			"reject action (\"%s\")", str_sanitize(str_c(reason), 64));
+			"reject action; reject message with reason `%s'", str_sanitize(str_c(reason), 64));
 
 	/* Add reject action to the result */
 	pool = sieve_result_pool(renv->result);
diff --git a/src/lib-sieve/sieve-address-parts.c b/src/lib-sieve/sieve-address-parts.c
index d163e8ce79b5f0d574a32723ed5075842b869d2b..9cae114ab05390c45023b515802f9f87f4c43104 100644
--- a/src/lib-sieve/sieve-address-parts.c
+++ b/src/lib-sieve/sieve-address-parts.c
@@ -7,6 +7,7 @@
 #include "hash.h"
 #include "array.h"
 #include "message-address.h"
+#include "str-sanitize.h"
 
 #include "sieve-extensions.h"
 #include "sieve-code.h"
@@ -234,9 +235,13 @@ int sieve_address_match
 (const struct sieve_address_part *addrp, struct sieve_match_context *mctx, 		
 	const char *data)
 {
+	const struct sieve_runtime_env *renv = mctx->runenv;
 	int result = FALSE;
 	const struct message_address *addr;
 
+	sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+            "  matching addresses `%s'", str_sanitize(data, 80));
+
 	T_BEGIN {
 		bool valid = TRUE;
 		const struct message_address *aitem;
diff --git a/src/lib-sieve/sieve-code.c b/src/lib-sieve/sieve-code.c
index 6f15607ac30625aa39a79fb23acb1b4e953b5afd..02cb48415cce1253b3360ce2fd9da441eb28ff5b 100644
--- a/src/lib-sieve/sieve-code.c
+++ b/src/lib-sieve/sieve-code.c
@@ -1058,8 +1058,7 @@ static int opc_jmptrue_execute
 {	
 	bool result = sieve_interpreter_get_test_result(renv->interp);
 	
-	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "jump if true (%s)", 
-		result ? "true" : "false");
+	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "jump if result is true");
 	
 	return sieve_interpreter_program_jump(renv->interp, result);
 }
@@ -1069,8 +1068,7 @@ static int opc_jmpfalse_execute
 {	
 	bool result = sieve_interpreter_get_test_result(renv->interp);
 	
-	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "jump if false (%s)",
-		result ? "true" : "false" );
+	sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "jump if result is false");
 	
 	return sieve_interpreter_program_jump(renv->interp, !result);
 }	
diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c
index 68260ea5b61f3efc09db91d7a7662ee61915103b..3b2c9a074f70d3bd9f180734f7e1fcdda5ea6e12 100644
--- a/src/lib-sieve/sieve-interpreter.c
+++ b/src/lib-sieve/sieve-interpreter.c
@@ -425,10 +425,23 @@ int sieve_interpreter_program_jump
 		jmp_start + jmp_offset > 0 ) 
 	{	
 		if ( jump ) {
-			sieve_runtime_trace_here(renv, SIEVE_TRLVL_COMMANDS, "jump to #%08llx", 
-				(long long unsigned int) jmp_start + jmp_offset);
+			sieve_size_t jmp_addr = jmp_start + jmp_offset;
+
+			if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
+				unsigned int jmp_line = 
+					sieve_runtime_get_source_location(renv, jmp_addr);
+
+				if ( (renv->trace_config.flags & SIEVE_TRFLG_ADDRESSES) > 0 ) {
+					sieve_runtime_trace(renv, 0, "jumping to line %d [%08llx]", 
+						jmp_line, (long long unsigned int) jmp_addr);
+				} else {
+					sieve_runtime_trace(renv, 0, "jumping to line %d", jmp_line);
+				}
+			}
 
-			*address = jmp_start + jmp_offset;
+			*address = jmp_addr;
+		} else {
+			sieve_runtime_trace(renv, 0, "not jumping");	
 		}
 		
 		return SIEVE_EXEC_OK;
diff --git a/src/lib-sieve/sieve-match.c b/src/lib-sieve/sieve-match.c
index 523e1791e81d33d062014267b81a13b5d0191f3e..0d4c8bb937b948efc2e01d0e193f4f170a5556d2 100644
--- a/src/lib-sieve/sieve-match.c
+++ b/src/lib-sieve/sieve-match.c
@@ -61,20 +61,25 @@ int sieve_match_value
 	const struct sieve_runtime_env *renv = mctx->runenv;
 	const struct sieve_match_type *mcht = mctx->match_type;
 	sieve_coded_stringlist_reset(mctx->key_list);
+	bool trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING);
 	bool ok = TRUE;
+	int ret = 0;
 
 	/* Reject unimplemented match-type */
-	if ( mcht->def == NULL || mcht->def->match == NULL )
+	if ( mcht->def == NULL || mcht->def->match == NULL ) {
+		mctx->status = FALSE;
 		return FALSE;
+	}
 
-	sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
-		"  matching value `%s'", str_sanitize(value, 80));
+	if ( trace ) {
+		sieve_runtime_trace(renv, 0,
+			"  matching value `%s'", str_sanitize(value, 80));
+	}
 
 	/* Match to all key values */
 	if ( mcht->def->is_iterative ) {
 		unsigned int key_index = 0;
 		string_t *key_item = NULL;
-		int ret = 0;
 	
 		while ( (ok=sieve_coded_stringlist_next_item(mctx->key_list, &key_item)) 
 			&& key_item != NULL ) {				
@@ -91,8 +96,10 @@ int sieve_match_value
 							ret = mcht->def->match
 								(mctx, value, val_size, key, key_size, key_index);
 						
-							sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
-								"    with key `%s' => %d", str_sanitize(key, 80), ret);
+							if ( trace ) {
+								sieve_runtime_trace(renv, 0,
+									"    with key `%s' => %d", str_sanitize(key, 80), ret);
+							}
 
 							if ( ret != 0 ) break;
 						}
@@ -101,8 +108,10 @@ int sieve_match_value
 					ret = mcht->def->match(mctx, value, val_size, str_c(key_item), 
 							str_len(key_item), key_index);
 
-					sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
-						"    with key `%s' => %d", str_sanitize(str_c(key_item), 80), ret);
+					if ( trace ) {
+						sieve_runtime_trace(renv, 0,
+							"    with key `%s' => %d", str_sanitize(str_c(key_item), 80), ret);
+					}
 				}
 			} T_END;
 			
@@ -112,31 +121,23 @@ int sieve_match_value
 			key_index++;
 		}
 
-		if ( !ok ) 
-			return -1;
-
-		if ( ret < 0 ) 
-			return ret;
-		if ( ret > 0 )
-			return TRUE;
+		if ( !ok ) ret = -1;
 
 	} else {
-		int ret;
-
 		T_BEGIN {
 			ret = mcht->def->match(mctx, value, val_size, NULL, 0, -1);
 		} T_END;
-
-		return ret;
 	}
 
-	return FALSE;
+	mctx->status = ret;
+	return ret;
 }
 
 int sieve_match_end(struct sieve_match_context **mctx)
 {
 	const struct sieve_runtime_env *renv = (*mctx)->runenv;
 	const struct sieve_match_type *mcht = (*mctx)->match_type;
+	int status = (*mctx)->status;
 	int ret = FALSE;
 
 	if ( mcht->def != NULL && mcht->def->match_deinit != NULL ) {
@@ -146,9 +147,11 @@ int sieve_match_end(struct sieve_match_context **mctx)
 	pool_unref(&(*mctx)->pool);
 	*mctx = NULL;
 
+	if ( ret < 0 ) status = ret;
+
 	sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
 		"  finishing match with result: %s", 
-		( ret > 0 ? "true" : ( ret < 0 ? "error" : "false" ) ));
+		( status > 0 ? "true" : ( status < 0 ? "error" : "false" ) ));
 
 	return ret;
 }
diff --git a/src/lib-sieve/sieve-match.h b/src/lib-sieve/sieve-match.h
index cd79c9a00fbba1fda4f8a828ab0b9c1c72fa057c..ed3c1d79c8a1df2f144f0c61b966d68c591646f8 100644
--- a/src/lib-sieve/sieve-match.h
+++ b/src/lib-sieve/sieve-match.h
@@ -25,7 +25,7 @@ struct sieve_match_context {
 
 	struct sieve_coded_stringlist *key_list;
 
-
+	int status;
 	void *data;
 };
 
diff --git a/src/lib-sieve/sieve-runtime-trace.c b/src/lib-sieve/sieve-runtime-trace.c
index b570fa01782390efb4e0f6200bc11054d14c0470..a4bdd8426b8d44c8b8b1ea179499f9e6e4b9a8cc 100644
--- a/src/lib-sieve/sieve-runtime-trace.c
+++ b/src/lib-sieve/sieve-runtime-trace.c
@@ -11,12 +11,13 @@
 #include "sieve-runtime-trace.h"
 
 static inline string_t *_trace_line_new
-(sieve_size_t address, unsigned int cmd_line)
+(const struct sieve_runtime_env *renv, sieve_size_t address, unsigned int cmd_line)
 {
 	string_t *trline;
 	
 	trline = t_str_new(128);
-	str_printfa(trline, "%08llx: ", (unsigned long long) address);
+	if ( (renv->trace_config.flags & SIEVE_TRFLG_ADDRESSES) > 0 )
+		str_printfa(trline, "%08llx: ", (unsigned long long) address);
 	if ( cmd_line > 0 )	
 		str_printfa(trline, "%4d: ", cmd_line); 
 	else
@@ -46,7 +47,7 @@ static inline void _trace_line_print_empty
 void _sieve_runtime_trace_error
 (const struct sieve_runtime_env *renv, const char *fmt, va_list args)
 {
-	string_t *trline = _trace_line_new(renv->pc, 0);
+	string_t *trline = _trace_line_new(renv, renv->pc, 0);
 
 	str_printfa(trline, "%s: #ERROR#: ", sieve_operation_mnemonic(renv->oprtn));
 	str_vprintfa(trline, fmt, args);
@@ -59,7 +60,7 @@ void _sieve_runtime_trace_operand_error
 	const char *field_name, const char *fmt, va_list args)
 {
 	string_t *trline = _trace_line_new
-		(oprnd->address, sieve_runtime_get_source_location(renv, oprnd->address));
+		(renv, oprnd->address, sieve_runtime_get_source_location(renv, oprnd->address));
 
 	str_printfa(trline, "%s: #ERROR#: ", sieve_operation_mnemonic(renv->oprtn));
 
@@ -79,7 +80,7 @@ static inline void _sieve_runtime_trace_vprintf
 (const struct sieve_runtime_env *renv, sieve_size_t address,
 	unsigned int cmd_line, const char *fmt, va_list args)
 {	
-	string_t *trline = _trace_line_new(address, cmd_line);
+	string_t *trline = _trace_line_new(renv, address, cmd_line);
 		
 	str_vprintfa(trline, fmt, args); 
 	
diff --git a/src/lib-sieve/tst-address.c b/src/lib-sieve/tst-address.c
index bdecded82a4dd77dbe43ddd46f4ca8081f9a7662..bf6d83feb81b7da4611e85dc81f0e544bc7eda87 100644
--- a/src/lib-sieve/tst-address.c
+++ b/src/lib-sieve/tst-address.c
@@ -264,6 +264,9 @@ static int tst_address_operation_execute
 		(result=sieve_coded_stringlist_next_item(hdr_list, &hdr_item)) 
 		&& hdr_item != NULL ) {
 		const char *const *headers;
+
+		sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+            "  matching header `%s'", str_sanitize(str_c(hdr_item), 80));
 			
 		if ( mail_get_headers_utf8
 			(renv->msgdata->mail, str_c(hdr_item), &headers) >= 0 ) {	
diff --git a/src/lib-sieve/tst-exists.c b/src/lib-sieve/tst-exists.c
index ee3851ac685f57bc2754499944373f273df96fee..278faf80ceaa69210470494ae4ee35b8eef0dee8 100644
--- a/src/lib-sieve/tst-exists.c
+++ b/src/lib-sieve/tst-exists.c
@@ -1,6 +1,9 @@
 /* Copyright (c) 2002-2010 Dovecot Sieve authors, see the included COPYING file
  */
 
+#include "lib.h"
+#include "str-sanitize.h"
+
 #include "sieve-common.h"
 #include "sieve-commands.h"
 #include "sieve-code.h"
@@ -132,9 +135,13 @@ static int tst_exists_operation_execute
 			
 		if ( mail_get_headers
 			(renv->msgdata->mail, str_c(hdr_item), &headers) < 0 ||
-			headers[0] == NULL ) {	
+			headers[0] == NULL ) {
 			matched = FALSE;				 
-		}
+		}	
+	
+		sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+        	"  header `%s' %s", str_sanitize(str_c(hdr_item), 80),
+			( matched ? "exists" : "missing" ));
 	}
 	
 	/* Set test result for subsequent conditional jump */
diff --git a/src/lib-sieve/tst-header.c b/src/lib-sieve/tst-header.c
index 438b2e42eb2adf0f329b35dbd0f558ec44adaba9..26ce9311f87be65d2105313bb67559a86a9c56d8 100644
--- a/src/lib-sieve/tst-header.c
+++ b/src/lib-sieve/tst-header.c
@@ -1,6 +1,9 @@
 /* Copyright (c) 2002-2010 Dovecot Sieve authors, see the included COPYING file
  */
 
+#include "lib.h"
+#include "str-sanitize.h"
+
 #include "sieve-common.h"
 #include "sieve-commands.h"
 #include "sieve-code.h"
@@ -219,6 +222,9 @@ static int tst_header_operation_execute
 		(result=sieve_coded_stringlist_next_item(hdr_list, &hdr_item)) 
 		&& hdr_item != NULL ) {
 		const char *const *headers;
+
+		sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+			"  matching header `%s'", str_sanitize(str_c(hdr_item), 80));
 			
 		if ( mail_get_headers_utf8
 			(renv->msgdata->mail, str_c(hdr_item), &headers) >= 0 ) {	
diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c
index fe5aa36e49f542d3f9e9742e5190a354e05c12d2..55c05771e1f82ec9313bc76f2bb29a9a9cd5259f 100644
--- a/src/sieve-tools/sieve-test.c
+++ b/src/sieve-tools/sieve-test.c
@@ -120,9 +120,9 @@ static void parse_trace_option
 			i_fatal_status(EX_USAGE, "Unknown -tlevel= trace level: %s", lvl);
 		}
 	} else if ( strcmp(tr_option, "debug") == 0 ) {
-		tr_config->flags = SIEVE_TRFLG_DEBUG;
+		tr_config->flags |= SIEVE_TRFLG_DEBUG;
 	} else if ( strcmp(tr_option, "addresses") == 0 ) {
-		tr_config->flags = SIEVE_TRFLG_ADDRESSES;
+		tr_config->flags |= SIEVE_TRFLG_ADDRESSES;
 	} else {
 		i_fatal_status(EX_USAGE, "Unknown -t trace option value: %s", tr_option);
 	}