diff --git a/TODO b/TODO index 894a41f94d8470c8b9f5148909c7b1f9b2ca10ac..53f6f693c8b11f8c4be0be1eb8b0209ff8132c2e 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,6 @@ Current: * Finish enotify extension: - - Mailto: prevent multiple notifications to a single recipient - Cleanup method API. - Regorous testing * Test new multiscript support extensively. diff --git a/src/lib-sieve/plugins/enotify/ntfy-mailto.c b/src/lib-sieve/plugins/enotify/ntfy-mailto.c index e087018038fab58d31c7f1396aabb50943e48ec5..0376a7a33679af37bd4f4c3450be7a0d8d6d66e1 100644 --- a/src/lib-sieve/plugins/enotify/ntfy-mailto.c +++ b/src/lib-sieve/plugins/enotify/ntfy-mailto.c @@ -39,7 +39,7 @@ * Configuration */ -#define NTFY_MAILTO_MAX_RECIPIENTS 4 +#define NTFY_MAILTO_MAX_RECIPIENTS 8 #define NTFY_MAILTO_MAX_HEADERS 16 #define NTFY_MAILTO_MAX_SUBJECT 256 @@ -344,7 +344,7 @@ static bool _uri_parse_recipients str_append_c(to, ch); } } else { - if ( *p == ':' || *p == ';' || !_is_qchar(*p) ) { + if ( *p == ':' || *p == ';' || *p == ',' || !_is_qchar(*p) ) { _uri_parse_error (nlog, "invalid character '%c' in 'to' part", *p); return FALSE; @@ -758,12 +758,52 @@ static bool ntfy_mailto_runtime_check_operands */ static int ntfy_mailto_action_check_duplicates -(const struct sieve_enotify_log *nlog, void *method_ctx1, void *method_ctx2, - const char *dupl_location) +(const struct sieve_enotify_log *nlog ATTR_UNUSED, + void *method_ctx1, void *method_ctx2, + const char *dupl_location ATTR_UNUSED) { - /* FIXME: kill duplicate recipients */ + struct ntfy_mailto_context *mt_new = + (struct ntfy_mailto_context *) method_ctx1; + struct ntfy_mailto_context *mt_old = + (struct ntfy_mailto_context *) method_ctx2; + const struct ntfy_mailto_recipient *new_rcpts, *old_rcpts; + unsigned int new_count, old_count, i, j; + unsigned int del_start = 0, del_len = 0; + + new_rcpts = array_get(&mt_new->recipients, &new_count); + old_rcpts = array_get(&mt_old->recipients, &old_count); + + for ( i = 0; i < new_count; i++ ) { + for ( j = 0; j < old_count; j++ ) { + if ( strcmp(new_rcpts[i].normalized, old_rcpts[j].normalized) == 0 ) + break; + } + + if ( j == old_count ) { + /* Not duplicate */ + if ( del_len > 0 ) { + /* Perform pending deletion */ + array_delete(&mt_new->recipients, del_start, del_len); + + /* Make sure the loop integrity is maintained */ + i -= del_len; + new_rcpts = array_get(&mt_new->recipients, &new_count); + } + del_len = 0; + } else { + /* Mark deletion */ + if ( del_len == 0 ) + del_start = i; + del_len++; + } + } - return 0; + /* Perform pernding deletion */ + if ( del_len > 0 ) { + array_delete(&mt_new->recipients, del_start, del_len); + } + + return ( array_count(&mt_new->recipients) > 0 ? 0 : 1 ); } /* @@ -814,6 +854,8 @@ static void ntfy_mailto_action_print if ( mtctx->body != NULL ) sieve_result_printf(rpenv, " => body : \n--\n%s\n--\n\n", mtctx->body); + + sieve_result_printf(rpenv, "\n"); } /* diff --git a/tests/extensions/enotify/execute.svtest b/tests/extensions/enotify/execute.svtest index c044e8d0168e5b2449483e3175a301eb7f7a75c0..63b31e89b37db92b9323fa31a497943f4ba69deb 100644 --- a/tests/extensions/enotify/execute.svtest +++ b/tests/extensions/enotify/execute.svtest @@ -1,4 +1,6 @@ require "vnd.dovecot.testsuite"; +require "relational"; + /* * Execution testing (currently just meant to trigger any segfaults) @@ -87,6 +89,10 @@ test "Duplicate recipients" { test_fail "script execute failed"; } + if test_result :count "ne" "2" { + test_fail "second notify action was discarded entirely"; + } + if not test_result_execute { test_fail "result execute failed"; } diff --git a/tests/extensions/enotify/execute/duplicates.sieve b/tests/extensions/enotify/execute/duplicates.sieve index c16796d08d134cb28f5df5767be0f00d3d58c2c4..2bed19aa7ce373fba20fde38db0505ecf5d0c1af 100644 --- a/tests/extensions/enotify/execute/duplicates.sieve +++ b/tests/extensions/enotify/execute/duplicates.sieve @@ -1,4 +1,4 @@ require "enotify"; -notify :message "Incoming stupidity." "mailto:stephan@rename-it.nl"; -notify :message "There it is." "mailto:tss@iki.fi,stephan@rename-it.nl"; +notify :message "Incoming stupidity." "mailto:stephan@rename-it.nl%2cstephan@drunksnipers.com%2cidiot@rename-it.nl"; +notify :message "There it is." "mailto:tss@iki.fi%2cstephan@rename-it.nl%2cidiot@rename-it.nl%2cnico@vestingbar.nl%2cstephan@drunksnipers.com";