diff --git a/TODO b/TODO index d331ef9f32585feb359d4a8f2a18878081c8411f..7c76065a20c599cfccc6eac64e05990a4fd0fceb 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,5 @@ Current: -* Test new enotify extension extensively. * Test new multiscript support extensively. Next (in order of descending priority/precedence): diff --git a/src/lib-sieve/sieve-commands.h b/src/lib-sieve/sieve-commands.h index 9ad11388484eccfc6bb08594371e3103c167f0df..9968c6b57ca113e6a58a89707eaea9525c3dab15 100644 --- a/src/lib-sieve/sieve-commands.h +++ b/src/lib-sieve/sieve-commands.h @@ -73,7 +73,8 @@ void sieve_arg_catenated_string_add_element enum sieve_command_type { SCT_NONE, SCT_COMMAND, - SCT_TEST + SCT_TEST, + SCT_HYBRID }; struct sieve_command { diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c index 09a67e95604f6f0fd1e05d1a2f28352198c9f93b..ffc6b8d71fa34338ac246ed6dbcdd6632cb948e8 100644 --- a/src/lib-sieve/sieve-validator.c +++ b/src/lib-sieve/sieve-validator.c @@ -926,6 +926,7 @@ static bool sieve_validate_command_subtests switch ( ctype ) { case SCT_TEST: /* Spurious test */ + case SCT_HYBRID: sieve_command_validate_error(valdtr, cmd, "the %s %s accepts no sub-tests, but tests are specified", cmd->command->identifier, sieve_command_type_name(cmd->command)); diff --git a/src/testsuite/cmd-test-message.c b/src/testsuite/cmd-test-message.c index 05a4e1be7d85b92ddfd76fca3bcee9f831981d14..c269d02622a9c2665f5d7fa78f97582c1757ded4 100644 --- a/src/testsuite/cmd-test-message.c +++ b/src/testsuite/cmd-test-message.c @@ -30,7 +30,7 @@ static bool cmd_test_message_generate const struct sieve_command cmd_test_message = { "test_message", - SCT_COMMAND, + SCT_HYBRID, 1, 0, FALSE, FALSE, cmd_test_message_registered, NULL, @@ -239,11 +239,14 @@ static bool cmd_test_message_generate /* Emit operation */ sieve_operation_emit_code(cgenv->sbin, test_message_operations[ctx_data->msg_source]); - + + /* Emit is_test flag */ + sieve_binary_emit_byte(cgenv->sbin, ( cmd->ast_node->type == SAT_TEST )); + /* Generate arguments */ if ( !sieve_generate_arguments(cgenv, cmd, NULL) ) return FALSE; - + return TRUE; } @@ -255,7 +258,13 @@ static bool cmd_test_message_smtp_operation_dump (const struct sieve_operation *op ATTR_UNUSED, const struct sieve_dumptime_env *denv, sieve_size_t *address) { - sieve_code_dumpf(denv, "TEST_MESSAGE_SMTP:"); + unsigned int is_test; + + if ( !sieve_binary_read_byte(denv->sbin, address, &is_test) ) + return FALSE; + + sieve_code_dumpf(denv, "TEST_MESSAGE_SMTP (%s):", + ( is_test ? "TEST" : "COMMAND" )); sieve_code_descend(denv); @@ -266,7 +275,13 @@ static bool cmd_test_message_mailbox_operation_dump (const struct sieve_operation *op ATTR_UNUSED, const struct sieve_dumptime_env *denv, sieve_size_t *address) { - sieve_code_dumpf(denv, "TEST_MESSAGE_MAILBOX:"); + unsigned int is_test; + + if ( !sieve_binary_read_byte(denv->sbin, address, &is_test) ) + return FALSE; + + sieve_code_dumpf(denv, "TEST_MESSAGE_MAILBOX (%s):", + ( is_test ? "TEST" : "COMMAND" )); sieve_code_descend(denv); @@ -284,16 +299,45 @@ static int cmd_test_message_smtp_operation_execute const struct sieve_runtime_env *renv, sieve_size_t *address) { sieve_number_t msg_index; + unsigned int is_test = -1; + bool result; + + /* + * Read operands + */ + + /* Is test */ + + if ( !sieve_binary_read_byte(renv->sbin, address, &is_test) ) { + sieve_runtime_trace_error(renv, "invalid is_test flag"); + return SIEVE_EXEC_BIN_CORRUPT; + } /* Index */ + if ( !sieve_opr_number_read(renv, address, &msg_index) ) { sieve_runtime_trace_error(renv, "invalid index operand"); return SIEVE_EXEC_BIN_CORRUPT; } + + /* + * Perform operation + */ - sieve_runtime_trace(renv, "TEST_MESSAGE_SMTP [%d]", msg_index); + sieve_runtime_trace(renv, "TEST_MESSAGE_SMTP (%s) [%d]", + ( is_test ? "TEST" : "COMMAND" ), msg_index); + + result = testsuite_smtp_get(renv, msg_index); - return testsuite_smtp_get(renv, msg_index); + if ( is_test ) { + sieve_interpreter_set_test_result(renv->interp, result); + return SIEVE_EXEC_OK; + } + + if ( !result ) + testsuite_test_failf("no outgoing SMTP message with index %d", msg_index); + + return SIEVE_EXEC_OK; } static int cmd_test_message_mailbox_operation_execute @@ -302,6 +346,17 @@ static int cmd_test_message_mailbox_operation_execute { string_t *folder; sieve_number_t msg_index; + unsigned int is_test = -1; + + /* + * Read operands + */ + + /* Is test */ + if ( !sieve_binary_read_byte(renv->sbin, address, &is_test) ) { + sieve_runtime_trace_error(renv, "invalid is_test flag"); + return SIEVE_EXEC_BIN_CORRUPT; + } /* Folder */ if ( !sieve_opr_string_read(renv, address, &folder) ) { @@ -314,9 +369,13 @@ static int cmd_test_message_mailbox_operation_execute sieve_runtime_trace_error(renv, "invalid index operand"); return SIEVE_EXEC_BIN_CORRUPT; } + + /* + * Perform operation + */ - sieve_runtime_trace(renv, "TEST_MESSAGE_MAILBOX \"%s\" [%d]", - str_c(folder), msg_index); + sieve_runtime_trace(renv, "TEST_MESSAGE_MAILBOX (%s) \"%s\" [%d]", + ( is_test ? "TEST" : "COMMAND" ), str_c(folder), msg_index); /* FIXME: to be implemented */ diff --git a/src/testsuite/testsuite-common.c b/src/testsuite/testsuite-common.c index 824a07960939c4e27741c4164a1cf9240b8d5e9a..b48894025f4732025031ebf1124e094b6f2e4037 100644 --- a/src/testsuite/testsuite-common.c +++ b/src/testsuite/testsuite-common.c @@ -113,18 +113,33 @@ void testsuite_test_start(string_t *name) } void testsuite_test_fail(string_t *reason) +{ + testsuite_test_fail_cstr(str_c(reason)); +} + +void testsuite_test_failf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + testsuite_test_fail_cstr(t_strdup_vprintf(fmt, args)); + + va_end(args); +} + +void testsuite_test_fail_cstr(const char *reason) { if ( str_len(test_name) == 0 ) { - if ( reason == NULL || str_len(reason) == 0 ) + if ( reason == NULL || *reason == '\0' ) printf("%2d: Test FAILED\n", test_index); else - printf("%2d: Test FAILED: %s\n", test_index, str_c(reason)); + printf("%2d: Test FAILED: %s\n", test_index, reason); } else { - if ( reason == NULL || str_len(reason) == 0 ) + if ( reason == NULL || *reason == '\0' ) printf("%2d: Test '%s' FAILED\n", test_index, str_c(test_name)); else printf("%2d: Test '%s' FAILED: %s\n", test_index, - str_c(test_name), str_c(reason)); + str_c(test_name), reason); } str_truncate(test_name, 0); diff --git a/src/testsuite/testsuite-common.h b/src/testsuite/testsuite-common.h index a7f6be0efe2d4383d6932de41d9166dac124ca4b..50b18523ae660ede75844698379f3f6cb9001109 100644 --- a/src/testsuite/testsuite-common.h +++ b/src/testsuite/testsuite-common.h @@ -107,6 +107,9 @@ enum testsuite_operand_code { void testsuite_test_start(string_t *name); void testsuite_test_fail(string_t *reason); +void testsuite_test_failf(const char *fmt, ...) ATTR_FORMAT(1, 2); +void testsuite_test_fail_cstr(const char *reason); + void testsuite_test_succeed(string_t *reason); void testsuite_testcase_fail(const char *reason); diff --git a/src/testsuite/testsuite-smtp.c b/src/testsuite/testsuite-smtp.c index 85307280d76bb31c550ba9e259e32b3074541966..0f26c62ba384d7f19d2b26dde57fd6055a6a1b64 100644 --- a/src/testsuite/testsuite-smtp.c +++ b/src/testsuite/testsuite-smtp.c @@ -110,17 +110,13 @@ bool testsuite_smtp_close(void *handle) * Access */ -int testsuite_smtp_get +bool testsuite_smtp_get (const struct sieve_runtime_env *renv, unsigned int index) { const struct testsuite_smtp_message *smtp_msg; - if ( index >= array_count(&testsuite_smtp_messages) ) { - sieve_runtime_error(renv, - sieve_error_script_location(renv->script, 0), - "no outgoing smtp message with index %d", index); - return SIEVE_EXEC_FAILURE; - } + if ( index >= array_count(&testsuite_smtp_messages) ) + return FALSE; smtp_msg = array_idx(&testsuite_smtp_messages, index); @@ -128,5 +124,5 @@ int testsuite_smtp_get testsuite_envelope_set_sender(smtp_msg->envelope_from); testsuite_envelope_set_recipient(smtp_msg->envelope_to); - return SIEVE_EXEC_OK; + return TRUE; } diff --git a/src/testsuite/testsuite-smtp.h b/src/testsuite/testsuite-smtp.h index e7491e2b43c7adaa2b537c9bd1710d0dab3d40b4..f1e7f38a1d9015e779a6e6885937a3fb4621a225 100644 --- a/src/testsuite/testsuite-smtp.h +++ b/src/testsuite/testsuite-smtp.h @@ -20,7 +20,7 @@ bool testsuite_smtp_close(void *handle); * Access */ -int testsuite_smtp_get +bool testsuite_smtp_get (const struct sieve_runtime_env *renv, unsigned int index); #endif /* __TESTSUITE_SMTP_H */ diff --git a/tests/extensions/enotify/mailto.svtest b/tests/extensions/enotify/mailto.svtest index 5202746b4fabcb33e82f6ce4a25297cc721f34a7..6abd107adf9f55643e7ee366d122c65a4b8d4722 100644 --- a/tests/extensions/enotify/mailto.svtest +++ b/tests/extensions/enotify/mailto.svtest @@ -95,5 +95,68 @@ test "Multiple recipients" { } } +/* + * Duplicate recipients + */ + +test_result_reset; + +test_set "message" text: +From: stephan@rename-it.nl +To: nico@vestingbar.nl +Subject: Frop! + +Klutsefluts. +. +; +test "Duplicate recipients" { + notify "mailto:timo@example.com%2cstephan@dovecot.org?cc=stephan@dovecot.org"; + notify "mailto:stephan@rename-it.nl?cc=timo@example.com"; + + if not test_result_execute { + test_fail "failed to execute notify"; + } + + test_message :smtp 0; + + if address "Cc" "stephan@dovecot.org" { + test_fail "duplicate recipient not removed from first message"; + } + + test_message :smtp 1; + + if address "Cc" "timo@example.com" { + test_fail "duplicate recipient not removed from second message"; + } +} + + +/* + * Notifying on automated messages + */ + +test_result_reset; + +test_set "message" text: +From: stephan@rename-it.nl +To: nico@vestingbar.nl +Auto-submitted: auto-notify +Subject: Frop! + +Klutsefluts. +. +; + +test "Notifying on automated messages" { + notify "mailto:stephan@rename-it.nl?cc=timo@example.com"; + + if not test_result_execute { + test_fail "failed to execute notify"; + } + + if test_message :smtp 0 { + test_fail "notified of auto-submitted message"; + } +}