From 169dd8d4da784c500194d5f8796e73fbb4dbbe7e Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Fri, 30 Jul 2010 14:53:14 +0200 Subject: [PATCH] Implemented generic string list interface and simplified matching API. --- TODO | 17 +- src/lib-sieve/Makefile.am | 2 + src/lib-sieve/ext-envelope.c | 432 +++++++++++------- src/lib-sieve/mcht-contains.c | 15 +- src/lib-sieve/mcht-is.c | 15 +- src/lib-sieve/mcht-matches.c | 19 +- src/lib-sieve/plugins/body/ext-body-common.c | 96 +++- src/lib-sieve/plugins/body/ext-body-common.h | 24 +- src/lib-sieve/plugins/body/tst-body.c | 90 +--- src/lib-sieve/plugins/date/ext-date-common.c | 147 ++++++ src/lib-sieve/plugins/date/ext-date-common.h | 15 + src/lib-sieve/plugins/date/tst-date.c | 123 ++--- src/lib-sieve/plugins/enotify/cmd-notify.c | 2 +- .../plugins/enotify/ext-enotify-common.c | 19 +- .../plugins/enotify/ext-enotify-common.h | 2 +- .../enotify/tst-notify-method-capability.c | 25 +- .../plugins/enotify/tst-valid-notify-method.c | 12 +- .../plugins/environment/tst-environment.c | 32 +- src/lib-sieve/plugins/imap4flags/cmd-flag.c | 10 +- .../imap4flags/ext-imap4flags-common.c | 176 +++++-- .../imap4flags/ext-imap4flags-common.h | 14 +- src/lib-sieve/plugins/imap4flags/tag-flags.c | 10 +- .../plugins/imap4flags/tst-hasflag.c | 95 +--- .../plugins/mailbox/tst-mailboxexists.c | 20 +- src/lib-sieve/plugins/notify/cmd-denotify.c | 18 +- src/lib-sieve/plugins/notify/cmd-notify.c | 12 +- src/lib-sieve/plugins/regex/mcht-regex.c | 213 +++++---- .../relational/ext-relational-common.h | 6 +- src/lib-sieve/plugins/relational/mcht-count.c | 118 ++--- src/lib-sieve/plugins/relational/mcht-value.c | 27 +- .../plugins/spamvirustest/tst-spamvirustest.c | 37 +- src/lib-sieve/plugins/vacation/cmd-vacation.c | 14 +- src/lib-sieve/plugins/variables/tst-string.c | 110 +++-- src/lib-sieve/sieve-address-parts.c | 138 +++--- src/lib-sieve/sieve-address-parts.h | 12 +- src/lib-sieve/sieve-address.c | 138 ++++++ src/lib-sieve/sieve-address.h | 51 ++- src/lib-sieve/sieve-code.c | 142 +++--- src/lib-sieve/sieve-code.h | 27 +- src/lib-sieve/sieve-common.h | 4 + src/lib-sieve/sieve-match-types.h | 36 +- src/lib-sieve/sieve-match.c | 179 ++++---- src/lib-sieve/sieve-match.h | 29 +- src/lib-sieve/sieve-message.c | 106 +++++ src/lib-sieve/sieve-message.h | 7 + src/lib-sieve/sieve-stringlist.c | 139 ++++++ src/lib-sieve/sieve-stringlist.h | 51 +++ src/lib-sieve/tst-address.c | 59 +-- src/lib-sieve/tst-exists.c | 10 +- src/lib-sieve/tst-header.c | 67 +-- src/testsuite/testsuite-log.c | 77 ++++ src/testsuite/testsuite-log.h | 3 + src/testsuite/testsuite-result.c | 80 ++++ src/testsuite/testsuite-result.h | 3 + src/testsuite/tst-test-error.c | 48 +- src/testsuite/tst-test-multiscript.c | 19 +- src/testsuite/tst-test-result.c | 61 +-- tests/extensions/envelope.svtest | 4 + 58 files changed, 2136 insertions(+), 1321 deletions(-) create mode 100644 src/lib-sieve/sieve-stringlist.c create mode 100644 src/lib-sieve/sieve-stringlist.h diff --git a/TODO b/TODO index 5b936e961..199e8e777 100644 --- a/TODO +++ b/TODO @@ -35,14 +35,15 @@ Next (in order of descending priority/precedence): - Implement proper :content "multipart" behavior - Implement proper :content "message/rfc822" behavior - Build test cases for decoding MIME encodings to UTF-8 +* Implement index extension * Build a sieve tool to filter an entire existing mailbox through a Sieve script: - Add commandline options to fully customize execution - Write manual page * Vacation extension improvements: - - Implement configurable sender exclusion list. - - Implement mechanism for implicitly including an account's aliases in the - vacation command's :addresses list. + - Implement configurable sender exclusion list. + - Implement mechanism for implicitly including an account's aliases in the + vacation command's :addresses list. * Improve error handling. - Implement dropping errors in the user's mailbox as a mail message. * Fix remaining RFC deviations: @@ -69,8 +70,8 @@ Next (in order of descending priority/precedence): them to the user if appropriate/safe. * Implement proper support for ManageSieve SASL ANONYMOUS login. * Test ManageSieve behavior thoroughly: - - Test pipelined behavior - - Test proxy authentication + - Test pipelined behavior + - Test proxy authentication * Code cleanup: - Make address handling more uniform. - Review all FIXMEs @@ -80,11 +81,7 @@ Next (in order of descending priority/precedence): * ## MAKE A THIRD RELEASE (0.3.x) ## -* Implement abstract string list and make matching interface more generic. Use - this to: - - Simplify matching API - - Implement index extension - - Implement extlists extension +* Implement extlists extension as a plugin * Enotify extension: detect use of variable values extracted from the message that are used in the method argument. RFC reports this as a security issue. * Make the sieve storage a base class with (possibly) various implementations, diff --git a/src/lib-sieve/Makefile.am b/src/lib-sieve/Makefile.am index 7e0493f24..509efffda 100644 --- a/src/lib-sieve/Makefile.am +++ b/src/lib-sieve/Makefile.am @@ -91,6 +91,7 @@ libdovecot_sieve_la_SOURCES = \ sieve-result.c \ sieve-error.c \ sieve-objects.c \ + sieve-stringlist.c \ sieve-comparators.c \ sieve-match-types.c \ sieve-address-parts.c \ @@ -136,6 +137,7 @@ headers = \ sieve-error.h \ sieve-error-private.h \ sieve-objects.h \ + sieve-stringlist.h \ sieve-match.h \ sieve-comparators.h \ sieve-match-types.h \ diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c index 1b095776e..7b7465abd 100644 --- a/src/lib-sieve/ext-envelope.c +++ b/src/lib-sieve/ext-envelope.c @@ -18,6 +18,7 @@ #include "sieve-common.h" #include "sieve-extensions.h" #include "sieve-commands.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-address.h" #include "sieve-comparators.h" @@ -176,6 +177,250 @@ static const struct sieve_envelope_part *_envelope_part_find return NULL; } +/* Envelope parts implementation */ + +static const struct sieve_address *const *_from_part_get_addresses +(const struct sieve_runtime_env *renv) +{ + ARRAY_DEFINE(envelope_values, const struct sieve_address *); + const struct sieve_address *address = + sieve_message_get_sender_address(renv->msgctx); + + if ( address != NULL ) { + t_array_init(&envelope_values, 2); + + array_append(&envelope_values, &address, 1); + + (void)array_append_space(&envelope_values); + return array_idx(&envelope_values, 0); + } + + return NULL; +} + +static const char *const *_from_part_get_values +(const struct sieve_runtime_env *renv) +{ + ARRAY_DEFINE(envelope_values, const char *); + + t_array_init(&envelope_values, 2); + + if ( renv->msgdata->return_path != NULL ) { + array_append(&envelope_values, &renv->msgdata->return_path, 1); + } + + (void)array_append_space(&envelope_values); + + return array_idx(&envelope_values, 0); +} + +static const struct sieve_address *const *_to_part_get_addresses +(const struct sieve_runtime_env *renv) +{ + ARRAY_DEFINE(envelope_values, const struct sieve_address *); + const struct sieve_address *address = + sieve_message_get_recipient_address(renv->msgctx); + + if ( address != NULL && address->local_part != NULL ) { + t_array_init(&envelope_values, 2); + + array_append(&envelope_values, &address, 1); + + (void)array_append_space(&envelope_values); + return array_idx(&envelope_values, 0); + } + + return NULL; +} + +static const char *const *_to_part_get_values +(const struct sieve_runtime_env *renv) +{ + ARRAY_DEFINE(envelope_values, const char *); + + t_array_init(&envelope_values, 2); + + if ( renv->msgdata->to_address != NULL ) { + array_append(&envelope_values, &renv->msgdata->to_address, 1); + } + + (void)array_append_space(&envelope_values); + + return array_idx(&envelope_values, 0); +} + + +static const char *const *_auth_part_get_values +(const struct sieve_runtime_env *renv) +{ + ARRAY_DEFINE(envelope_values, const char *); + + t_array_init(&envelope_values, 2); + + if ( renv->msgdata->auth_user != NULL ) + array_append(&envelope_values, &renv->msgdata->auth_user, 1); + + (void)array_append_space(&envelope_values); + + return array_idx(&envelope_values, 0); +} + +/* + * Envelope address list + */ + +/* Forward declarations */ + +static int sieve_envelope_address_list_next_string_item + (struct sieve_stringlist *_strlist, string_t **str_r); +static int sieve_envelope_address_list_next_item + (struct sieve_address_list *_addrlist, struct sieve_address *addr_r, + string_t **unparsed_r); +static void sieve_envelope_address_list_reset + (struct sieve_stringlist *_strlist); + +/* Stringlist object */ + +struct sieve_envelope_address_list { + struct sieve_address_list addrlist; + + struct sieve_stringlist *env_parts; + + const struct sieve_address *const *cur_addresses; + const char * const *cur_values; + + int value_index; +}; + +static struct sieve_address_list *sieve_envelope_address_list_create +(const struct sieve_runtime_env *renv, struct sieve_stringlist *env_parts) +{ + struct sieve_envelope_address_list *addrlist; + + addrlist = t_new(struct sieve_envelope_address_list, 1); + addrlist->addrlist.strlist.runenv = renv; + addrlist->addrlist.strlist.next_item = + sieve_envelope_address_list_next_string_item; + addrlist->addrlist.strlist.reset = sieve_envelope_address_list_reset; + addrlist->addrlist.next_item = sieve_envelope_address_list_next_item; + addrlist->env_parts = env_parts; + + return &addrlist->addrlist; +} + +static int sieve_envelope_address_list_next_item +(struct sieve_address_list *_addrlist, struct sieve_address *addr_r, + string_t **unparsed_r) +{ + struct sieve_envelope_address_list *addrlist = + (struct sieve_envelope_address_list *) _addrlist; + const struct sieve_runtime_env *renv = _addrlist->strlist.runenv; + + if ( addr_r != NULL ) addr_r->local_part = NULL; + if ( unparsed_r != NULL ) *unparsed_r = NULL; + + while ( addrlist->cur_addresses == NULL && addrlist->cur_values == NULL ) { + const struct sieve_envelope_part *epart; + string_t *envp_item = NULL; + int ret; + + /* Read next header value from source list */ + if ( (ret=sieve_stringlist_next_item(addrlist->env_parts, &envp_item)) + <= 0 ) + return ret; + + if ( (epart=_envelope_part_find(str_c(envp_item))) != NULL ) { + addrlist->value_index = 0; + + if ( epart->get_addresses != NULL ) { + /* Field contains addresses */ + addrlist->cur_addresses = epart->get_addresses(renv); + + /* Drop empty list */ + if ( addrlist->cur_addresses != NULL && + addrlist->cur_addresses[0] == NULL ) + addrlist->cur_addresses = NULL; + } + + if ( addrlist->cur_addresses == NULL && epart->get_values != NULL ) { + /* Field contains something else */ + addrlist->cur_values = epart->get_values(renv); + + /* Drop empty list */ + if ( addrlist->cur_values != NULL && addrlist->cur_values[0] == NULL ) + addrlist->cur_values = NULL; + } + } + } + + /* Return next item */ + if ( addrlist->cur_addresses != NULL ) { + const struct sieve_address *addr = + addrlist->cur_addresses[addrlist->value_index]; + + if ( addr->local_part == NULL ) { + /* Null path <> */ + if ( unparsed_r != NULL ) + *unparsed_r = t_str_new_const("", 0); + } else { + if ( addr_r != NULL ) + *addr_r = *addr; + } + + /* Advance to next value */ + addrlist->value_index++; + if ( addrlist->cur_addresses[addrlist->value_index] == NULL ) { + addrlist->cur_addresses = NULL; + addrlist->value_index = 0; + } + } else { + if ( unparsed_r != NULL ) { + const char *value = addrlist->cur_values[addrlist->value_index]; + + *unparsed_r = t_str_new_const(value, strlen(value)); + } + + /* Advance to next value */ + addrlist->value_index++; + if ( addrlist->cur_values[addrlist->value_index] == NULL ) { + addrlist->cur_values = NULL; + addrlist->value_index = 0; + } + } + + return 1; +} + +static int sieve_envelope_address_list_next_string_item +(struct sieve_stringlist *_strlist, string_t **str_r) +{ + struct sieve_address_list *addrlist = (struct sieve_address_list *)_strlist; + struct sieve_address addr; + int ret; + + if ( (ret=sieve_envelope_address_list_next_item + (addrlist, &addr, str_r)) <= 0 ) + return ret; + + if ( addr.local_part != NULL ) { + const char *addr_str = sieve_address_to_string(&addr); + *str_r = t_str_new_const(addr_str, strlen(addr_str)); + } + + return 1; +} + +static void sieve_envelope_address_list_reset +(struct sieve_stringlist *_strlist) +{ + struct sieve_envelope_address_list *addrlist = + (struct sieve_envelope_address_list *)_strlist; + + sieve_stringlist_reset(addrlist->env_parts); + addrlist->cur_addresses = NULL; + addrlist->cur_values = NULL; + addrlist->value_index = 0; +} /* * Command Registration @@ -320,107 +565,17 @@ static bool ext_envelope_operation_dump * Interpretation */ -static const struct sieve_address *const *_from_part_get_addresses -(const struct sieve_runtime_env *renv) -{ - ARRAY_DEFINE(envelope_values, const struct sieve_address *); - const struct sieve_address *address = - sieve_message_get_sender_address(renv->msgctx); - - if ( address != NULL ) { - t_array_init(&envelope_values, 2); - - array_append(&envelope_values, &address, 1); - - (void)array_append_space(&envelope_values); - return array_idx(&envelope_values, 0); - } - - return NULL; -} - -static const char *const *_from_part_get_values -(const struct sieve_runtime_env *renv) -{ - ARRAY_DEFINE(envelope_values, const char *); - - t_array_init(&envelope_values, 2); - - if ( renv->msgdata->return_path != NULL ) { - array_append(&envelope_values, &renv->msgdata->return_path, 1); - } - - (void)array_append_space(&envelope_values); - - return array_idx(&envelope_values, 0); -} - -static const struct sieve_address *const *_to_part_get_addresses -(const struct sieve_runtime_env *renv) -{ - ARRAY_DEFINE(envelope_values, const struct sieve_address *); - const struct sieve_address *address = - sieve_message_get_recipient_address(renv->msgctx); - - if ( address != NULL && address->local_part != NULL ) { - t_array_init(&envelope_values, 2); - - array_append(&envelope_values, &address, 1); - - (void)array_append_space(&envelope_values); - return array_idx(&envelope_values, 0); - } - - return NULL; -} - -static const char *const *_to_part_get_values -(const struct sieve_runtime_env *renv) -{ - ARRAY_DEFINE(envelope_values, const char *); - - t_array_init(&envelope_values, 2); - - if ( renv->msgdata->to_address != NULL ) { - array_append(&envelope_values, &renv->msgdata->to_address, 1); - } - - (void)array_append_space(&envelope_values); - - return array_idx(&envelope_values, 0); -} - - -static const char *const *_auth_part_get_values -(const struct sieve_runtime_env *renv) -{ - ARRAY_DEFINE(envelope_values, const char *); - - t_array_init(&envelope_values, 2); - - if ( renv->msgdata->auth_user != NULL ) - array_append(&envelope_values, &renv->msgdata->auth_user, 1); - - (void)array_append_space(&envelope_values); - - return array_idx(&envelope_values, 0); -} - static int ext_envelope_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { - bool result = TRUE; struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator); struct sieve_match_type mcht = SIEVE_MATCH_TYPE_DEFAULT(is_match_type); struct sieve_address_part addrp = SIEVE_ADDRESS_PART_DEFAULT(all_address_part); - struct sieve_match_context *mctx; - struct sieve_coded_stringlist *envp_list; - struct sieve_coded_stringlist *key_list; - string_t *envp_item; - bool matched; + struct sieve_stringlist *env_part_list, *value_list, *key_list; + struct sieve_address_list *addr_list; int ret; /* @@ -433,7 +588,7 @@ static int ext_envelope_operation_execute return SIEVE_EXEC_BIN_CORRUPT; /* Read envelope-part */ - if ( (envp_list=sieve_opr_stringlist_read(renv, address, "envelope-part")) + if ( (env_part_list=sieve_opr_stringlist_read(renv, address, "envelope-part")) == NULL ) return SIEVE_EXEC_BIN_CORRUPT; @@ -447,90 +602,21 @@ static int ext_envelope_operation_execute */ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "envelope test"); - - /* Initialize match */ - mctx = sieve_match_begin(renv, &mcht, &cmp, NULL, key_list); - - /* Iterate through all requested headers to match */ - envp_item = NULL; - matched = FALSE; - while ( result && !matched && - (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; - int i; - - if ( epart->get_addresses != NULL ) { - /* Field contains addresses */ - addresses = epart->get_addresses(renv); - - if ( addresses != NULL ) { - for ( i = 0; !matched && addresses[i] != NULL; i++ ) { - if ( addresses[i]->local_part == NULL ) { - /* Null path <> */ - ret = sieve_match_value(mctx, "", 0); - } else { - const char *part = NULL; - - if ( addrp.def != NULL && addrp.def->extract_from != NULL ) - part = addrp.def->extract_from(&addrp, addresses[i]); - - if ( part != NULL ) - ret = sieve_match_value(mctx, part, strlen(part)); - else - ret = 0; - } - - if ( ret < 0 ) { - result = FALSE; - break; - } - - matched = ret > 0; - } - } - } - - if ( epart->get_values != NULL && addresses == NULL && - sieve_address_part_is(&addrp, all_address_part) ) { - /* Field contains something else */ - const char *const *values = epart->get_values(renv); + /* Create value stringlist */ + addr_list = sieve_envelope_address_list_create(renv, env_part_list); + value_list = sieve_address_part_stringlist_create(renv, &addrp, addr_list); - if ( values == NULL ) continue; + /* Perform match */ + ret = sieve_match(renv, &mcht, &cmp, value_list, key_list); - for ( i = 0; !matched && values[i] != NULL; i++ ) { - - if ( (ret=sieve_match_value - (mctx, values[i], strlen(values[i]))) < 0 ) { - result = FALSE; - break; - } - - matched = ret > 0; - } - } - } - } - - /* Finish match */ - if ( (ret=sieve_match_end(&mctx)) < 0 ) - result = FALSE; - else - matched = ( ret > 0 || matched ); - - if ( result ) { - /* Set test result for subsequent conditional jump */ - sieve_interpreter_set_test_result(renv->interp, matched); + /* Set test result for subsequent conditional jump */ + if ( ret >= 0 ) { + sieve_interpreter_set_test_result(renv->interp, ret > 0); return SIEVE_EXEC_OK; - } - - sieve_runtime_trace_error(renv, "invalid string-list item"); + } + + sieve_runtime_trace_error(renv, "invalid string-list item"); return SIEVE_EXEC_BIN_CORRUPT; } diff --git a/src/lib-sieve/mcht-contains.c b/src/lib-sieve/mcht-contains.c index e5cc61956..23b2afa43 100644 --- a/src/lib-sieve/mcht-contains.c +++ b/src/lib-sieve/mcht-contains.c @@ -17,9 +17,9 @@ * Forward declarations */ -static int mcht_contains_match +static int mcht_contains_match_key (struct sieve_match_context *mctx, const char *val, size_t val_size, - const char *key, size_t key_size, int key_index); + const char *key, size_t key_size); /* * Match-type object @@ -27,11 +27,10 @@ static int mcht_contains_match const struct sieve_match_type_def contains_match_type = { SIEVE_OBJECT("contains", &match_type_operand, SIEVE_MATCH_TYPE_CONTAINS), - TRUE, TRUE, NULL, sieve_match_substring_validate_context, - NULL, - mcht_contains_match, + NULL, NULL, NULL, + mcht_contains_match_key, NULL }; @@ -42,9 +41,9 @@ const struct sieve_match_type_def contains_match_type = { /* FIXME: Naive substring match implementation. Should switch to more * efficient algorithm if large values need to be searched (e.g. message body). */ -static int mcht_contains_match +static int mcht_contains_match_key (struct sieve_match_context *mctx, const char *val, size_t val_size, - const char *key, size_t key_size, int key_index ATTR_UNUSED) + const char *key, size_t key_size) { const struct sieve_comparator *cmp = mctx->comparator; const char *vend = (const char *) val + val_size; @@ -52,7 +51,7 @@ static int mcht_contains_match const char *vp = val; const char *kp = key; - if ( val == NULL || val_size == 0 ) + if ( val_size == 0 ) return ( key_size == 0 ); if ( cmp->def == NULL || cmp->def->char_match == NULL ) diff --git a/src/lib-sieve/mcht-is.c b/src/lib-sieve/mcht-is.c index 154dff792..c3ac2fab3 100644 --- a/src/lib-sieve/mcht-is.c +++ b/src/lib-sieve/mcht-is.c @@ -17,9 +17,9 @@ * Forward declarations */ -static int mcht_is_match +static int mcht_is_match_key (struct sieve_match_context *mctx, const char *val, size_t val_size, - const char *key, size_t key_size, int key_index); + const char *key, size_t key_size); /* * Match-type object @@ -27,9 +27,8 @@ static int mcht_is_match const struct sieve_match_type_def is_match_type = { SIEVE_OBJECT("is", &match_type_operand, SIEVE_MATCH_TYPE_IS), - TRUE, TRUE, - NULL, NULL, NULL, - mcht_is_match, + NULL, NULL, NULL, NULL, NULL, + mcht_is_match_key, NULL }; @@ -37,12 +36,12 @@ const struct sieve_match_type_def is_match_type = { * Match-type implementation */ -static int mcht_is_match +static int mcht_is_match_key (struct sieve_match_context *mctx ATTR_UNUSED, const char *val, size_t val_size, - const char *key, size_t key_size, int key_index ATTR_UNUSED) + const char *key, size_t key_size) { - if ( (val == NULL || val_size == 0) ) + if ( val_size == 0 ) return ( key_size == 0 ); if ( mctx->comparator->def != NULL && mctx->comparator->def->compare != NULL ) diff --git a/src/lib-sieve/mcht-matches.c b/src/lib-sieve/mcht-matches.c index 3a1f1652e..e14f1dd6a 100644 --- a/src/lib-sieve/mcht-matches.c +++ b/src/lib-sieve/mcht-matches.c @@ -18,9 +18,9 @@ * Forward declarations */ -static int mcht_matches_match +static int mcht_matches_match_key (struct sieve_match_context *mctx, const char *val, size_t val_size, - const char *key, size_t key_size, int key_index); + const char *key, size_t key_size); /* * Match-type object @@ -28,11 +28,10 @@ static int mcht_matches_match const struct sieve_match_type_def matches_match_type = { SIEVE_OBJECT("matches", &match_type_operand, SIEVE_MATCH_TYPE_MATCHES), - TRUE, FALSE, NULL, sieve_match_substring_validate_context, - NULL, - mcht_matches_match, + NULL, NULL, NULL, + mcht_matches_match_key, NULL }; @@ -83,9 +82,9 @@ static char _scan_key_section return '\0'; } -static int mcht_matches_match +static int mcht_matches_match_key (struct sieve_match_context *mctx, const char *val, size_t val_size, - const char *key, size_t key_size, int key_index ATTR_UNUSED) + const char *key, size_t key_size) { const struct sieve_comparator *cmp = mctx->comparator; struct sieve_match_values *mvalues; @@ -100,12 +99,6 @@ static int mcht_matches_match if ( cmp->def == NULL || cmp->def->char_match == NULL ) return FALSE; - /* Value may be NULL, parse empty string in stead */ - if ( val == NULL ) { - val = ""; - val_size = 0; - } - /* Key sections */ section = t_str_new(32); /* Section (after beginning or *) */ subsection = t_str_new(32); /* Sub-section (after ?) */ diff --git a/src/lib-sieve/plugins/body/ext-body-common.c b/src/lib-sieve/plugins/body/ext-body-common.c index 559588688..2d80d8ae4 100644 --- a/src/lib-sieve/plugins/body/ext-body-common.c +++ b/src/lib-sieve/plugins/body/ext-body-common.c @@ -13,15 +13,22 @@ #include "message-decoder.h" #include "sieve-common.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-message.h" #include "sieve-interpreter.h" #include "ext-body-common.h" -/* This implementation is largely borrowed from the original sieve-cmu.c of the - * cmusieve plugin. +/* FIXME: This implementation is largely borrowed from the original sieve-cmu.c + * of the old cmusieve plugin. This nees work to match current specification of + * the body extension. */ + +struct ext_body_part { + const char *content; + unsigned long size; +}; struct ext_body_part_cached { const char *content_type; @@ -147,6 +154,7 @@ static void ext_body_part_save if ( !decoded ) { body_part->raw_body = part_data; body_part->raw_body_size = part_size; + printf("%ld <=> %ld\n", (long) buf->used - 1, (long) part->body_size.physical_size); i_assert(buf->used - 1 == part->body_size.physical_size); } else { body_part->decoded_body = part_data; @@ -325,7 +333,7 @@ static struct ext_body_message_context *ext_body_get_context return ctx; } -bool ext_body_get_content +static bool ext_body_get_content (const struct sieve_runtime_env *renv, const char * const *content_types, int decode_to_plain, struct ext_body_part **parts_r) { @@ -351,7 +359,7 @@ bool ext_body_get_content return result; } -bool ext_body_get_raw +static bool ext_body_get_raw (const struct sieve_runtime_env *renv, struct ext_body_part **parts_r) { const struct sieve_extension *this_ext = renv->oprtn->ext; @@ -406,3 +414,83 @@ bool ext_body_get_raw return TRUE; } + +/* + * Body part stringlist + */ + +static int ext_body_stringlist_next_item + (struct sieve_stringlist *_strlist, string_t **str_r); +static void ext_body_stringlist_reset + (struct sieve_stringlist *_strlist); + +struct ext_body_stringlist { + struct sieve_stringlist strlist; + + struct ext_body_part *body_parts; + struct ext_body_part *body_parts_iter; +}; + +struct sieve_stringlist *ext_body_get_part_list +(const struct sieve_runtime_env *renv, enum tst_body_transform transform, + const char * const *content_types) +{ + static const char * const _no_content_types[] = { "", NULL }; + struct ext_body_stringlist *strlist; + struct ext_body_part *body_parts; + + if ( content_types == NULL ) content_types = _no_content_types; + + switch ( transform ) { + case TST_BODY_TRANSFORM_RAW: + if ( !ext_body_get_raw(renv, &body_parts) ) + return NULL; + break; + case TST_BODY_TRANSFORM_CONTENT: + /* FIXME: check these parameters */ + if ( !ext_body_get_content(renv, content_types, TRUE, &body_parts) ) + return NULL; + break; + case TST_BODY_TRANSFORM_TEXT: + /* FIXME: check these parameters */ + if ( !ext_body_get_content(renv, content_types, TRUE, &body_parts) ) + return NULL; + break; + default: + i_unreached(); + } + + strlist = t_new(struct ext_body_stringlist, 1); + strlist->strlist.runenv = renv; + strlist->strlist.next_item = ext_body_stringlist_next_item; + strlist->strlist.reset = ext_body_stringlist_reset; + strlist->body_parts = body_parts; + strlist->body_parts_iter = body_parts; + + return &strlist->strlist; +} + +static int ext_body_stringlist_next_item +(struct sieve_stringlist *_strlist, string_t **str_r) +{ + struct ext_body_stringlist *strlist = + (struct ext_body_stringlist *)_strlist; + + *str_r = NULL; + + if ( strlist->body_parts_iter->content == NULL ) return 0; + + *str_r = t_str_new_const + (strlist->body_parts_iter->content, strlist->body_parts_iter->size); + strlist->body_parts_iter++; + return 1; +} + +static void ext_body_stringlist_reset +(struct sieve_stringlist *_strlist) +{ + struct ext_body_stringlist *strlist = + (struct ext_body_stringlist *)_strlist; + + strlist->body_parts_iter = strlist->body_parts; +} diff --git a/src/lib-sieve/plugins/body/ext-body-common.h b/src/lib-sieve/plugins/body/ext-body-common.h index ba61bbc33..d2c1fa58b 100644 --- a/src/lib-sieve/plugins/body/ext-body-common.h +++ b/src/lib-sieve/plugins/body/ext-body-common.h @@ -4,6 +4,16 @@ #ifndef __EXT_BODY_COMMON_H #define __EXT_BODY_COMMON_H +/* + * Types + */ + +enum tst_body_transform { + TST_BODY_TRANSFORM_RAW, + TST_BODY_TRANSFORM_CONTENT, + TST_BODY_TRANSFORM_TEXT +}; + /* * Extension */ @@ -26,16 +36,8 @@ extern const struct sieve_operation_def body_operation; * Message body part extraction */ -struct ext_body_part { - const char *content; - unsigned long size; -}; - -bool ext_body_get_content - (const struct sieve_runtime_env *renv, const char * const *content_types, - int decode_to_plain, struct ext_body_part **parts_r); - -bool ext_body_get_raw - (const struct sieve_runtime_env *renv, struct ext_body_part **parts_r); +struct sieve_stringlist *ext_body_get_part_list + (const struct sieve_runtime_env *renv, enum tst_body_transform transform, + const char * const *content_types); #endif /* __EXT_BODY_COMMON_H */ diff --git a/src/lib-sieve/plugins/body/tst-body.c b/src/lib-sieve/plugins/body/tst-body.c index f416f586c..f3033bc87 100644 --- a/src/lib-sieve/plugins/body/tst-body.c +++ b/src/lib-sieve/plugins/body/tst-body.c @@ -3,6 +3,7 @@ #include "sieve-extensions.h" #include "sieve-commands.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-comparators.h" #include "sieve-match-types.h" @@ -17,16 +18,6 @@ #include "ext-body-common.h" -/* - * Types - */ - -enum tst_body_transform { - TST_BODY_TRANSFORM_RAW, - TST_BODY_TRANSFORM_CONTENT, - TST_BODY_TRANSFORM_TEXT -}; - /* * Body test * @@ -311,21 +302,16 @@ static bool ext_body_operation_dump static int ext_body_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { - static const char * const _no_content_types[] = { "", NULL }; - int ret = SIEVE_EXEC_OK; + int ret; int opt_code = 0; - int mret; struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator); - struct sieve_match_type mtch = + struct sieve_match_type mcht = SIEVE_MATCH_TYPE_DEFAULT(is_match_type); - enum tst_body_transform transform; - struct sieve_coded_stringlist *key_list, *ctype_list = NULL; - struct sieve_match_context *mctx; - const char * const *content_types = _no_content_types; - struct ext_body_part *body_parts; + enum tst_body_transform transform = TST_BODY_TRANSFORM_TEXT; + struct sieve_stringlist *ctype_list, *value_list, *key_list; bool mvalues_active; - bool matched; + const char * const *content_types = NULL; /* * Read operands @@ -333,12 +319,12 @@ static int ext_body_operation_execute /* Optional operands */ + ctype_list = NULL; for (;;) { bool opok = TRUE; - int ret; if ( (ret=sieve_match_opr_optional_read - (renv, address, &opt_code, &cmp, &mtch)) < 0 ) + (renv, address, &opt_code, &cmp, &mcht)) < 0 ) return SIEVE_EXEC_BIN_CORRUPT; if ( ret == 0 ) break; @@ -371,9 +357,9 @@ static int ext_body_operation_execute if ( (key_list=sieve_opr_stringlist_read(renv, address, "key-list")) == NULL ) return SIEVE_EXEC_BIN_CORRUPT; - if ( ctype_list != NULL && !sieve_coded_stringlist_read_all + if ( ctype_list != NULL && !sieve_stringlist_read_all (ctype_list, pool_datastack_create(), &content_types) ) { - sieve_runtime_trace_error(renv, "invalid content-type-list operand"); + sieve_runtime_trace_error(renv, "failed to read content-type-list operand"); return SIEVE_EXEC_BIN_CORRUPT; } @@ -384,53 +370,25 @@ static int ext_body_operation_execute sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "body test"); /* Extract requested parts */ - - if ( transform == TST_BODY_TRANSFORM_RAW ) { - if ( !ext_body_get_raw(renv, &body_parts) ) { - return SIEVE_EXEC_FAILURE; - } - } else { - if ( !ext_body_get_content - (renv, content_types, TRUE, &body_parts) ) { - return SIEVE_EXEC_FAILURE; - } - } + value_list = ext_body_get_part_list(renv, transform, content_types); + if ( value_list == FALSE ) + return SIEVE_EXEC_FAILURE; /* Disable match values processing as required by RFC */ - mvalues_active = sieve_match_values_set_enabled(renv, FALSE); - /* Iterate through all requested body parts to match */ - - matched = FALSE; - mctx = sieve_match_begin(renv, &mtch, &cmp, NULL, key_list); - while ( !matched && body_parts->content != NULL ) { - if ( (mret=sieve_match_value(mctx, body_parts->content, body_parts->size)) - < 0) - { - sieve_runtime_trace_error(renv, "invalid string list item"); - ret = SIEVE_EXEC_BIN_CORRUPT; - break; - } - - matched = ( mret > 0 ); - body_parts++; - } + /* Perform match */ + ret = sieve_match(renv, &mcht, &cmp, value_list, key_list); - if ( (mret=sieve_match_end(&mctx)) < 0 ) { - sieve_runtime_trace_error(renv, "invalid string list item"); - ret = SIEVE_EXEC_BIN_CORRUPT; - } else - matched = ( mret > 0 || matched ); - - /* Restore match values processing */ - + /* Restore match values processing */ (void)sieve_match_values_set_enabled(renv, mvalues_active); - /* Set test result */ - - if ( ret == SIEVE_EXEC_OK ) - sieve_interpreter_set_test_result(renv->interp, matched); - - return ret; + /* Set test result for subsequent conditional jump */ + if ( ret >= 0 ) { + sieve_interpreter_set_test_result(renv->interp, ret > 0); + return SIEVE_EXEC_OK; + } + + sieve_runtime_trace_error(renv, "invalid string-list item"); + return SIEVE_EXEC_BIN_CORRUPT; } diff --git a/src/lib-sieve/plugins/date/ext-date-common.c b/src/lib-sieve/plugins/date/ext-date-common.c index 28ce60634..7891b17e5 100644 --- a/src/lib-sieve/plugins/date/ext-date-common.c +++ b/src/lib-sieve/plugins/date/ext-date-common.c @@ -3,8 +3,11 @@ #include "lib.h" #include "utc-offset.h" +#include "str.h" +#include "message-date.h" #include "sieve-common.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-interpreter.h" #include "sieve-message.h" @@ -465,3 +468,147 @@ static const char *ext_date_weekday_part_get return t_strdup_printf("%d", tm->tm_wday); } +/* + * Date stringlist + */ + +/* Forward declarations */ + +static int ext_date_stringlist_next_item + (struct sieve_stringlist *_strlist, string_t **str_r); +static void ext_date_stringlist_reset + (struct sieve_stringlist *_strlist); + +/* Stringlist object */ + +struct ext_date_stringlist { + struct sieve_stringlist strlist; + + struct sieve_stringlist *field_values; + int time_zone; + const char *date_part; + + time_t local_time; + int local_zone; + + unsigned int read:1; +}; + +struct sieve_stringlist *ext_date_stringlist_create +(const struct sieve_runtime_env *renv, struct sieve_stringlist *field_values, + int time_zone, const char *date_part) +{ + struct ext_date_stringlist *strlist; + + strlist = t_new(struct ext_date_stringlist, 1); + strlist->strlist.runenv = renv; + strlist->strlist.next_item = ext_date_stringlist_next_item; + strlist->strlist.reset = ext_date_stringlist_reset; + strlist->field_values = field_values; + strlist->time_zone = time_zone; + strlist->date_part = date_part; + + strlist->local_time = ext_date_get_current_date(renv, &strlist->local_zone); + + return &strlist->strlist; +} + +/* Stringlist implementation */ + +static int ext_date_stringlist_next_item +(struct sieve_stringlist *_strlist, string_t **str_r) +{ + struct ext_date_stringlist *strlist = + (struct ext_date_stringlist *) _strlist; + bool got_date = FALSE; + time_t date_value; + const char *part_value = NULL; + int original_zone; + + /* Check whether the item was already read */ + if ( strlist->read ) return 0; + + if ( strlist->field_values != NULL ) { + string_t *hdr_item; + const char *header_value, *date_string; + int ret; + + /* Use header field value */ + + /* Read first */ + if ( (ret=sieve_stringlist_next_item(strlist->field_values, &hdr_item)) + <= 0 ) + return ret; + + /* Extract the date string value */ + + header_value = str_c(hdr_item); + date_string = strrchr(header_value, ';'); + + if ( date_string == NULL ) { + /* Direct header value */ + date_string = header_value; + } else { + /* Delimited by ';', e.g. a Received: header */ + date_string++; + } + + /* Parse the date value */ + if ( message_date_parse((const unsigned char *) date_string, + strlen(date_string), &date_value, &original_zone) ) { + got_date = TRUE; + } + } else { + /* Use time stamp recorded at the time the script first started */ + date_value = strlist->local_time; + original_zone = strlist->local_zone; + got_date = TRUE; + } + + if ( got_date ) { + int wanted_zone; + struct tm *date_tm; + + /* Apply wanted timezone */ + + switch ( strlist->time_zone ) { + case EXT_DATE_TIMEZONE_LOCAL: + wanted_zone = strlist->local_zone; + break; + case EXT_DATE_TIMEZONE_ORIGINAL: + wanted_zone = original_zone; + break; + default: + wanted_zone = strlist->time_zone; + } + + date_value += wanted_zone * 60; + + /* Convert timestamp to struct tm */ + + if ( (date_tm=gmtime(&date_value)) != NULL ) { + /* Extract the date part */ + part_value = ext_date_part_extract + (strlist->date_part, date_tm, wanted_zone); + } + } + + strlist->read = TRUE; + + if ( part_value == NULL ) + return 0; + + *str_r = t_str_new_const(part_value, strlen(part_value)); + return 1; +} + +static void ext_date_stringlist_reset +(struct sieve_stringlist *_strlist) +{ + struct ext_date_stringlist *strlist = + (struct ext_date_stringlist *) _strlist; + + if ( strlist->field_values != NULL ) + sieve_stringlist_reset(strlist->field_values); + strlist->read = FALSE; +} diff --git a/src/lib-sieve/plugins/date/ext-date-common.h b/src/lib-sieve/plugins/date/ext-date-common.h index a6f9cee51..07e578e70 100644 --- a/src/lib-sieve/plugins/date/ext-date-common.h +++ b/src/lib-sieve/plugins/date/ext-date-common.h @@ -63,4 +63,19 @@ struct ext_date_part { const char *ext_date_part_extract (const char *part, struct tm *tm, int zone_offset); +/* + * Date stringlist + */ + +enum ext_date_timezone_special { + EXT_DATE_TIMEZONE_LOCAL = 100, + EXT_DATE_TIMEZONE_ORIGINAL = 101 +}; + +struct sieve_stringlist *ext_date_stringlist_create +(const struct sieve_runtime_env *renv, struct sieve_stringlist *field_values, + int time_zone, const char *date_part); + + + #endif /* __EXT_DATE_COMMON_H */ diff --git a/src/lib-sieve/plugins/date/tst-date.c b/src/lib-sieve/plugins/date/tst-date.c index 541cbabaa..90b62c3b5 100644 --- a/src/lib-sieve/plugins/date/tst-date.c +++ b/src/lib-sieve/plugins/date/tst-date.c @@ -3,7 +3,6 @@ #include "lib.h" #include "str-sanitize.h" -#include "message-date.h" #include "sieve-common.h" #include "sieve-commands.h" @@ -11,6 +10,7 @@ #include "sieve-comparators.h" #include "sieve-match-types.h" #include "sieve-address-parts.h" +#include "sieve-message.h" #include "sieve-validator.h" #include "sieve-generator.h" #include "sieve-interpreter.h" @@ -372,6 +372,7 @@ static bool tst_date_operation_dump sieve_opr_stringlist_dump(denv, address, "key list"); } + /* * Code execution */ @@ -380,21 +381,17 @@ static int tst_date_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { const struct sieve_operation *op = renv->oprtn; - bool result = TRUE, zone_specified = FALSE, got_date = FALSE, matched = FALSE; int opt_code = 0; - const struct sieve_message_data *msgdata = renv->msgdata; struct sieve_match_type mcht = SIEVE_MATCH_TYPE_DEFAULT(is_match_type); struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator); struct sieve_operand operand; - struct sieve_match_context *mctx; - string_t *header_name = NULL, *date_part = NULL, *zone = NULL; - struct sieve_coded_stringlist *key_list; - time_t date_value, local_time; - struct tm *date_tm; - const char *part_value; - int local_zone = 0, original_zone = 0, wanted_zone = 0; + string_t *date_part = NULL, *zone = NULL; + struct sieve_stringlist *hdr_list = NULL, *hdr_value_list; + struct sieve_stringlist *value_list, *key_list; + bool zone_specified = FALSE; + int time_zone; int ret; /* Read optional operands */ @@ -427,8 +424,9 @@ static int tst_date_operation_execute } if ( sieve_operation_is(op, date_operation) ) { - /* Read header name */ - if ( !sieve_opr_string_read(renv, address, "header-name", &header_name) ) + /* Read header name as stringlist */ + if ( (hdr_list=sieve_opr_stringlist_read(renv, address, "header-name")) + == NULL ) return SIEVE_EXEC_BIN_CORRUPT; } @@ -441,102 +439,47 @@ static int tst_date_operation_execute == NULL ) return SIEVE_EXEC_BIN_CORRUPT; + /* Determine what time zone to use in the result */ + if ( !zone_specified ) { + time_zone = EXT_DATE_TIMEZONE_LOCAL; + } else if ( zone == NULL ) { + time_zone = EXT_DATE_TIMEZONE_ORIGINAL; + } else if ( !ext_date_parse_timezone(str_c(zone), &time_zone) ) { + /* FIXME: warn about parse failures */ + time_zone = EXT_DATE_TIMEZONE_LOCAL; + } + /* * Perform test */ - - /* Get the date value */ - - local_time = ext_date_get_current_date(renv, &local_zone); - + if ( sieve_operation_is(op, date_operation) ) { - const char *header_value; - const char *date_string; - + sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "date test"); - /* Get date from the message */ - - /* Read first header - * NOTE: need something for index extension to hook into some time. - */ - if ( (ret=mail_get_first_header - (msgdata->mail, str_c(header_name), &header_value)) > 0 ) { - - /* Extract the date string value */ - date_string = strrchr(header_value, ';'); - if ( date_string == NULL ) - /* Direct header value */ - date_string = header_value; - else { - /* Delimited by ';', e.g. a Received: header */ - date_string++; - } + /* Create value stringlist */ + hdr_value_list = sieve_message_header_stringlist_create(renv, hdr_list); + value_list = ext_date_stringlist_create + (renv, hdr_value_list, time_zone, str_c(date_part)); - /* Parse the date value */ - if ( message_date_parse((const unsigned char *) date_string, - strlen(date_string), &date_value, &original_zone) ) { - got_date = TRUE; - } - } } else if ( sieve_operation_is(op, currentdate_operation) ) { /* Use time stamp recorded at the time the script first started */ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "currentdatedate test"); - date_value = local_time; - original_zone = local_zone; - got_date = TRUE; - + /* Create value stringlist */ + value_list = ext_date_stringlist_create + (renv, NULL, time_zone, str_c(date_part)); } else { i_unreached(); } - if ( got_date ) { - /* Apply wanted timezone */ - - if ( !zone_specified ) - wanted_zone = local_zone; - else if ( zone == NULL - || !ext_date_parse_timezone(str_c(zone), &wanted_zone) ) { - - /* FIXME: warn about parse failures */ - wanted_zone = original_zone; - } - - date_value += wanted_zone * 60; - - /* Convert timestamp to struct tm */ - - if ( (date_tm=gmtime(&date_value)) == NULL ) { - got_date = FALSE; - } else { - /* Extract the date part */ - part_value = ext_date_part_extract - (str_c(date_part), date_tm, wanted_zone); - } - } - - /* Initialize match */ - mctx = sieve_match_begin(renv, &mcht, &cmp, NULL, key_list); - - if ( got_date && part_value != NULL ) { - /* Match value */ - if ( (ret=sieve_match_value(mctx, part_value, strlen(part_value))) < 0 ) - result = FALSE; - else - matched = ret > 0; - } - - /* Finish match */ - if ( (ret=sieve_match_end(&mctx)) < 0 ) - result = FALSE; - else - matched = ( ret > 0 || matched ); + /* Perform match */ + ret = sieve_match(renv, &mcht, &cmp, value_list, key_list); /* Set test result for subsequent conditional jump */ - if ( result ) { - sieve_interpreter_set_test_result(renv->interp, matched); + if ( ret >= 0 ) { + sieve_interpreter_set_test_result(renv->interp, ret > 0); return SIEVE_EXEC_OK; } diff --git a/src/lib-sieve/plugins/enotify/cmd-notify.c b/src/lib-sieve/plugins/enotify/cmd-notify.c index 2db21f783..6be5703ca 100644 --- a/src/lib-sieve/plugins/enotify/cmd-notify.c +++ b/src/lib-sieve/plugins/enotify/cmd-notify.c @@ -401,7 +401,7 @@ static int cmd_notify_operation_execute pool_t pool; int opt_code = 0, result = SIEVE_EXEC_OK; sieve_number_t importance = 2; - struct sieve_coded_stringlist *options = NULL; + struct sieve_stringlist *options = NULL; const struct sieve_enotify_method *method; string_t *method_uri, *message = NULL, *from = NULL; unsigned int source_line; diff --git a/src/lib-sieve/plugins/enotify/ext-enotify-common.c b/src/lib-sieve/plugins/enotify/ext-enotify-common.c index ac77d628a..d4df47f0f 100644 --- a/src/lib-sieve/plugins/enotify/ext-enotify-common.c +++ b/src/lib-sieve/plugins/enotify/ext-enotify-common.c @@ -8,6 +8,7 @@ #include "sieve-common.h" #include "sieve-ast.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-commands.h" #include "sieve-validator.h" @@ -579,7 +580,7 @@ const char *ext_enotify_runtime_get_method_capability int ext_enotify_runtime_check_operands (const struct sieve_runtime_env *renv, unsigned int source_line, string_t *method_uri, string_t *message, string_t *from, - struct sieve_coded_stringlist *options, + struct sieve_stringlist *options, const struct sieve_enotify_method **method_r, void **method_context) { const struct sieve_enotify_method *method; @@ -592,7 +593,7 @@ int ext_enotify_runtime_check_operands /* Check provided operands */ if ( method->def != NULL && method->def->runtime_check_operands != NULL ) { struct sieve_enotify_env nenv; - int ret = SIEVE_EXEC_OK; + int result = SIEVE_EXEC_OK; memset(&nenv, 0, sizeof(nenv)); nenv.method = method; @@ -608,13 +609,11 @@ int ext_enotify_runtime_check_operands /* Check any provided options */ if ( options != NULL ) { - int result = TRUE; string_t *option = NULL; + int ret; /* Iterate through all provided options */ - while ( result && - (result=sieve_coded_stringlist_next_item(options, &option)) && - option != NULL ) { + while ( (ret=sieve_stringlist_next_item(options, &option)) > 0 ) { const char *opt_name = NULL, *opt_value = NULL; /* Parse option into <optionname> and <value> */ @@ -631,13 +630,13 @@ int ext_enotify_runtime_check_operands /* Check for binary corruptions encountered during string list iteration */ - if ( result ) { + if ( ret >= 0 ) { *method_r = method; } else { /* Binary corrupt */ sieve_runtime_trace_error (renv, "invalid item in options string list"); - ret = SIEVE_EXEC_BIN_CORRUPT; + result = SIEVE_EXEC_BIN_CORRUPT; } } else { @@ -647,11 +646,11 @@ int ext_enotify_runtime_check_operands } else { /* Operand check failed */ - ret = SIEVE_EXEC_FAILURE; + result = SIEVE_EXEC_FAILURE; } sieve_error_handler_unref(&nenv.ehandler); - return ret; + return result; } /* No check function defined: a most unlikely situation */ diff --git a/src/lib-sieve/plugins/enotify/ext-enotify-common.h b/src/lib-sieve/plugins/enotify/ext-enotify-common.h index 97ab61746..65c2274af 100644 --- a/src/lib-sieve/plugins/enotify/ext-enotify-common.h +++ b/src/lib-sieve/plugins/enotify/ext-enotify-common.h @@ -112,7 +112,7 @@ const char *ext_enotify_runtime_get_method_capability int ext_enotify_runtime_check_operands (const struct sieve_runtime_env *renv, unsigned int source_line, string_t *method_uri, string_t *message, string_t *from, - struct sieve_coded_stringlist *options, + struct sieve_stringlist *options, const struct sieve_enotify_method **method_r, void **method_context); /* diff --git a/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c b/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c index e30217896..8ee7fb53f 100644 --- a/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c +++ b/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c @@ -5,6 +5,7 @@ #include "sieve-common.h" #include "sieve-commands.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-comparators.h" #include "sieve-match-types.h" @@ -176,18 +177,15 @@ static bool tst_notifymc_operation_dump static int tst_notifymc_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { - int ret, mret; - bool result = TRUE; + int ret; int opt_code = 0; struct sieve_match_type mcht = SIEVE_MATCH_TYPE_DEFAULT(is_match_type); struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator); - struct sieve_match_context *mctx; string_t *notify_uri, *notify_capability; - struct sieve_coded_stringlist *key_list; + struct sieve_stringlist *value_list, *key_list; const char *cap_value; - bool matched; /* * Read operands @@ -228,21 +226,16 @@ static int tst_notifymc_operation_execute (renv, 0 /* FIXME */, notify_uri, str_c(notify_capability)); if ( cap_value != NULL ) { - mctx = sieve_match_begin(renv, &mcht, &cmp, NULL, key_list); + value_list = sieve_single_stringlist_create_cstr(renv, cap_value, TRUE); - if ( (mret=sieve_match_value(mctx, cap_value, strlen(cap_value))) < 0 ) - result = FALSE; - matched = ( mret > 0 ); - - if ( (mret=sieve_match_end(&mctx)) < 0 ) - result = FALSE; - matched = ( mret > 0 ) || matched; + /* Perform match */ + ret = sieve_match(renv, &mcht, &cmp, value_list, key_list); } else { - matched = FALSE; + ret = 0; } - if ( result ) { - sieve_interpreter_set_test_result(renv->interp, matched); + if ( ret >= 0 ) { + sieve_interpreter_set_test_result(renv->interp, ret > 0); return SIEVE_EXEC_OK; } diff --git a/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c b/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c index 20fc00da6..493bc3dc8 100644 --- a/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c +++ b/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c @@ -3,6 +3,7 @@ #include "sieve-common.h" #include "sieve-commands.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-comparators.h" #include "sieve-match-types.h" @@ -104,9 +105,10 @@ static bool tst_vnotifym_operation_dump static int tst_vnotifym_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { - struct sieve_coded_stringlist *notify_uris; + struct sieve_stringlist *notify_uris; string_t *uri_item; - bool result = TRUE, all_valid = TRUE; + bool all_valid = TRUE; + int ret; /* * Read operands @@ -124,16 +126,14 @@ static int tst_vnotifym_operation_execute sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "valid_notify_method test"); uri_item = NULL; - while ( (result=sieve_coded_stringlist_next_item(notify_uris, &uri_item)) - && uri_item != NULL ) { - + while ( (ret=sieve_stringlist_next_item(notify_uris, &uri_item)) > 0 ) { if ( !ext_enotify_runtime_method_validate(renv, 0 /* FIXME */, uri_item) ) { all_valid = FALSE; break; } } - if ( !result ) { + if ( ret < 0 ) { sieve_runtime_trace_error(renv, "invalid method uri item"); return SIEVE_EXEC_BIN_CORRUPT; } diff --git a/src/lib-sieve/plugins/environment/tst-environment.c b/src/lib-sieve/plugins/environment/tst-environment.c index 54e1fb49b..5f9496d0f 100644 --- a/src/lib-sieve/plugins/environment/tst-environment.c +++ b/src/lib-sieve/plugins/environment/tst-environment.c @@ -3,6 +3,7 @@ #include "sieve-common.h" #include "sieve-commands.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-comparators.h" #include "sieve-match-types.h" @@ -154,18 +155,15 @@ static int tst_environment_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { const struct sieve_extension *this_ext = renv->oprtn->ext; - int ret, mret; - bool result = TRUE; + int ret; int opt_code = 0; struct sieve_match_type mcht = SIEVE_MATCH_TYPE_DEFAULT(is_match_type); struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator); - struct sieve_match_context *mctx; string_t *name; - struct sieve_coded_stringlist *key_list; + struct sieve_stringlist *value_list, *key_list; const char *env_item; - bool matched = FALSE; /* * Read operands @@ -201,23 +199,17 @@ static int tst_environment_operation_execute (this_ext, str_c(name), renv->scriptenv); if ( env_item != NULL ) { - mctx = sieve_match_begin(renv, &mcht, &cmp, NULL, key_list); - - if ( (mret=sieve_match_value(mctx, strlen(env_item) == 0 ? NULL : env_item, - strlen(env_item))) < 0 ) { - result = FALSE; - } else { - matched = ( mret > 0 ); - } - - if ( (mret=sieve_match_end(&mctx)) < 0 ) - result = FALSE; - else - matched = ( mret > 0 || matched ); + /* Construct value list */ + value_list = sieve_single_stringlist_create_cstr(renv, env_item, FALSE); + + /* Perform match */ + ret = sieve_match(renv, &mcht, &cmp, value_list, key_list); + } else { + ret = 0; } - if ( result ) { - sieve_interpreter_set_test_result(renv->interp, matched); + if ( ret >= 0 ) { + sieve_interpreter_set_test_result(renv->interp, ret > 0); return SIEVE_EXEC_OK; } diff --git a/src/lib-sieve/plugins/imap4flags/cmd-flag.c b/src/lib-sieve/plugins/imap4flags/cmd-flag.c index 805e79acb..13e43100e 100644 --- a/src/lib-sieve/plugins/imap4flags/cmd-flag.c +++ b/src/lib-sieve/plugins/imap4flags/cmd-flag.c @@ -4,6 +4,7 @@ #include "lib.h" #include "sieve-code.h" +#include "sieve-stringlist.h" #include "sieve-commands.h" #include "sieve-validator.h" #include "sieve-generator.h" @@ -176,9 +177,8 @@ static int cmd_flag_operation_execute { const struct sieve_operation *op = renv->oprtn; struct sieve_operand operand; - bool result = TRUE; string_t *flag_item; - struct sieve_coded_stringlist *flag_list; + struct sieve_stringlist *flag_list; struct sieve_variable_storage *storage; unsigned int var_index; ext_imapflag_flag_operation_t flag_op; @@ -243,14 +243,12 @@ static int cmd_flag_operation_execute /* Iterate through all flags and perform requested operation */ - while ( (result=sieve_coded_stringlist_next_item(flag_list, &flag_item)) && - flag_item != NULL ) { - + while ( (ret=sieve_stringlist_next_item(flag_list, &flag_item)) > 0 ) { if ( (ret=flag_op(renv, storage, var_index, flag_item)) <= 0) return ret; } - if ( !result ) { + if ( ret < 0 ) { sieve_runtime_trace_error(renv, "invalid flag-list item"); return SIEVE_EXEC_BIN_CORRUPT; } diff --git a/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c b/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c index 44dae44b3..771455247 100644 --- a/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c +++ b/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c @@ -8,6 +8,7 @@ #include "sieve-common.h" #include "sieve-commands.h" #include "sieve-code.h" +#include "sieve-stringlist.h" #include "sieve-actions.h" #include "sieve-validator.h" #include "sieve-generator.h" @@ -256,12 +257,13 @@ const struct sieve_interpreter_extension imap4flags_interpreter_extension = { }; /* - * Flag operations + * Flag handling */ /* FIXME: This currently accepts a potentially unlimited number of * flags, making the internal or variable flag list indefinitely long */ + static bool flag_is_valid(const char *flag) { if (*flag == '\\') { @@ -293,24 +295,35 @@ static bool flag_is_valid(const char *flag) return TRUE; } +/* Flag iterator */ + +static void ext_imap4flags_iter_clear +(struct ext_imap4flags_iter *iter) +{ + memset(iter, 0, sizeof(*iter)); +} + void ext_imap4flags_iter_init (struct ext_imap4flags_iter *iter, string_t *flags_list) { + ext_imap4flags_iter_clear(iter); iter->flags_list = flags_list; - iter->offset = 0; - iter->last = 0; } -const char *ext_imap4flags_iter_get_flag +static string_t *ext_imap4flags_iter_get_flag_str (struct ext_imap4flags_iter *iter) { - unsigned int len = str_len(iter->flags_list); + unsigned int len; const unsigned char *fp; const unsigned char *fbegin; const unsigned char *fstart; const unsigned char *fend; + /* Return if not initialized */ + if ( iter->flags_list == NULL ) return NULL; + /* Return if no more flags are available */ + len = str_len(iter->flags_list); if ( iter->offset >= len ) return NULL; /* Mark string boundries */ @@ -328,7 +341,8 @@ const char *ext_imap4flags_iter_get_flag /* Did we scan more than nothing ? */ if ( fp > fstart ) { /* Return flag */ - const char *flag = t_strdup_until(fstart, fp); + string_t *flag = t_str_new(fp-fstart+1); + str_append_n(flag, fstart, fp-fstart); iter->last = fstart - fbegin; iter->offset = fp - fbegin; @@ -349,6 +363,16 @@ const char *ext_imap4flags_iter_get_flag return NULL; } +const char *ext_imap4flags_iter_get_flag +(struct ext_imap4flags_iter *iter) +{ + string_t *flag = ext_imap4flags_iter_get_flag_str(iter); + + if ( flag == NULL ) return NULL; + + return str_c(flag); +} + static void ext_imap4flags_iter_delete_last (struct ext_imap4flags_iter *iter) { @@ -363,6 +387,8 @@ static void ext_imap4flags_iter_delete_last iter->offset = iter->last; } +/* Flag operations */ + static bool flags_list_flag_exists (string_t *flags_list, const char *flag) { @@ -431,10 +457,6 @@ static void flags_list_set_flags flags_list_add_flags(flags_list, flags); } -/* - * Flag registration - */ - int ext_imap4flags_set_flags (const struct sieve_runtime_env *renv, struct sieve_variable_storage *storage, unsigned int var_index, string_t *flags) @@ -489,41 +511,119 @@ int ext_imap4flags_remove_flags return SIEVE_EXEC_OK; } -int ext_imap4flags_get_flags_string -(const struct sieve_runtime_env *renv, struct sieve_variable_storage *storage, - unsigned int var_index, const char **flags) +/* Flag stringlist */ + +static int ext_imap4flags_stringlist_next_item + (struct sieve_stringlist *_strlist, string_t **str_r); +static void ext_imap4flags_stringlist_reset + (struct sieve_stringlist *_strlist); + +struct ext_imap4flags_stringlist { + struct sieve_stringlist strlist; + + struct sieve_stringlist *flags_list; + string_t *flags_string; + struct ext_imap4flags_iter flit; + + unsigned int normalize:1; +}; + +static struct sieve_stringlist *ext_imap4flags_stringlist_create +(const struct sieve_runtime_env *renv, struct sieve_stringlist *flags_list, + bool normalize) { - string_t *cur_flags; - - if ( storage != NULL ) { - if ( !sieve_variable_get_modifiable(storage, var_index, &cur_flags) ) - return SIEVE_EXEC_BIN_CORRUPT; - } else - cur_flags = _get_flags_string(renv->oprtn->ext, renv->result); - - if ( cur_flags == NULL ) - *flags = ""; - else - *flags = str_c(cur_flags); + struct ext_imap4flags_stringlist *strlist; - return SIEVE_EXEC_OK; + strlist = t_new(struct ext_imap4flags_stringlist, 1); + strlist->strlist.runenv = renv; + strlist->strlist.next_item = ext_imap4flags_stringlist_next_item; + strlist->strlist.reset = ext_imap4flags_stringlist_reset; + strlist->normalize = normalize; + + strlist->flags_list = flags_list; + + return &strlist->strlist; } -void ext_imap4flags_get_flags_init -(struct ext_imap4flags_iter *iter, const struct sieve_runtime_env *renv, - string_t *flags_list) +static struct sieve_stringlist *ext_imap4flags_stringlist_create_single +(const struct sieve_runtime_env *renv, string_t *flags_string, bool normalize) { - string_t *cur_flags; - - if ( flags_list != NULL ) { - cur_flags = t_str_new(256); - - flags_list_set_flags(cur_flags, flags_list); + struct ext_imap4flags_stringlist *strlist; + + strlist = t_new(struct ext_imap4flags_stringlist, 1); + strlist->strlist.runenv = renv; + strlist->strlist.next_item = ext_imap4flags_stringlist_next_item; + strlist->strlist.reset = ext_imap4flags_stringlist_reset; + strlist->normalize = normalize; + + if ( normalize ) { + strlist->flags_string = t_str_new(256); + flags_list_set_flags(strlist->flags_string, flags_string); + } else { + strlist->flags_string = flags_string; } - else - cur_flags = _get_flags_string(renv->oprtn->ext, renv->result); + + ext_imap4flags_iter_init(&strlist->flit, strlist->flags_string); + + return &strlist->strlist; +} + +static int ext_imap4flags_stringlist_next_item +(struct sieve_stringlist *_strlist, string_t **str_r) +{ + struct ext_imap4flags_stringlist *strlist = + (struct ext_imap4flags_stringlist *)_strlist; - ext_imap4flags_iter_init(iter, cur_flags); + while ( (*str_r=ext_imap4flags_iter_get_flag_str(&strlist->flit)) == NULL ) { + int ret; + + if ( strlist->flags_list == NULL ) + return 0; + + if ( (ret=sieve_stringlist_next_item + (strlist->flags_list, &strlist->flags_string)) <= 0 ) + return ret; + + if ( strlist->flags_string == NULL ) + return -1; + + if ( strlist->normalize ) { + string_t *flags_string = t_str_new(256); + + flags_list_set_flags(flags_string, strlist->flags_string); + strlist->flags_string = flags_string; + } + + ext_imap4flags_iter_init(&strlist->flit, strlist->flags_string); + } + + return 1; +} + +static void ext_imap4flags_stringlist_reset +(struct sieve_stringlist *_strlist) +{ + struct ext_imap4flags_stringlist *strlist = + (struct ext_imap4flags_stringlist *)_strlist; + + if ( strlist->flags_list != NULL ) { + sieve_stringlist_reset(strlist->flags_list); + ext_imap4flags_iter_clear(&strlist->flit); + } else { + ext_imap4flags_iter_init(&strlist->flit, strlist->flags_string); + } +} + +/* Flag access */ + +struct sieve_stringlist *ext_imap4flags_get_flags +(const struct sieve_runtime_env *renv, struct sieve_stringlist *flags_list) +{ + if ( flags_list == NULL ) + return ext_imap4flags_stringlist_create_single + (renv, _get_flags_string(renv->oprtn->ext, renv->result), FALSE); + + return ext_imap4flags_stringlist_create(renv, flags_list, TRUE); } void ext_imap4flags_get_implicit_flags_init diff --git a/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h b/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h index 2a7dd0ef7..5e4140a36 100644 --- a/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h +++ b/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h @@ -86,6 +86,8 @@ void ext_imap4flags_iter_init const char *ext_imap4flags_iter_get_flag (struct ext_imap4flags_iter *iter); +/* Flag operations */ + typedef int (*ext_imapflag_flag_operation_t) (const struct sieve_runtime_env *renv, struct sieve_variable_storage *storage, unsigned int var_index, string_t *flags); @@ -100,17 +102,11 @@ int ext_imap4flags_remove_flags (const struct sieve_runtime_env *renv, struct sieve_variable_storage *storage, unsigned int var_index, string_t *flags); -/* - * Flags access - */ +/* Flags access */ -int ext_imap4flags_get_flags_string -(const struct sieve_runtime_env *renv, struct sieve_variable_storage *storage, - unsigned int var_index, const char **flags); +struct sieve_stringlist *ext_imap4flags_get_flags + (const struct sieve_runtime_env *renv, struct sieve_stringlist *flags_list); -void ext_imap4flags_get_flags_init - (struct ext_imap4flags_iter *iter, const struct sieve_runtime_env *renv, - string_t *flags_list); void ext_imap4flags_get_implicit_flags_init (struct ext_imap4flags_iter *iter, const struct sieve_extension *this_ext, struct sieve_result *result); diff --git a/src/lib-sieve/plugins/imap4flags/tag-flags.c b/src/lib-sieve/plugins/imap4flags/tag-flags.c index b7115d4db..2cf116e61 100644 --- a/src/lib-sieve/plugins/imap4flags/tag-flags.c +++ b/src/lib-sieve/plugins/imap4flags/tag-flags.c @@ -7,6 +7,7 @@ #include "mail-storage.h" #include "sieve-code.h" +#include "sieve-stringlist.h" #include "sieve-extensions.h" #include "sieve-commands.h" #include "sieve-result.h" @@ -256,12 +257,12 @@ static bool seff_flags_read_context const struct sieve_runtime_env *renv, sieve_size_t *address, void **se_context) { - bool result = TRUE; + int ret; struct sieve_operand operand; pool_t pool = sieve_result_pool(renv->result); struct seff_flags_context *ctx; string_t *flags_item; - struct sieve_coded_stringlist *flag_list; + struct sieve_stringlist *flag_list; ctx = p_new(pool, struct seff_flags_context, 1); p_array_init(&ctx->keywords, pool, 2); @@ -293,8 +294,7 @@ static bool seff_flags_read_context /* Unpack */ flags_item = NULL; - while ( (result=sieve_coded_stringlist_next_item(flag_list, &flags_item)) && - flags_item != NULL ) { + while ( (ret=sieve_stringlist_next_item(flag_list, &flags_item)) > 0 ) { const char *flag; struct ext_imap4flags_iter flit; @@ -328,7 +328,7 @@ static bool seff_flags_read_context t_pop(); - return result; + return ( ret >= 0 ); } /* Result verification */ diff --git a/src/lib-sieve/plugins/imap4flags/tst-hasflag.c b/src/lib-sieve/plugins/imap4flags/tst-hasflag.c index fd370e913..b6ea02ed5 100644 --- a/src/lib-sieve/plugins/imap4flags/tst-hasflag.c +++ b/src/lib-sieve/plugins/imap4flags/tst-hasflag.c @@ -4,6 +4,7 @@ #include "lib.h" #include "sieve-commands.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-comparators.h" #include "sieve-match-types.h" @@ -170,52 +171,17 @@ static bool tst_hasflag_operation_dump /* * Interpretation */ - -static int _flag_key_extract_init -(void **context, string_t *raw_key) -{ - struct ext_imap4flags_iter *iter = t_new(struct ext_imap4flags_iter, 1); - - ext_imap4flags_iter_init(iter, raw_key); - - *context = iter; - - return TRUE; -} - -static int _flag_key_extract -(void *context, const char **key, size_t *size) -{ - struct ext_imap4flags_iter *iter = (struct ext_imap4flags_iter *) context; - - if ( (*key = ext_imap4flags_iter_get_flag(iter)) != NULL ) { - *size = strlen(*key); - return TRUE; - } - - return FALSE; -} - -static const struct sieve_match_key_extractor _flag_extractor = { - _flag_key_extract_init, - _flag_key_extract -}; static int tst_hasflag_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { - int mret; - bool result = TRUE; int opt_code = 0; struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator); - struct sieve_match_type mtch = + struct sieve_match_type mcht = SIEVE_MATCH_TYPE_DEFAULT(is_match_type); - struct sieve_match_context *mctx; - struct sieve_coded_stringlist *flag_list, *variables_list = NULL; - struct ext_imap4flags_iter iter; - const char *flag; - bool matched; + struct sieve_stringlist *flag_list, *variables_list, *value_list, *key_list; + int ret; /* * Read operands @@ -223,12 +189,12 @@ static int tst_hasflag_operation_execute /* Optional operands */ + variables_list = NULL; for (;;) { bool opok = TRUE; - int ret; if ( (ret=sieve_match_opr_optional_read - (renv, address, &opt_code, &cmp, &mtch)) < 0 ) + (renv, address, &opt_code, &cmp, &mcht)) < 0 ) return SIEVE_EXEC_BIN_CORRUPT; if ( ret == 0 ) break; @@ -259,50 +225,19 @@ static int tst_hasflag_operation_execute sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "hasflag test"); - matched = FALSE; - mctx = sieve_match_begin - (renv, &mtch, &cmp, &_flag_extractor, flag_list); - - matched = FALSE; + value_list = ext_imap4flags_get_flags(renv, variables_list); - if ( variables_list != NULL ) { - string_t *var_item = NULL; - - /* Iterate through all requested variables to match */ - while ( result && !matched && - (result=sieve_coded_stringlist_next_item(variables_list, &var_item)) - && var_item != NULL ) { - - ext_imap4flags_get_flags_init(&iter, renv, var_item); - while ( !matched && (flag=ext_imap4flags_iter_get_flag(&iter)) != NULL ) { - if ( (mret=sieve_match_value(mctx, flag, strlen(flag))) < 0 ) { - result = FALSE; - break; - } - - matched = ( mret > 0 ); - } - } - } else { - ext_imap4flags_get_flags_init(&iter, renv, NULL); - while ( !matched && (flag=ext_imap4flags_iter_get_flag(&iter)) != NULL ) { - if ( (mret=sieve_match_value(mctx, flag, strlen(flag))) < 0 ) { - result = FALSE; - break; - } - - matched = ( mret > 0 ); - } - } + if ( sieve_match_type_is(&mcht, is_match_type) || + sieve_match_type_is(&mcht, contains_match_type) ) + key_list = ext_imap4flags_get_flags(renv, flag_list); + else + key_list = flag_list; - if ( (mret=sieve_match_end(&mctx)) < 0 ) { - result = FALSE; - } else - matched = ( mret > 0 || matched ); + ret = sieve_match(renv, &mcht, &cmp, value_list, key_list); /* Assign test result */ - if ( result ) { - sieve_interpreter_set_test_result(renv->interp, matched); + if ( ret >= 0 ) { + sieve_interpreter_set_test_result(renv->interp, ret > 0); return SIEVE_EXEC_OK; } diff --git a/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c b/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c index 9c57204c1..aead5b0d5 100644 --- a/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c +++ b/src/lib-sieve/plugins/mailbox/tst-mailboxexists.c @@ -7,6 +7,7 @@ #include "sieve-common.h" #include "sieve-commands.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-validator.h" #include "sieve-generator.h" @@ -105,9 +106,9 @@ static bool tst_mailboxexists_operation_dump static int tst_mailboxexists_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { - struct sieve_coded_stringlist *mailbox_names; + struct sieve_stringlist *mailbox_names; string_t *mailbox_item; - bool result = TRUE, all_exist = TRUE; + bool all_exist = TRUE; /* * Read operands @@ -125,10 +126,11 @@ static int tst_mailboxexists_operation_execute sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "mailboxexists test"); if ( renv->scriptenv->user != NULL ) { + int ret; + mailbox_item = NULL; - while ( (result=sieve_coded_stringlist_next_item - (mailbox_names, &mailbox_item)) - && mailbox_item != NULL ) { + while ( (ret=sieve_stringlist_next_item(mailbox_names, &mailbox_item)) > 0 ) + { struct mail_namespace *ns; const char *mailbox = str_c(mailbox_item); struct mailbox *box; @@ -157,11 +159,11 @@ static int tst_mailboxexists_operation_execute /* Close mailbox */ mailbox_free(&box); } - } - if ( !result ) { - sieve_runtime_trace_error(renv, "invalid mailbox name item"); - return SIEVE_EXEC_BIN_CORRUPT; + if ( ret < 0 ) { + sieve_runtime_trace_error(renv, "invalid mailbox name item"); + return SIEVE_EXEC_BIN_CORRUPT; + } } sieve_interpreter_set_test_result(renv->interp, all_exist); diff --git a/src/lib-sieve/plugins/notify/cmd-denotify.c b/src/lib-sieve/plugins/notify/cmd-denotify.c index 82c1baa0e..0a920006d 100644 --- a/src/lib-sieve/plugins/notify/cmd-denotify.c +++ b/src/lib-sieve/plugins/notify/cmd-denotify.c @@ -4,6 +4,7 @@ #include "lib.h" #include "sieve-common.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-extensions.h" #include "sieve-ast.h" @@ -279,7 +280,7 @@ static int cmd_denotify_operation_execute SIEVE_MATCH_TYPE_DEFAULT(is_match_type); const struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_octet_comparator); - struct sieve_coded_stringlist *match_key = NULL; + struct sieve_stringlist *match_key = NULL; sieve_number_t importance = 0; struct sieve_match_context *mctx; struct sieve_result_iterate_context *rictx; @@ -339,7 +340,7 @@ static int cmd_denotify_operation_execute if ( match_key != NULL ) { /* Initialize match */ - mctx = sieve_match_begin(renv, &mcht, &cmp, NULL, match_key); + mctx = sieve_match_begin(renv, &mcht, &cmp); /* Iterate through all actions */ rictx = sieve_result_iterate_init(renv->result); @@ -351,8 +352,8 @@ static int cmd_denotify_operation_execute (struct ext_notify_action *) action->context; if ( importance == 0 || nact->importance == importance ) { - if ( (ret=sieve_match_value(mctx, nact->id, strlen(nact->id))) - < 0 ) { + if ( (ret=sieve_match_value + (mctx, nact->id, strlen(nact->id), match_key)) < 0 ) { result = FALSE; break; } @@ -364,12 +365,11 @@ static int cmd_denotify_operation_execute } /* Finish match */ - if ( sieve_match_end(&mctx) < 0 ) - result = FALSE; + (void)sieve_match_end(&mctx); - if ( !result ) { - sieve_runtime_trace_error(renv, "invalid string-list item"); - return SIEVE_EXEC_BIN_CORRUPT; + if ( !result ) { + sieve_runtime_trace_error(renv, "invalid string-list item"); + return SIEVE_EXEC_BIN_CORRUPT; } } else { /* Iterate through all actions */ diff --git a/src/lib-sieve/plugins/notify/cmd-notify.c b/src/lib-sieve/plugins/notify/cmd-notify.c index 813d07d23..e0e03ba76 100644 --- a/src/lib-sieve/plugins/notify/cmd-notify.c +++ b/src/lib-sieve/plugins/notify/cmd-notify.c @@ -12,6 +12,7 @@ #include "rfc2822.h" #include "sieve-common.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-extensions.h" #include "sieve-commands.h" @@ -417,7 +418,7 @@ static int cmd_notify_operation_execute pool_t pool; int opt_code = 0; sieve_number_t importance = 1; - struct sieve_coded_stringlist *options = NULL; + struct sieve_stringlist *options = NULL; string_t *message = NULL, *id = NULL; unsigned int source_line; @@ -481,7 +482,7 @@ static int cmd_notify_operation_execute if ( options != NULL ) { string_t *raw_address; string_t *out_message; - bool result; + int ret; pool = sieve_result_pool(renv->result); act = p_new(pool, struct ext_notify_action, 1); @@ -498,13 +499,12 @@ static int cmd_notify_operation_execute /* Normalize and verify all :options addresses */ - sieve_coded_stringlist_reset(options); + sieve_stringlist_reset(options); p_array_init(&act->recipients, pool, 4); raw_address = NULL; - while ( (result=sieve_coded_stringlist_next_item(options, &raw_address)) - && raw_address != NULL ) { + while ( (ret=sieve_stringlist_next_item(options, &raw_address)) > 0 ) { const char *error = NULL; const char *addr_norm = sieve_address_normalize(raw_address, &error); @@ -557,7 +557,7 @@ static int cmd_notify_operation_execute } } - if ( !result ) { + if ( ret < 0 ) { sieve_runtime_trace_error(renv, "invalid options stringlist"); return SIEVE_EXEC_BIN_CORRUPT; } diff --git a/src/lib-sieve/plugins/regex/mcht-regex.c b/src/lib-sieve/plugins/regex/mcht-regex.c index 2fda6940a..793edcbf3 100644 --- a/src/lib-sieve/plugins/regex/mcht-regex.c +++ b/src/lib-sieve/plugins/regex/mcht-regex.c @@ -9,10 +9,12 @@ #include "buffer.h" #include "array.h" #include "str.h" +#include "str-sanitize.h" #include "sieve-common.h" #include "sieve-limits.h" #include "sieve-ast.h" +#include "sieve-stringlist.h" #include "sieve-commands.h" #include "sieve-validator.h" #include "sieve-comparators.h" @@ -40,18 +42,19 @@ static bool mcht_regex_validate_context struct sieve_match_type_context *ctx, struct sieve_ast_argument *key_arg); static void mcht_regex_match_init(struct sieve_match_context *mctx); -static int mcht_regex_match +static int mcht_regex_match_keys (struct sieve_match_context *mctx, const char *val, size_t val_size, - const char *key, size_t key_size, int key_index); -static int mcht_regex_match_deinit(struct sieve_match_context *mctx); + struct sieve_stringlist *key_list); +static void mcht_regex_match_deinit(struct sieve_match_context *mctx); const struct sieve_match_type_def regex_match_type = { SIEVE_OBJECT("regex", ®ex_match_type_operand, 0), - TRUE, FALSE, NULL, mcht_regex_validate_context, + NULL, mcht_regex_match_init, - mcht_regex_match, + mcht_regex_match_keys, + NULL, mcht_regex_match_deinit }; @@ -170,11 +173,16 @@ static bool mcht_regex_validate_context * Match type implementation */ +struct mcht_regex_key { + regex_t regexp; + int status; +}; + struct mcht_regex_context { - ARRAY_DEFINE(reg_expressions, regex_t); - int value_index; + ARRAY_DEFINE(reg_expressions, struct mcht_regex_key); regmatch_t *pmatch; size_t nmatch; + unsigned int all_compiled:1; }; static void mcht_regex_match_init @@ -185,8 +193,6 @@ static void mcht_regex_match_init /* Create context */ ctx = p_new(pool, struct mcht_regex_context, 1); - p_array_init(&ctx->reg_expressions, pool, 4); - ctx->value_index = -1; /* Create storage for match values if match values are requested */ if ( sieve_match_values_are_enabled(mctx->runenv) ) { @@ -201,72 +207,20 @@ static void mcht_regex_match_init mctx->data = (void *) ctx; } -static regex_t *mcht_regex_get -(struct mcht_regex_context *ctx, - const struct sieve_comparator *cmp, - const char *key, unsigned int key_index) -{ - int ret; - int cflags; - regex_t *regexp; - - /* If this is the first matched value, the regexes are not compiled - * yet. - */ - if ( ctx->value_index <= 0 ) { - /* Allocate space */ - array_idx_clear(&ctx->reg_expressions, key_index); - regexp = array_idx_modifiable(&ctx->reg_expressions, key_index); - - /* Configure case-sensitivity according to comparator */ - if ( sieve_comparator_is(cmp, i_octet_comparator) ) - cflags = REG_EXTENDED; - else if ( sieve_comparator_is(cmp, i_ascii_casemap_comparator) ) - cflags = REG_EXTENDED | REG_ICASE; - else - return NULL; /* Not supported */ - - /* Indicate whether match values need to be produced */ - if ( ctx->nmatch == 0 ) cflags |= REG_NOSUB; - - /* Compile regular expression */ - if ( (ret=regcomp(regexp, key, cflags)) != 0 ) { - /* FIXME: Do something useful, i.e. report error somewhere */ - return NULL; - } - } else { - /* Get compiled regex from cache */ - regexp = array_idx_modifiable(&ctx->reg_expressions, key_index); - } - - return regexp; -} - -static int mcht_regex_match -(struct sieve_match_context *mctx, - const char *val, size_t val_size ATTR_UNUSED, - const char *key, size_t key_size ATTR_UNUSED, int key_index) +static int mcht_regex_match_key +(struct sieve_match_context *mctx, const char *val, + const regex_t *regexp) { struct mcht_regex_context *ctx = (struct mcht_regex_context *) mctx->data; - regex_t *regexp; - - if ( val == NULL ) { - val = ""; - val_size = 0; - } - - if ( key_index < 0 ) return FALSE; + int ret; - if ( key_index == 0 ) ctx->value_index++; + /* Execute regex */ - /* Get compiled regex */ - if ( (regexp=mcht_regex_get(ctx, mctx->comparator, key, key_index)) == NULL ) - return FALSE; + ret = regexec(regexp, val, ctx->nmatch, ctx->pmatch, 0); - /* Execute regex */ - if ( regexec(regexp, val, ctx->nmatch, ctx->pmatch, 0) == 0 ) { + /* Handle match values if necessary */ - /* Handle match values if necessary */ + if ( ret == 0 ) { if ( ctx->nmatch > 0 ) { struct sieve_match_values *mvalues; size_t i; @@ -281,13 +235,13 @@ static int mcht_regex_match /* Add match values from regular expression */ for ( i = 0; i < ctx->nmatch; i++ ) { str_truncate(subst, 0); - + if ( ctx->pmatch[i].rm_so != -1 ) { if ( skipped > 0 ) { sieve_match_values_skip(mvalues, skipped); skipped = 0; } - + str_append_n(subst, val + ctx->pmatch[i].rm_so, ctx->pmatch[i].rm_eo - ctx->pmatch[i].rm_so); sieve_match_values_add(mvalues, subst); @@ -299,25 +253,124 @@ static int mcht_regex_match sieve_match_values_commit(mctx->runenv, &mvalues); } - return TRUE; + return 1; } - - return FALSE; + + return 0; } -int mcht_regex_match_deinit +static int mcht_regex_match_keys +(struct sieve_match_context *mctx, const char *val, size_t val_size ATTR_UNUSED, + struct sieve_stringlist *key_list) +{ + const struct sieve_runtime_env *renv = mctx->runenv; + bool trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING); + struct mcht_regex_context *ctx = (struct mcht_regex_context *) mctx->data; + const struct sieve_comparator *cmp = mctx->comparator; + int result = 0; + + if ( !ctx->all_compiled ) { + string_t *key_item = NULL; + unsigned int i; + int ret; + + /* Regular expressions still need to be compiled */ + + if ( !array_is_created(&ctx->reg_expressions) ) + p_array_init(&ctx->reg_expressions, mctx->pool, 16); + + i = 0; + while ( result == 0 && + (ret=sieve_stringlist_next_item(key_list, &key_item)) > 0 ) { + + T_BEGIN { + struct mcht_regex_key *rkey; + + if ( i >= array_count(&ctx->reg_expressions) ) { + int cflags; + + rkey = array_append_space(&ctx->reg_expressions); + + /* Configure case-sensitivity according to comparator */ + if ( sieve_comparator_is(cmp, i_octet_comparator) ) + cflags = REG_EXTENDED; + else if ( sieve_comparator_is(cmp, i_ascii_casemap_comparator) ) + cflags = REG_EXTENDED | REG_ICASE; + else + rkey->status = -1; /* Not supported */ + + if ( rkey->status >= 0 ) { + /* Indicate whether match values need to be produced */ + if ( ctx->nmatch == 0 ) cflags |= REG_NOSUB; + + /* Compile regular expression */ + if ( regcomp(&rkey->regexp, str_c(key_item), cflags) != 0 ) { + /* FIXME: Do something useful, i.e. report error somewhere */ + rkey->status = -1; + } else { + rkey->status = 1; + } + } + } else { + rkey = array_idx_modifiable(&ctx->reg_expressions, 1); + } + + if ( rkey->status > 0 ) { + result = mcht_regex_match_key(mctx, val, &rkey->regexp); + + if ( trace ) { + sieve_runtime_trace(renv, 0, + " with regex `%s' [id=%d] => %d", + str_sanitize(str_c(key_item), 80), + array_count(&ctx->reg_expressions)-1, result); + } + } + } T_END; + + i++; + } + + if ( ret < 0 ) result = -1; + + } else { + const struct mcht_regex_key *rkeys; + unsigned int i, count; + + /* Regular expressions are compiled */ + + rkeys = array_get(&ctx->reg_expressions, &count); + + i = 0; + while ( result == 0 && i < count ) { + if ( rkeys[i].status > 0 ) { + result = mcht_regex_match_key(mctx, val, &rkeys[i].regexp); + + if ( trace ) { + sieve_runtime_trace(renv, 0, + " with compiled regex [id=%d] => %d", i, result); + } + } + + i++; + } + + if ( i == count ) ctx->all_compiled = TRUE; + } + + return result; +} + +void mcht_regex_match_deinit (struct sieve_match_context *mctx) { struct mcht_regex_context *ctx = (struct mcht_regex_context *) mctx->data; - regex_t *regexps; + struct mcht_regex_key *rkeys; unsigned int count, i; /* Clean up compiled regular expressions */ - regexps = array_get_modifiable(&ctx->reg_expressions, &count); + rkeys = array_get_modifiable(&ctx->reg_expressions, &count); for ( i = 0; i < count; i++ ) { - regfree(®exps[i]); + regfree(&rkeys[i].regexp); } - - return FALSE; } diff --git a/src/lib-sieve/plugins/relational/ext-relational-common.h b/src/lib-sieve/plugins/relational/ext-relational-common.h index 396c00230..17c03cb9d 100644 --- a/src/lib-sieve/plugins/relational/ext-relational-common.h +++ b/src/lib-sieve/plugins/relational/ext-relational-common.h @@ -85,9 +85,9 @@ bool mcht_relational_validate * Value match function (also used by :count) */ -int mcht_value_match - (struct sieve_match_context *mctx, const char *val, size_t val_size, - const char *key, size_t key_size, int key_index); +int mcht_value_match_key + (struct sieve_match_context *mctx, const char *val, size_t val_size, + const char *key, size_t key_size); #endif /* __EXT_RELATIONAL_COMMON_H */ diff --git a/src/lib-sieve/plugins/relational/mcht-count.c b/src/lib-sieve/plugins/relational/mcht-count.c index 27e50b263..9ec75274b 100644 --- a/src/lib-sieve/plugins/relational/mcht-count.c +++ b/src/lib-sieve/plugins/relational/mcht-count.c @@ -6,9 +6,11 @@ #include "lib.h" #include "str.h" +#include "str-sanitize.h" #include "sieve-common.h" #include "sieve-ast.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-extensions.h" #include "sieve-commands.h" @@ -17,6 +19,7 @@ #include "sieve-validator.h" #include "sieve-generator.h" #include "sieve-interpreter.h" +#include "sieve-runtime-trace.h" #include "sieve-match.h" #include "ext-relational-common.h" @@ -25,11 +28,9 @@ * Forward declarations */ -static void mcht_count_match_init(struct sieve_match_context *mctx); static int mcht_count_match - (struct sieve_match_context *mctx, const char *val, size_t val_size, - const char *key, size_t key_size, int key_index); -static int mcht_count_match_deinit(struct sieve_match_context *mctx); + (struct sieve_match_context *mctx, struct sieve_stringlist *value_list, + struct sieve_stringlist *key_list); /* * Match-type objects @@ -37,21 +38,18 @@ static int mcht_count_match_deinit(struct sieve_match_context *mctx); const struct sieve_match_type_def count_match_type = { SIEVE_OBJECT("count", &rel_match_type_operand, RELATIONAL_COUNT), - FALSE, FALSE, mcht_relational_validate, - NULL, NULL, NULL, NULL + NULL, NULL, NULL, NULL, NULL, NULL }; -#define COUNT_MATCH_TYPE(name, rel_match) \ -const struct sieve_match_type_def rel_match_count_ ## name = { \ - SIEVE_OBJECT( \ - "count-" #name, &rel_match_type_operand, \ - REL_MATCH_INDEX(RELATIONAL_COUNT, rel_match)), \ - FALSE, FALSE, \ - NULL, NULL, \ - mcht_count_match_init, \ - mcht_count_match, \ - mcht_count_match_deinit \ +#define COUNT_MATCH_TYPE(name, rel_match) \ +const struct sieve_match_type_def rel_match_count_ ## name = { \ + SIEVE_OBJECT( \ + "count-" #name, &rel_match_type_operand, \ + REL_MATCH_INDEX(RELATIONAL_COUNT, rel_match)), \ + NULL, NULL, \ + mcht_count_match, \ + NULL, NULL, NULL, NULL \ } COUNT_MATCH_TYPE(gt, REL_MATCH_GREATER); @@ -65,72 +63,48 @@ COUNT_MATCH_TYPE(ne, REL_MATCH_NOT_EQUAL); * Match-type implementation */ -struct mcht_count_context { - unsigned int count; -}; - -static void mcht_count_match_init(struct sieve_match_context *mctx) -{ - struct mcht_count_context *cctx = p_new(mctx->pool, struct mcht_count_context, 1); - - cctx->count = 0; - mctx->data = (void *) cctx; -} - static int mcht_count_match -(struct sieve_match_context *mctx, - const char *val ATTR_UNUSED, size_t val_size ATTR_UNUSED, - const char *key ATTR_UNUSED, size_t key_size ATTR_UNUSED, - int key_index) +(struct sieve_match_context *mctx, struct sieve_stringlist *value_list, + struct sieve_stringlist *key_list) { - if ( val == NULL ) - return FALSE; - - /* Count values */ - if ( key_index == -1 ) { - struct mcht_count_context *cctx = - (struct mcht_count_context *) mctx->data; - - cctx->count++; - } + const struct sieve_runtime_env *renv = mctx->runenv; + bool trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING); + int count; + string_t *key_item; + int ret; - return FALSE; -} + if ( (count=sieve_stringlist_get_length(value_list)) < 0 ) + return -1; -static int mcht_count_match_deinit(struct sieve_match_context *mctx) -{ - struct mcht_count_context *cctx = - (struct mcht_count_context *) mctx->data; - int key_index; - string_t *key_item; - sieve_coded_stringlist_reset(mctx->key_list); - bool ok = TRUE; + sieve_stringlist_reset(key_list); string_t *value = t_str_new(20); - str_printfa(value, "%d", cctx->count); - - /* Match to all key values */ - key_index = 0; - key_item = NULL; - while ( (ok=sieve_coded_stringlist_next_item(mctx->key_list, &key_item)) - && key_item != NULL ) - { - int ret = mcht_value_match - (mctx, str_c(value), str_len(value), str_c(key_item), - str_len(key_item), key_index); - - if ( ret > 0 ) - return TRUE; - - if ( ret < 0 ) - return ret; + str_printfa(value, "%d", count); - key_index++; - } + if ( trace ) { + sieve_runtime_trace(renv, 0, + " matching count value `%s'", str_sanitize(str_c(value), 80)); + } + + /* Match to all key values */ + key_item = NULL; + ret = 0; + while ( ret == 0 && + (ret=sieve_stringlist_next_item(key_list, &key_item)) > 0 ) + { + ret = mcht_value_match_key + (mctx, str_c(value), str_len(value), str_c(key_item), str_len(key_item)); + + if ( trace ) { + sieve_runtime_trace(renv, 0, + " with key `%s' => %d", str_sanitize(str_c(key_item), 80), ret); + } + } - return ( ok ? FALSE : -1 ); + return ret; } + diff --git a/src/lib-sieve/plugins/relational/mcht-value.c b/src/lib-sieve/plugins/relational/mcht-value.c index 625efb42a..fac3de9e0 100644 --- a/src/lib-sieve/plugins/relational/mcht-value.c +++ b/src/lib-sieve/plugins/relational/mcht-value.c @@ -25,20 +25,18 @@ const struct sieve_match_type_def value_match_type = { SIEVE_OBJECT("value", &rel_match_type_operand, RELATIONAL_VALUE), - TRUE, TRUE, mcht_relational_validate, - NULL, NULL, NULL, NULL + NULL, NULL, NULL, NULL, NULL, NULL }; -#define VALUE_MATCH_TYPE(name, rel_match) \ +#define VALUE_MATCH_TYPE(name, rel_match) \ const struct sieve_match_type_def rel_match_value_ ## name = { \ - SIEVE_OBJECT( \ - "value-" #name, &rel_match_type_operand, \ - REL_MATCH_INDEX(RELATIONAL_VALUE, rel_match)), \ - TRUE, TRUE, \ - NULL, NULL, NULL, \ - mcht_value_match, \ - NULL \ + SIEVE_OBJECT( \ + "value-" #name, &rel_match_type_operand, \ + REL_MATCH_INDEX(RELATIONAL_VALUE, rel_match)), \ + NULL, NULL, NULL, NULL, NULL, \ + mcht_value_match_key, \ + NULL \ } VALUE_MATCH_TYPE(gt, REL_MATCH_GREATER); @@ -52,19 +50,14 @@ VALUE_MATCH_TYPE(ne, REL_MATCH_NOT_EQUAL); * Match-type implementation */ -int mcht_value_match +int mcht_value_match_key (struct sieve_match_context *mctx, const char *val, size_t val_size, - const char *key, size_t key_size, int key_index ATTR_UNUSED) + const char *key, size_t key_size) { const struct sieve_match_type *mtch = mctx->match_type; unsigned int rel_match = REL_MATCH(mtch->object.def->code); int cmp_result; - if ( val == NULL ) { - val = ""; - val_size = 0; - } - cmp_result = mctx->comparator->def-> compare(mctx->comparator, val, val_size, key, key_size); diff --git a/src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c b/src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c index a93b5d224..cda0a3e3a 100644 --- a/src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c +++ b/src/lib-sieve/plugins/spamvirustest/tst-spamvirustest.c @@ -6,6 +6,7 @@ #include "sieve-common.h" #include "sieve-extensions.h" #include "sieve-commands.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-comparators.h" #include "sieve-match-types.h" @@ -241,16 +242,14 @@ static int tst_spamvirustest_operation_execute { const struct sieve_operation *op = renv->oprtn; const struct sieve_extension *this_ext = op->ext; - bool result = TRUE, matched = FALSE; int opt_code = 0; struct sieve_match_type mcht = SIEVE_MATCH_TYPE_DEFAULT(is_match_type); struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator); bool percent = FALSE; - struct sieve_coded_stringlist *key_value; - struct sieve_match_context *mctx; - const char *value; + struct sieve_stringlist *value_list, *key_list; + const char *score_value; int ret; /* Read optional operands */ @@ -274,7 +273,7 @@ static int tst_spamvirustest_operation_execute } /* Read value part */ - if ( (key_value=sieve_opr_stringlist_read(renv, address, "value")) == NULL ) + if ( (key_list=sieve_opr_stringlist_read(renv, address, "value")) == NULL ) return SIEVE_EXEC_BIN_CORRUPT; /* Perform test */ @@ -288,30 +287,18 @@ static int tst_spamvirustest_operation_execute (renv, SIEVE_TRLVL_TESTS, "virustest test"); } - /* Initialize match */ - mctx = sieve_match_begin(renv, &mcht, &cmp, NULL, key_value); + /* Get score value */ + score_value = ext_spamvirustest_get_value(renv, this_ext, percent); - /* Perform match */ - - matched = FALSE; - - value = ext_spamvirustest_get_value(renv, this_ext, percent); - - if ( (ret=sieve_match_value(mctx, value, strlen(value))) < 0 ) { - result = FALSE; - } else { - matched = ( ret > 0 ); - } + /* Construct value list */ + value_list = sieve_single_stringlist_create_cstr(renv, score_value, TRUE); - /* Finish match */ - if ( (ret=sieve_match_end(&mctx)) < 0 ) - result = FALSE; - else - matched = ( ret > 0 || matched ); + /* Perform match */ + ret = sieve_match(renv, &mcht, &cmp, value_list, key_list); /* Set test result for subsequent conditional jump */ - if ( result ) { - sieve_interpreter_set_test_result(renv->interp, matched); + if ( ret >= 0 ) { + sieve_interpreter_set_test_result(renv->interp, ret > 0); return SIEVE_EXEC_OK; } diff --git a/src/lib-sieve/plugins/vacation/cmd-vacation.c b/src/lib-sieve/plugins/vacation/cmd-vacation.c index 6152eaf0c..01aaab836 100644 --- a/src/lib-sieve/plugins/vacation/cmd-vacation.c +++ b/src/lib-sieve/plugins/vacation/cmd-vacation.c @@ -14,6 +14,7 @@ #include "rfc2822.h" #include "sieve-common.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-address.h" #include "sieve-extensions.h" @@ -541,7 +542,7 @@ static int ext_vacation_operation_execute int opt_code = 0; sieve_number_t days = 7; bool mime = FALSE; - struct sieve_coded_stringlist *addresses = NULL; + struct sieve_stringlist *addresses = NULL; string_t *reason, *subject = NULL, *from = NULL, *handle = NULL; unsigned int source_line; const char *from_normalized = NULL; @@ -643,15 +644,14 @@ static int ext_vacation_operation_execute if ( addresses != NULL ) { ARRAY_DEFINE(norm_addresses, const char *); string_t *raw_address; - bool result = FALSE; - - sieve_coded_stringlist_reset(addresses); + int ret; + + sieve_stringlist_reset(addresses); p_array_init(&norm_addresses, pool, 4); raw_address = NULL; - while ( (result=sieve_coded_stringlist_next_item(addresses, &raw_address)) - && raw_address != NULL ) { + while ( (ret=sieve_stringlist_next_item(addresses, &raw_address)) > 0 ) { const char *error; const char *addr_norm = sieve_address_normalize(raw_address, &error); @@ -664,7 +664,7 @@ static int ext_vacation_operation_execute } } - if ( !result ) { + if ( ret < 0 ) { sieve_runtime_trace_error(renv, "invalid addresses stringlist"); return SIEVE_EXEC_BIN_CORRUPT; } diff --git a/src/lib-sieve/plugins/variables/tst-string.c b/src/lib-sieve/plugins/variables/tst-string.c index 9e8977feb..b4184f1ec 100644 --- a/src/lib-sieve/plugins/variables/tst-string.c +++ b/src/lib-sieve/plugins/variables/tst-string.c @@ -3,6 +3,7 @@ #include "sieve-common.h" #include "sieve-commands.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-comparators.h" #include "sieve-match-types.h" @@ -160,21 +161,79 @@ static bool tst_string_operation_dump * Code execution */ +static int tst_string_stringlist_next_item + (struct sieve_stringlist *_strlist, string_t **str_r); +static void tst_string_stringlist_reset + (struct sieve_stringlist *_strlist); +static int tst_string_stringlist_get_length + (struct sieve_stringlist *_strlist); + +struct tst_string_stringlist { + struct sieve_stringlist strlist; + + struct sieve_stringlist *value_list; +}; + +static struct sieve_stringlist *tst_string_stringlist_create +(const struct sieve_runtime_env *renv, struct sieve_stringlist *value_list) +{ + struct tst_string_stringlist *strlist; + + strlist = t_new(struct tst_string_stringlist, 1); + strlist->strlist.runenv = renv; + strlist->strlist.next_item = tst_string_stringlist_next_item; + strlist->strlist.reset = tst_string_stringlist_reset; + strlist->strlist.get_length = tst_string_stringlist_get_length; + strlist->value_list = value_list; + + return &strlist->strlist; +} + +static int tst_string_stringlist_next_item +(struct sieve_stringlist *_strlist, string_t **str_r) +{ + struct tst_string_stringlist *strlist = + (struct tst_string_stringlist *)_strlist; + + return sieve_stringlist_next_item(strlist->value_list, str_r); +} + +static void tst_string_stringlist_reset +(struct sieve_stringlist *_strlist) +{ + struct tst_string_stringlist *strlist = + (struct tst_string_stringlist *)_strlist; + + sieve_stringlist_reset(strlist->value_list); +} + +static int tst_string_stringlist_get_length +(struct sieve_stringlist *_strlist) +{ + struct tst_string_stringlist *strlist = + (struct tst_string_stringlist *)_strlist; + string_t *item; + int length = 0; + int ret; + + while ( (ret=sieve_stringlist_next_item(strlist->value_list, &item)) > 0 ) { + if ( str_len(item) > 0 ) + length++; + } + + return ( ret < 0 ? -1 : length ); +} + static int tst_string_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { - int ret, mret; - bool result = TRUE; + int ret; int opt_code = 0; struct sieve_match_type mcht = SIEVE_MATCH_TYPE_DEFAULT(is_match_type); struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_octet_comparator); - struct sieve_match_context *mctx; - struct sieve_coded_stringlist *source; - struct sieve_coded_stringlist *key_list; - string_t *src_item; - bool matched; + struct sieve_stringlist *source, *value_list, *key_list; /* * Read operands @@ -205,35 +264,18 @@ static int tst_string_operation_execute sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "string test"); - mctx = sieve_match_begin(renv, &mcht, &cmp, NULL, key_list); - - /* Iterate through all requested strings to match */ - src_item = NULL; - matched = FALSE; - while ( result && !matched && - (result=sieve_coded_stringlist_next_item(source, &src_item)) - && src_item != NULL ) { - const char *src = str_len(src_item) > 0 ? str_c(src_item) : NULL; - - if ( (mret=sieve_match_value - (mctx, src, str_len(src_item))) < 0 ) { - result = FALSE; - break; - } - - matched = ( mret > 0 ); - } + /* Create wrapper string list wich does not count empty string items */ + value_list = tst_string_stringlist_create(renv, source); - if ( (mret=sieve_match_end(&mctx)) < 0 ) - result = FALSE; - else - matched = ( mret > 0 || matched ); + /* Perform match */ + ret = sieve_match(renv, &mcht, &cmp, value_list, key_list); - if ( result ) { - sieve_interpreter_set_test_result(renv->interp, matched); + /* Set test result for subsequent conditional jump */ + if ( ret >= 0 ) { + sieve_interpreter_set_test_result(renv->interp, ret > 0); return SIEVE_EXEC_OK; - } - - sieve_runtime_trace_error(renv, "invalid string list item"); + } + + sieve_runtime_trace_error(renv, "invalid string-list item"); return SIEVE_EXEC_BIN_CORRUPT; } diff --git a/src/lib-sieve/sieve-address-parts.c b/src/lib-sieve/sieve-address-parts.c index 9cae114ab..540faf4ff 100644 --- a/src/lib-sieve/sieve-address-parts.c +++ b/src/lib-sieve/sieve-address-parts.c @@ -6,7 +6,6 @@ #include "mempool.h" #include "hash.h" #include "array.h" -#include "message-address.h" #include "str-sanitize.h" #include "sieve-extensions.h" @@ -228,67 +227,94 @@ const struct sieve_operand_def address_part_operand = { }; /* - * Address Matching + * Address-part string list */ - -int sieve_address_match -(const struct sieve_address_part *addrp, struct sieve_match_context *mctx, - const char *data) + +static int sieve_address_part_stringlist_next_item + (struct sieve_stringlist *_strlist, string_t **str_r); +static void sieve_address_part_stringlist_reset + (struct sieve_stringlist *_strlist); +static int sieve_address_part_stringlist_get_length + (struct sieve_stringlist *_strlist); + +struct sieve_address_part_stringlist { + struct sieve_stringlist strlist; + + const struct sieve_address_part *addrp; + struct sieve_address_list *addresses; +}; + +struct sieve_stringlist *sieve_address_part_stringlist_create +(const struct sieve_runtime_env *renv, const struct sieve_address_part *addrp, + struct sieve_address_list *addresses) { - 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; - - addr = message_address_parse - (pool_datastack_create(), (const unsigned char *) data, - strlen(data), 256, FALSE); - - /* Check validity of all addresses simultaneously. Unfortunately, - * errorneous addresses cannot be extracted from the address list - * and therefore :all will match against the whole header value - * which is not entirely standard. - */ - aitem = addr; - while ( aitem != NULL) { - if ( aitem->invalid_syntax ) - valid = FALSE; - aitem = aitem->next; - } + struct sieve_address_part_stringlist *strlist; - if ( !valid || addr == NULL ) { - if ( sieve_address_part_is(addrp, all_address_part) ) - result = sieve_match_value(mctx, data, strlen(data)); - else - result = FALSE; - } else { - while ( result == 0 && addr != NULL) { - /* mailbox@domain */ - struct sieve_address address; - const char *part = NULL; - - if ( addr->domain != NULL ) { - address.local_part = addr->mailbox; - address.domain = addr->domain; - - if ( addrp->def != NULL && addrp->def->extract_from ) - part = addrp->def->extract_from(addrp, &address); + strlist = t_new(struct sieve_address_part_stringlist, 1); + strlist->strlist.runenv = renv; + strlist->strlist.next_item = sieve_address_part_stringlist_next_item; + strlist->strlist.reset = sieve_address_part_stringlist_reset; + strlist->strlist.get_length = sieve_address_part_stringlist_get_length; + + strlist->addrp = addrp; + strlist->addresses = addresses; + + return &strlist->strlist; +} + +static int sieve_address_part_stringlist_next_item + (struct sieve_stringlist *_strlist, string_t **str_r) +{ + struct sieve_address_part_stringlist *strlist = + (struct sieve_address_part_stringlist *)_strlist; + struct sieve_address item; + string_t *item_unparsed; + int ret; + + *str_r = NULL; - if ( part != NULL ) - result = sieve_match_value(mctx, part, strlen(part)); - } - addr = addr->next; + while ( *str_r == NULL ) { + if ( (ret=sieve_address_list_next_item + (strlist->addresses, &item, &item_unparsed)) <= 0 ) + return ret; + + if ( item.local_part == NULL ) { + if ( item_unparsed != NULL ) { + if ( str_len(item_unparsed) == 0 || + sieve_address_part_is(strlist->addrp, all_address_part) ) + *str_r = item_unparsed; } + } else { + const struct sieve_address_part *addrp = strlist->addrp; + const char *part = NULL; + + if ( addrp->def != NULL && addrp->def->extract_from ) + part = addrp->def->extract_from(addrp, &item); + + if ( part != NULL ) + *str_r = t_str_new_const(part, strlen(part)); } - } T_END; - - return result; + } + + return 1; +} + +static void sieve_address_part_stringlist_reset + (struct sieve_stringlist *_strlist) +{ + struct sieve_address_part_stringlist *strlist = + (struct sieve_address_part_stringlist *)_strlist; + + sieve_address_list_reset(strlist->addresses); +} + +static int sieve_address_part_stringlist_get_length + (struct sieve_stringlist *_strlist) +{ + struct sieve_address_part_stringlist *strlist = + (struct sieve_address_part_stringlist *)_strlist; + + return sieve_address_list_get_length(strlist->addresses); } /* diff --git a/src/lib-sieve/sieve-address-parts.h b/src/lib-sieve/sieve-address-parts.h index 3df79c380..c72bb1a81 100644 --- a/src/lib-sieve/sieve-address-parts.h +++ b/src/lib-sieve/sieve-address-parts.h @@ -106,14 +106,18 @@ static inline bool sieve_opr_address_part_dump (denv, &sieve_address_part_operand_class, address, NULL); } +/* + * Address-part string list + */ + +struct sieve_stringlist *sieve_address_part_stringlist_create + (const struct sieve_runtime_env *renv, const struct sieve_address_part *addrp, + struct sieve_address_list *addresses); + /* * Match utility */ -int sieve_address_match -(const struct sieve_address_part *addrp, struct sieve_match_context *mctx, - const char *data); - enum sieve_addrmatch_opt_operand { SIEVE_AM_OPT_END, SIEVE_AM_OPT_COMPARATOR, diff --git a/src/lib-sieve/sieve-address.c b/src/lib-sieve/sieve-address.c index 4121ac3b7..ca7b70d59 100644 --- a/src/lib-sieve/sieve-address.c +++ b/src/lib-sieve/sieve-address.c @@ -5,12 +5,150 @@ #include "str.h" #include "str-sanitize.h" #include "rfc822-parser.h" +#include "message-address.h" #include "sieve-common.h" + #include "sieve-address.h" #include <ctype.h> +/* + * Header address list + */ + +/* Forward declarations */ + +static int sieve_header_address_list_next_string_item + (struct sieve_stringlist *_strlist, string_t **str_r); +static int sieve_header_address_list_next_item + (struct sieve_address_list *_addrlist, struct sieve_address *addr_r, + string_t **unparsed_r); +static void sieve_header_address_list_reset + (struct sieve_stringlist *_strlist); + +/* Stringlist object */ + +struct sieve_header_address_list { + struct sieve_address_list addrlist; + + struct sieve_stringlist *field_values; + const struct message_address *cur_address; +}; + +struct sieve_address_list *sieve_header_address_list_create +(const struct sieve_runtime_env *renv, struct sieve_stringlist *field_values) +{ + struct sieve_header_address_list *addrlist; + + addrlist = t_new(struct sieve_header_address_list, 1); + addrlist->addrlist.strlist.runenv = renv; + addrlist->addrlist.strlist.next_item = + sieve_header_address_list_next_string_item; + addrlist->addrlist.strlist.reset = sieve_header_address_list_reset; + addrlist->addrlist.next_item = sieve_header_address_list_next_item; + addrlist->field_values = field_values; + + return &addrlist->addrlist; +} + +static int sieve_header_address_list_next_item +(struct sieve_address_list *_addrlist, struct sieve_address *addr_r, + string_t **unparsed_r) +{ + struct sieve_header_address_list *addrlist = + (struct sieve_header_address_list *) _addrlist; + const struct message_address *aitem; + bool valid = TRUE; + + if ( addr_r != NULL ) addr_r->local_part = NULL; + if ( unparsed_r != NULL ) *unparsed_r = NULL; + + /* Parse next header field value if necessary */ + while ( addrlist->cur_address == NULL ) { + string_t *value_item = NULL; + int ret; + + /* Read next header value from source list */ + if ( (ret=sieve_stringlist_next_item(addrlist->field_values, &value_item)) + <= 0 ) + return ret; + + addrlist->cur_address = message_address_parse + (pool_datastack_create(), (const unsigned char *) str_data(value_item), + str_len(value_item), 256, FALSE); + + /* Check validity of all addresses simultaneously. Unfortunately, + * errorneous addresses cannot be extracted from the address list. + */ + aitem = addrlist->cur_address; + while ( aitem != NULL) { + if ( aitem->invalid_syntax ) + valid = FALSE; + aitem = aitem->next; + } + + if ( addrlist->cur_address == NULL || !valid ) { + addrlist->cur_address = NULL; + + if ( unparsed_r != NULL) *unparsed_r = value_item; + return 1; + } + + /* Find first usable address */ + aitem = addrlist->cur_address; + while ( aitem != NULL && aitem->domain == NULL ) { + aitem = aitem->next; + } + + addrlist->cur_address = aitem; + } + + /* Return next item */ + + if ( addr_r != NULL ) { + addr_r->local_part = addrlist->cur_address->mailbox; + addr_r->domain = addrlist->cur_address->domain; + } + + /* Find next usable address */ + aitem = addrlist->cur_address->next; + while ( aitem != NULL && aitem->domain == NULL ) { + aitem = aitem->next; + } + addrlist->cur_address = aitem; + + return 1; +} + +static int sieve_header_address_list_next_string_item +(struct sieve_stringlist *_strlist, string_t **str_r) +{ + struct sieve_address_list *addrlist = (struct sieve_address_list *)_strlist; + struct sieve_address addr; + int ret; + + if ( (ret=sieve_header_address_list_next_item(addrlist, &addr, str_r)) <= 0 ) + return ret; + + if ( addr.local_part != NULL ) { + const char *addr_str = sieve_address_to_string(&addr); + *str_r = t_str_new_const(addr_str, strlen(addr_str)); + } + + return 1; +} + +static void sieve_header_address_list_reset +(struct sieve_stringlist *_strlist) +{ + struct sieve_header_address_list *addrlist = + (struct sieve_header_address_list *)_strlist; + + sieve_stringlist_reset(addrlist->field_values); + addrlist->cur_address = NULL; +} + /* * RFC 2822 addresses */ diff --git a/src/lib-sieve/sieve-address.h b/src/lib-sieve/sieve-address.h index 830ef81c3..9ae4c2cc9 100644 --- a/src/lib-sieve/sieve-address.h +++ b/src/lib-sieve/sieve-address.h @@ -7,6 +7,9 @@ #include "lib.h" #include "strfuncs.h" +#include "sieve-common.h" +#include "sieve-stringlist.h" + /* * Generic address representation */ @@ -16,14 +19,54 @@ struct sieve_address { const char *domain; }; -static inline const char *sieve_address_to_string(const struct sieve_address *address) +static inline const char *sieve_address_to_string +(const struct sieve_address *address) +{ + if ( address == NULL || address->local_part == NULL || + address->domain == NULL ) + return NULL; + + return t_strconcat(address->local_part, "@", address->domain, NULL); +} + +/* + * Address list API + */ + +struct sieve_address_list { + struct sieve_stringlist strlist; + + int (*next_item) + (struct sieve_address_list *_addrlist, struct sieve_address *addr_r, + string_t **unparsed_r); +}; + +static inline int sieve_address_list_next_item +(struct sieve_address_list *addrlist, struct sieve_address *addr_r, + string_t **unparsed_r) { - if ( address == NULL || address->local_part == NULL || address->domain == NULL ) - return NULL; + return addrlist->next_item(addrlist, addr_r, unparsed_r); +} + +static inline void sieve_address_list_reset +(struct sieve_address_list *addrlist) +{ + return sieve_stringlist_reset(&addrlist->strlist); +} - return t_strconcat(address->local_part, "@", address->domain, NULL); +static inline int sieve_address_list_get_length +(struct sieve_address_list *addrlist) +{ + return sieve_stringlist_get_length(&addrlist->strlist); } +/* + * Header address list + */ + +struct sieve_address_list *sieve_header_address_list_create + (const struct sieve_runtime_env *renv, struct sieve_stringlist *field_values); + /* * RFC 2822 addresses */ diff --git a/src/lib-sieve/sieve-code.c b/src/lib-sieve/sieve-code.c index bccc4caa1..320a49f88 100644 --- a/src/lib-sieve/sieve-code.c +++ b/src/lib-sieve/sieve-code.c @@ -8,6 +8,7 @@ #include "sieve-common.h" #include "sieve-limits.h" #include "sieve-extensions.h" +#include "sieve-stringlist.h" #include "sieve-actions.h" #include "sieve-binary.h" #include "sieve-generator.h" @@ -18,111 +19,99 @@ #include <stdio.h> -/* return opr_r->def != NULL; - * Coded stringlist +/* + * Code stringlist */ -struct sieve_coded_stringlist { - const struct sieve_runtime_env *runenv; +/* Forward declarations */ + +static int sieve_code_stringlist_next_item + (struct sieve_stringlist *_strlist, string_t **str_r); +static void sieve_code_stringlist_reset + (struct sieve_stringlist *_strlist); +static int sieve_code_stringlist_get_length + (struct sieve_stringlist *_strlist); + +/* Coded stringlist object */ + +struct sieve_code_stringlist { + struct sieve_stringlist strlist; + sieve_size_t start_address; sieve_size_t end_address; sieve_size_t current_offset; - unsigned int length; - unsigned int index; + int length; + int index; }; -static struct sieve_coded_stringlist *sieve_coded_stringlist_create +static struct sieve_stringlist *sieve_code_stringlist_create (const struct sieve_runtime_env *renv, sieve_size_t start_address, unsigned int length, sieve_size_t end) { - struct sieve_coded_stringlist *strlist; + struct sieve_code_stringlist *strlist; if ( end > sieve_binary_block_get_size(renv->sblock) ) return NULL; - strlist = t_new(struct sieve_coded_stringlist, 1); - strlist->runenv = renv; + strlist = t_new(struct sieve_code_stringlist, 1); + strlist->strlist.runenv = renv; + strlist->strlist.next_item = sieve_code_stringlist_next_item; + strlist->strlist.reset = sieve_code_stringlist_reset; + strlist->strlist.get_length = sieve_code_stringlist_get_length; strlist->start_address = start_address; strlist->current_offset = start_address; strlist->end_address = end; strlist->length = length; strlist->index = 0; - return strlist; + return &strlist->strlist; } -bool sieve_coded_stringlist_next_item -(struct sieve_coded_stringlist *strlist, string_t **str_r) +/* Stringlist implementation */ + +static int sieve_code_stringlist_next_item +(struct sieve_stringlist *_strlist, string_t **str_r) { + struct sieve_code_stringlist *strlist = + (struct sieve_code_stringlist *) _strlist; sieve_size_t address; *str_r = NULL; + /* Check for end of list */ if ( strlist->index >= strlist->length ) - return TRUE; - else { - address = strlist->current_offset; - - if ( sieve_opr_string_read(strlist->runenv, &address, NULL, str_r) ) { - strlist->index++; - strlist->current_offset = address; - return TRUE; - } - } + return 0; + + /* Read next item */ + address = strlist->current_offset; + if ( sieve_opr_string_read(_strlist->runenv, &address, NULL, str_r) ) { + strlist->index++; + strlist->current_offset = address; + return 1; + } - return FALSE; -} - -void sieve_coded_stringlist_reset(struct sieve_coded_stringlist *strlist) -{ - strlist->current_offset = strlist->start_address; - strlist->index = 0; -} - -unsigned int sieve_coded_stringlist_get_length -(struct sieve_coded_stringlist *strlist) -{ - return strlist->length; + return -1; } -sieve_size_t sieve_coded_stringlist_get_end_address -(struct sieve_coded_stringlist *strlist) +static void sieve_code_stringlist_reset +(struct sieve_stringlist *_strlist) { - return strlist->end_address; -} + struct sieve_code_stringlist *strlist = + (struct sieve_code_stringlist *) _strlist; -sieve_size_t sieve_coded_stringlist_get_current_offset -(struct sieve_coded_stringlist *strlist) -{ - return strlist->current_offset; + strlist->current_offset = strlist->start_address; + strlist->index = 0; } -bool sieve_coded_stringlist_read_all -(struct sieve_coded_stringlist *strlist, pool_t pool, - const char * const **list_r) +static int sieve_code_stringlist_get_length +(struct sieve_stringlist *_strlist) { - bool result = FALSE; - ARRAY_DEFINE(items, const char *); - string_t *item; - - sieve_coded_stringlist_reset(strlist); - - p_array_init(&items, pool, 4); - - item = NULL; - while ( (result=sieve_coded_stringlist_next_item(strlist, &item)) && - item != NULL ) { - const char *stritem = p_strdup(pool, str_c(item)); - - array_append(&items, &stritem, 1); - } - - (void)array_append_space(&items); - *list_r = array_idx(&items, 0); + struct sieve_code_stringlist *strlist = + (struct sieve_code_stringlist *) _strlist; - return result; + return strlist->length; } -static bool sieve_coded_stringlist_dump +static bool sieve_code_stringlist_dump (const struct sieve_dumptime_env *denv, sieve_size_t *address, unsigned int length, sieve_size_t end, const char *field_name) { @@ -328,7 +317,7 @@ const struct sieve_operand_def string_operand = { static bool opr_stringlist_dump (const struct sieve_dumptime_env *denv, sieve_size_t *address, const char *field_name); -static struct sieve_coded_stringlist *opr_stringlist_read +static struct sieve_stringlist *opr_stringlist_read (const struct sieve_runtime_env *renv, sieve_size_t *address); const struct sieve_opr_stringlist_interface stringlist_interface = { @@ -715,7 +704,7 @@ bool sieve_opr_stringlist_dump return sieve_opr_stringlist_dump_data(denv, &operand, address, field_name); } -struct sieve_coded_stringlist *sieve_opr_stringlist_read_data +struct sieve_stringlist *sieve_opr_stringlist_read_data (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd, sieve_size_t *address, const char *field_name) { @@ -725,7 +714,7 @@ struct sieve_coded_stringlist *sieve_opr_stringlist_read_data if ( oprnd->def->class == &stringlist_class ) { const struct sieve_opr_stringlist_interface *intf = (const struct sieve_opr_stringlist_interface *) oprnd->def->interface; - struct sieve_coded_stringlist *strlist; + struct sieve_stringlist *strlist; if ( intf->read == NULL ) return NULL; @@ -748,7 +737,7 @@ struct sieve_coded_stringlist *sieve_opr_stringlist_read_data return NULL; } - return sieve_coded_stringlist_create(renv, oprnd->address, 1, *address); + return sieve_code_stringlist_create(renv, oprnd->address, 1, *address); } sieve_runtime_trace_operand_error(renv, oprnd, field_name, @@ -757,7 +746,7 @@ struct sieve_coded_stringlist *sieve_opr_stringlist_read_data return NULL; } -struct sieve_coded_stringlist *sieve_opr_stringlist_read +struct sieve_stringlist *sieve_opr_stringlist_read (const struct sieve_runtime_env *renv, sieve_size_t *address, const char *field_name) { @@ -786,13 +775,13 @@ static bool opr_stringlist_dump if ( !sieve_binary_read_unsigned(denv->sblock, address, &length) ) return FALSE; - return sieve_coded_stringlist_dump(denv, address, length, end, field_name); + return sieve_code_stringlist_dump(denv, address, length, end, field_name); } -static struct sieve_coded_stringlist *opr_stringlist_read +static struct sieve_stringlist *opr_stringlist_read (const struct sieve_runtime_env *renv, sieve_size_t *address ) { - struct sieve_coded_stringlist *strlist; + struct sieve_stringlist *strlist; sieve_size_t pc = *address; sieve_size_t end; unsigned int length = 0; @@ -806,7 +795,8 @@ static struct sieve_coded_stringlist *opr_stringlist_read if ( !sieve_binary_read_unsigned(renv->sblock, address, &length) ) return NULL; - strlist = sieve_coded_stringlist_create(renv, *address, (unsigned int) length, end); + strlist = sieve_code_stringlist_create + (renv, *address, (unsigned int) length, end); /* Skip over the string list for now */ *address = end; diff --git a/src/lib-sieve/sieve-code.h b/src/lib-sieve/sieve-code.h index a350ecc5e..7f8ce700e 100644 --- a/src/lib-sieve/sieve-code.h +++ b/src/lib-sieve/sieve-code.h @@ -14,27 +14,6 @@ #include "sieve-runtime-trace.h" #include "sieve-dump.h" -/* - * Coded string list - */ - -struct sieve_coded_stringlist; - -bool sieve_coded_stringlist_next_item - (struct sieve_coded_stringlist *strlist, string_t **str_r); -void sieve_coded_stringlist_reset - (struct sieve_coded_stringlist *strlist); -bool sieve_coded_stringlist_read_all - (struct sieve_coded_stringlist *strlist, pool_t pool, - const char * const **list_r); - -unsigned int sieve_coded_stringlist_get_length - (struct sieve_coded_stringlist *strlist); -sieve_size_t sieve_coded_stringlist_get_end_address - (struct sieve_coded_stringlist *strlist); -sieve_size_t sieve_coded_stringlist_get_current_offset - (struct sieve_coded_stringlist *strlist); - /* * Operand object */ @@ -178,7 +157,7 @@ struct sieve_opr_stringlist_interface { bool (*dump) (const struct sieve_dumptime_env *denv, sieve_size_t *address, const char *field_name); - struct sieve_coded_stringlist *(*read) + struct sieve_stringlist *(*read) (const struct sieve_runtime_env *renv, sieve_size_t *address); }; @@ -266,10 +245,10 @@ bool sieve_opr_stringlist_dump_data bool sieve_opr_stringlist_dump (const struct sieve_dumptime_env *denv, sieve_size_t *address, const char *field_name); -struct sieve_coded_stringlist *sieve_opr_stringlist_read_data +struct sieve_stringlist *sieve_opr_stringlist_read_data (const struct sieve_runtime_env *renv, const struct sieve_operand *operand, sieve_size_t *address, const char *field_name); -struct sieve_coded_stringlist *sieve_opr_stringlist_read +struct sieve_stringlist *sieve_opr_stringlist_read (const struct sieve_runtime_env *renv, sieve_size_t *address, const char *field_name); diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h index a2edd81ab..260d46110 100644 --- a/src/lib-sieve/sieve-common.h +++ b/src/lib-sieve/sieve-common.h @@ -44,6 +44,9 @@ struct sieve_command_def; struct sieve_command_context; struct sieve_command_registration; +/* sieve-stringlist.h */ +struct sieve_stringlist; + /* sieve-code.h */ struct sieve_operation_extension; @@ -107,6 +110,7 @@ struct sieve_match_context; /* sieve-address.h */ struct sieve_address; +struct sieve_address_list; /* sieve-address-parts.h */ struct sieve_address_part_def; diff --git a/src/lib-sieve/sieve-match-types.h b/src/lib-sieve/sieve-match-types.h index dd040fb56..2a0e68f3c 100644 --- a/src/lib-sieve/sieve-match-types.h +++ b/src/lib-sieve/sieve-match-types.h @@ -37,16 +37,6 @@ extern const struct sieve_match_type_def matches_match_type; struct sieve_match_type_def { struct sieve_object_def obj_def; - - /* Match function called for every key value or should it be called once - * for every tested value? (TRUE = first alternative) - */ - bool is_iterative; - - /* Is the key value allowed to contain formatting to extract multiple keys - * out of the same string? - */ - bool allow_key_extract; bool (*validate) (struct sieve_validator *valdtr, struct sieve_ast_argument **arg, @@ -59,18 +49,24 @@ struct sieve_match_type_def { * Matching */ - void (*match_init)(struct sieve_match_context *mctx); + /* Custom implementation */ - /* WARNING: some tests may pass a val == NULL parameter indicating that the - * passed value has no significance. For string-type matches this should map - * to the empty string "", but for match types that consider the passed values - * as objects rather than strings (e.g. :count) this means that the passed - * value should be skipped. - */ int (*match) + (struct sieve_match_context *mctx, struct sieve_stringlist *value_list, + struct sieve_stringlist *key_list); + + /* Default match loop */ + + void (*match_init)(struct sieve_match_context *mctx); + + int (*match_keys) + (struct sieve_match_context *mctx, const char *val, size_t val_size, + struct sieve_stringlist *key_list); + int (*match_key) (struct sieve_match_context *mctx, const char *val, size_t val_size, - const char *key, size_t key_size, int key_index); - int (*match_deinit)(struct sieve_match_context *mctx); + const char *key, size_t key_size); + + void (*match_deinit)(struct sieve_match_context *mctx); }; /* @@ -88,6 +84,8 @@ struct sieve_match_type { #define sieve_match_type_name(mcht) \ ( (mcht)->object.def->identifier ) +#define sieve_match_type_is(mcht, definition) \ + ( (mcht)->def == &(definition) ) static inline const struct sieve_match_type *sieve_match_type_copy (pool_t pool, const struct sieve_match_type *cmp_orig) diff --git a/src/lib-sieve/sieve-match.c b/src/lib-sieve/sieve-match.c index 19e5c7520..b0b2acda2 100644 --- a/src/lib-sieve/sieve-match.c +++ b/src/lib-sieve/sieve-match.c @@ -9,6 +9,7 @@ #include "sieve-extensions.h" #include "sieve-commands.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-binary.h" #include "sieve-validator.h" @@ -26,28 +27,35 @@ */ struct sieve_match_context *sieve_match_begin -(const struct sieve_runtime_env *renv, const struct sieve_match_type *mcht, - const struct sieve_comparator *cmp, - const struct sieve_match_key_extractor *kextract, - struct sieve_coded_stringlist *key_list) +(const struct sieve_runtime_env *renv, + const struct sieve_match_type *mcht, + const struct sieve_comparator *cmp) { struct sieve_match_context *mctx; pool_t pool; + /* Reject unimplemented match-type */ + if ( mcht->def == NULL || (mcht->def->match == NULL && + mcht->def->match_keys == NULL && mcht->def->match_key == NULL) ) + return NULL; + + /* Create match context */ pool = pool_alloconly_create("sieve_match_context", 1024); mctx = p_new(pool, struct sieve_match_context, 1); - mctx->pool = pool; mctx->runenv = renv; mctx->match_type = mcht; mctx->comparator = cmp; - mctx->kextract = kextract; - mctx->key_list = key_list; + mctx->trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING); - sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING, - " starting `:%s' match with `%s' comparator:", sieve_match_type_name(mcht), - sieve_comparator_name(cmp)); + /* Trace */ + if ( mctx->trace ) { + sieve_runtime_trace(renv, 0, + " starting `:%s' match with `%s' comparator:", + sieve_match_type_name(mcht), sieve_comparator_name(cmp)); + } + /* Initialize match type */ if ( mcht->def != NULL && mcht->def->match_init != NULL ) { mcht->def->match_init(mctx); } @@ -56,107 +64,110 @@ struct sieve_match_context *sieve_match_begin } int sieve_match_value -(struct sieve_match_context *mctx, const char *value, size_t val_size) +(struct sieve_match_context *mctx, const char *value, size_t value_size, + struct sieve_stringlist *key_list) { - 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 ) { - mctx->status = FALSE; - return FALSE; - } + const struct sieve_runtime_env *renv = mctx->runenv; + int result = 0; - if ( trace ) { + if ( mctx->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; + /* Match to key values */ - while ( (ok=sieve_coded_stringlist_next_item(mctx->key_list, &key_item)) - && key_item != NULL ) { + sieve_stringlist_reset(key_list); + + if ( mcht->def->match_keys != NULL ) { + /* Call match-type's own key match handler */ + result = mcht->def->match_keys(mctx, value, value_size, key_list); + } else { + string_t *key_item = NULL; + int ret; + + /* Default key match loop */ + while ( result == 0 && + (ret=sieve_stringlist_next_item(key_list, &key_item)) > 0 ) { T_BEGIN { - if ( mctx->kextract != NULL && mcht->def->allow_key_extract ) { - const struct sieve_match_key_extractor *kext = mctx->kextract; - void *kctx; - - if ( (ret=kext->init(&kctx, key_item)) > 0 ) { - const char *key; - size_t key_size; - - while ( (ret=kext->extract_key(kctx, &key, &key_size)) > 0 ) { - ret = mcht->def->match - (mctx, value, val_size, key, key_size, key_index); - - if ( trace ) { - sieve_runtime_trace(renv, 0, - " with key `%s' => %d", str_sanitize(key, 80), ret); - } - - if ( ret != 0 ) break; - } - } - } else { - ret = mcht->def->match(mctx, value, val_size, str_c(key_item), - str_len(key_item), key_index); - - if ( trace ) { - sieve_runtime_trace(renv, 0, - " with key `%s' => %d", str_sanitize(str_c(key_item), 80), ret); - } + result = mcht->def->match_key + (mctx, value, value_size, str_c(key_item), str_len(key_item)); + + if ( mctx->trace ) { + sieve_runtime_trace(renv, 0, + " with key `%s' => %d", str_sanitize(str_c(key_item), 80), + result); } } T_END; - - if ( ret != 0 ) - break; - - key_index++; } - if ( !ok ) ret = -1; - - } else { - T_BEGIN { - ret = mcht->def->match(mctx, value, val_size, NULL, 0, -1); - } T_END; + if ( ret < 0 ) result = -1; } - mctx->status = ret; - return ret; + if ( mctx->status < 0 || result < 0 ) + mctx->status = -1; + else + mctx->status = ( mctx->status > result ? mctx->status : result ); + return result; } 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; + const struct sieve_runtime_env *renv = (*mctx)->runenv; + int result = (*mctx)->status; - if ( mcht->def != NULL && mcht->def->match_deinit != NULL ) { - ret = mcht->def->match_deinit(*mctx); - } + if ( mcht->def != NULL && mcht->def->match_deinit != NULL ) + mcht->def->match_deinit(*mctx); pool_unref(&(*mctx)->pool); - *mctx = NULL; - - if ( ret < 0 || status < 0 ) - status = ( ret <= status ? ret : status ); - else - status = status || ret; sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING, " finishing match with result: %s", - ( status > 0 ? "true" : ( status < 0 ? "error" : "false" ) )); + ( result > 0 ? "matched" : ( result < 0 ? "error" : "not matched" ) )); + + return result; +} + +int sieve_match +(const struct sieve_runtime_env *renv, + const struct sieve_match_type *mcht, + const struct sieve_comparator *cmp, + struct sieve_stringlist *value_list, + struct sieve_stringlist *key_list) +{ + struct sieve_match_context *mctx; + string_t *value_item = NULL; + int result, ret; + + if ( (mctx=sieve_match_begin(renv, mcht, cmp)) == NULL ) + return 0; + + /* Match value to keys */ + + sieve_stringlist_reset(value_list); + + if ( mcht->def->match != NULL ) { + /* Call match-type's match handler */ + result = mcht->def->match(mctx, value_list, key_list); + + } else { + /* Default value match loop */ + + result = 0; + while ( result == 0 && + (ret=sieve_stringlist_next_item(value_list, &value_item)) > 0 ) { + + result = sieve_match_value + (mctx, str_c(value_item), str_len(value_item), key_list); + } + + if ( ret < 0 ) result = -1; + } - return ret; + (void)sieve_match_end(&mctx); + return result; } /* diff --git a/src/lib-sieve/sieve-match.h b/src/lib-sieve/sieve-match.h index ed3c1d79c..e32bae1eb 100644 --- a/src/lib-sieve/sieve-match.h +++ b/src/lib-sieve/sieve-match.h @@ -9,40 +9,43 @@ /* * Matching context */ - -struct sieve_match_key_extractor { - int (*init)(void **context, string_t *raw_key); - int (*extract_key)(void *context, const char **key, size_t *size); -}; struct sieve_match_context { pool_t pool; const struct sieve_runtime_env *runenv; + const struct sieve_match_type *match_type; const struct sieve_comparator *comparator; - const struct sieve_match_key_extractor *kextract; - struct sieve_coded_stringlist *key_list; + void *data; int status; - void *data; + unsigned int trace:1; }; /* * Matching implementation */ +/* Manual value iteration (for when multiple matches are allowed) */ struct sieve_match_context *sieve_match_begin (const struct sieve_runtime_env *renv, - const struct sieve_match_type *mtch, - const struct sieve_comparator *cmp, - const struct sieve_match_key_extractor *kextract, - struct sieve_coded_stringlist *key_list); + const struct sieve_match_type *mcht, + const struct sieve_comparator *cmp); int sieve_match_value - (struct sieve_match_context *mctx, const char *value, size_t val_size); + (struct sieve_match_context *mctx, const char *value, size_t value_size, + struct sieve_stringlist *key_list); int sieve_match_end(struct sieve_match_context **mctx); +/* Default matching operation */ +int sieve_match + (const struct sieve_runtime_env *renv, + const struct sieve_match_type *mcht, + const struct sieve_comparator *cmp, + struct sieve_stringlist *value_list, + struct sieve_stringlist *key_list); + /* * Read matching operands */ diff --git a/src/lib-sieve/sieve-message.c b/src/lib-sieve/sieve-message.c index c54e867d4..a5f890c73 100644 --- a/src/lib-sieve/sieve-message.c +++ b/src/lib-sieve/sieve-message.c @@ -5,10 +5,14 @@ #include "ioloop.h" #include "mempool.h" #include "array.h" +#include "str.h" +#include "mail-storage.h" #include "sieve-common.h" +#include "sieve-stringlist.h" #include "sieve-error.h" #include "sieve-extensions.h" +#include "sieve-runtime.h" #include "sieve-address.h" #include "sieve-message.h" @@ -191,5 +195,107 @@ const char *sieve_message_get_sender return sieve_address_to_string(msgctx->envelope_sender); } +/* + * Header stringlist + */ + +/* Forward declarations */ + +static int sieve_message_header_stringlist_next_item + (struct sieve_stringlist *_strlist, string_t **str_r); +static void sieve_message_header_stringlist_reset + (struct sieve_stringlist *_strlist); + +/* String list object */ + +struct sieve_message_header_stringlist { + struct sieve_stringlist strlist; + + struct sieve_stringlist *field_names; + + const char *const *headers; + int headers_index; +}; + +struct sieve_stringlist *sieve_message_header_stringlist_create +(const struct sieve_runtime_env *renv, struct sieve_stringlist *field_names) +{ + struct sieve_message_header_stringlist *strlist; + + strlist = t_new(struct sieve_message_header_stringlist, 1); + strlist->strlist.runenv = renv; + strlist->strlist.next_item = sieve_message_header_stringlist_next_item; + strlist->strlist.reset = sieve_message_header_stringlist_reset; + strlist->field_names = field_names; + + return &strlist->strlist; +} + +static inline string_t *_header_right_trim(const char *raw) +{ + string_t *result; + int i; + + for ( i = strlen(raw)-1; i >= 0; i-- ) { + if ( raw[i] != ' ' && raw[i] != '\t' ) break; + } + + result = t_str_new(i+1); + str_append_n(result, raw, i + 1); + return result; +} + +/* String list implementation */ + +static int sieve_message_header_stringlist_next_item +(struct sieve_stringlist *_strlist, string_t **str_r) +{ + struct sieve_message_header_stringlist *strlist = + (struct sieve_message_header_stringlist *) _strlist; + const struct sieve_runtime_env *renv = _strlist->runenv; + struct mail *mail = renv->msgdata->mail; + + *str_r = NULL; + + /* Check for end of current header list */ + if ( strlist->headers == NULL ) { + strlist->headers_index = 0; + } else if ( strlist->headers[strlist->headers_index] == NULL ) { + strlist->headers = NULL; + strlist->headers_index = 0; + } + + /* Fetch next header */ + while ( strlist->headers == NULL ) { + string_t *hdr_item = NULL; + int ret; + + /* Read next header name from source list */ + if ( (ret=sieve_stringlist_next_item(strlist->field_names, &hdr_item)) + <= 0 ) + return ret; + + /* Fetch all matching headers from the e-mail */ + if ( mail_get_headers_utf8(mail, str_c(hdr_item), &strlist->headers) < 0 || + ( strlist->headers != NULL && strlist->headers[0] == NULL ) ) { + /* Try next item when this fails somehow */ + strlist->headers = NULL; + continue; + } + } + /* Return next item */ + *str_r = _header_right_trim(strlist->headers[strlist->headers_index++]); + return 1; +} +static void sieve_message_header_stringlist_reset +(struct sieve_stringlist *_strlist) +{ + struct sieve_message_header_stringlist *strlist = + (struct sieve_message_header_stringlist *) _strlist; + + strlist->headers = NULL; + strlist->headers_index = 0; + sieve_stringlist_reset(strlist->field_names); +} diff --git a/src/lib-sieve/sieve-message.h b/src/lib-sieve/sieve-message.h index 1e7555aa4..a7c145e57 100644 --- a/src/lib-sieve/sieve-message.h +++ b/src/lib-sieve/sieve-message.h @@ -48,5 +48,12 @@ const char *sieve_message_get_recipient const char *sieve_message_get_sender (struct sieve_message_context *msgctx); + +/* + * Header stringlist + */ + +struct sieve_stringlist *sieve_message_header_stringlist_create + (const struct sieve_runtime_env *renv, struct sieve_stringlist *field_names); #endif /* __SIEVE_MESSAGE_H */ diff --git a/src/lib-sieve/sieve-stringlist.c b/src/lib-sieve/sieve-stringlist.c new file mode 100644 index 000000000..d3f7bc38f --- /dev/null +++ b/src/lib-sieve/sieve-stringlist.c @@ -0,0 +1,139 @@ +#include "lib.h" +#include "array.h" +#include "str.h" + +#include "sieve-common.h" +#include "sieve-stringlist.h" + +/* + * Default implementation + */ + +bool sieve_stringlist_read_all +(struct sieve_stringlist *strlist, pool_t pool, + const char * const **list_r) +{ + if ( strlist->read_all == NULL ) { + ARRAY_DEFINE(items, const char *); + string_t *item; + int ret; + + sieve_stringlist_reset(strlist); + + p_array_init(&items, pool, 4); + + item = NULL; + while ( (ret=sieve_stringlist_next_item(strlist, &item)) > 0 ) { + const char *stritem = p_strdup(pool, str_c(item)); + + array_append(&items, &stritem, 1); + } + + (void)array_append_space(&items); + *list_r = array_idx(&items, 0); + + return ( ret >= 0 ); + } + + return strlist->read_all(strlist, pool, list_r); +} + +int sieve_stringlist_get_length +(struct sieve_stringlist *strlist) +{ + if ( strlist->get_length == NULL ) { + string_t *item; + int count = 0; + int ret; + + while ( (ret=sieve_stringlist_next_item(strlist, &item)) > 0 ) { + count++; + } + + return ( ret < 0 ? -1 : count ); + } + + return strlist->get_length(strlist); +} + +/* + * Single Stringlist + */ + +/* Object */ + +static int sieve_single_stringlist_next_item + (struct sieve_stringlist *_strlist, string_t **str_r); +static void sieve_single_stringlist_reset + (struct sieve_stringlist *_strlist); +static int sieve_single_stringlist_get_length + (struct sieve_stringlist *_strlist); + +struct sieve_single_stringlist { + struct sieve_stringlist strlist; + + string_t *value; + + unsigned int end:1; + unsigned int count_empty:1; +}; + +struct sieve_stringlist *sieve_single_stringlist_create +(const struct sieve_runtime_env *renv, string_t *str, bool count_empty) +{ + struct sieve_single_stringlist *strlist; + + strlist = t_new(struct sieve_single_stringlist, 1); + strlist->strlist.runenv = renv; + strlist->strlist.next_item = sieve_single_stringlist_next_item; + strlist->strlist.reset = sieve_single_stringlist_reset; + strlist->strlist.get_length = sieve_single_stringlist_get_length; + strlist->count_empty = count_empty; + strlist->value = str; + + return &strlist->strlist; +} + +struct sieve_stringlist *sieve_single_stringlist_create_cstr +(const struct sieve_runtime_env *renv, const char *cstr, bool count_empty) +{ + string_t *str = t_str_new_const(cstr, strlen(cstr)); + + return sieve_single_stringlist_create(renv, str, count_empty); +} + +/* Implementation */ + +static int sieve_single_stringlist_next_item +(struct sieve_stringlist *_strlist, string_t **str_r) +{ + struct sieve_single_stringlist *strlist = + (struct sieve_single_stringlist *)_strlist; + + if ( strlist->end ) { + *str_r = NULL; + return 0; + } + + *str_r = strlist->value; + strlist->end = TRUE; + return 1; +} + +static void sieve_single_stringlist_reset +(struct sieve_stringlist *_strlist) +{ + struct sieve_single_stringlist *strlist = + (struct sieve_single_stringlist *)_strlist; + + strlist->end = FALSE; +} + +static int sieve_single_stringlist_get_length +(struct sieve_stringlist *_strlist) +{ + struct sieve_single_stringlist *strlist = + (struct sieve_single_stringlist *)_strlist; + + return ( strlist->count_empty || str_len(strlist->value) > 0 ); +} diff --git a/src/lib-sieve/sieve-stringlist.h b/src/lib-sieve/sieve-stringlist.h new file mode 100644 index 000000000..c9e1ebace --- /dev/null +++ b/src/lib-sieve/sieve-stringlist.h @@ -0,0 +1,51 @@ +#ifndef __SIEVE_STRINGLIST_H +#define __SIEVE_STRINGLIST_H + +/* + * Stringlist API + */ + +struct sieve_stringlist { + const struct sieve_runtime_env *runenv; + + int (*next_item) + (struct sieve_stringlist *strlist, string_t **str_r); + void (*reset) + (struct sieve_stringlist *strlist); + int (*get_length) + (struct sieve_stringlist *strlist); + + bool (*read_all) + (struct sieve_stringlist *strlist, pool_t pool, + const char * const **list_r); +}; + +static inline int sieve_stringlist_next_item +(struct sieve_stringlist *strlist, string_t **str_r) +{ + return strlist->next_item(strlist, str_r); +} + +static inline void sieve_stringlist_reset +(struct sieve_stringlist *strlist) +{ + return strlist->reset(strlist); +} + +int sieve_stringlist_get_length + (struct sieve_stringlist *strlist); + +bool sieve_stringlist_read_all + (struct sieve_stringlist *strlist, pool_t pool, + const char * const **list_r); + +/* + * Single Stringlist + */ + +struct sieve_stringlist *sieve_single_stringlist_create + (const struct sieve_runtime_env *renv, string_t *str, bool count_empty); +struct sieve_stringlist *sieve_single_stringlist_create_cstr +(const struct sieve_runtime_env *renv, const char *cstr, bool count_empty); + +#endif /* __SIEVE_STRINGLIST_H */ diff --git a/src/lib-sieve/tst-address.c b/src/lib-sieve/tst-address.c index bf6d83feb..1e6567ce1 100644 --- a/src/lib-sieve/tst-address.c +++ b/src/lib-sieve/tst-address.c @@ -6,9 +6,12 @@ #include "sieve-common.h" #include "sieve-commands.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-comparators.h" #include "sieve-match-types.h" +#include "sieve-message.h" +#include "sieve-address.h" #include "sieve-address-parts.h" #include "sieve-validator.h" #include "sieve-generator.h" @@ -223,18 +226,14 @@ static bool tst_address_operation_dump static int tst_address_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { - bool result = TRUE; struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator); struct sieve_match_type mcht = SIEVE_MATCH_TYPE_DEFAULT(is_match_type); struct sieve_address_part addrp = SIEVE_ADDRESS_PART_DEFAULT(all_address_part); - struct sieve_match_context *mctx; - struct sieve_coded_stringlist *hdr_list; - struct sieve_coded_stringlist *key_list; - string_t *hdr_item; - bool matched; + struct sieve_stringlist *hdr_list, *hdr_value_list, *value_list, *key_list; + struct sieve_address_list *addr_list; int ret; /* Read optional operands */ @@ -254,48 +253,20 @@ static int tst_address_operation_execute sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "address test"); - /* Initialize match context */ - mctx = sieve_match_begin(renv, &mcht, &cmp, NULL, key_list); - - /* Iterate through all requested headers to match */ - hdr_item = NULL; - matched = FALSE; - while ( result && !matched && - (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 ) { - int i; - - for ( i = 0; !matched && headers[i] != NULL; i++ ) { - if ( (ret=sieve_address_match(&addrp, mctx, headers[i])) < 0 ) { - result = FALSE; - break; - } - - matched = ret > 0; - } - } - } - - /* Finish match */ + /* Create value stringlist */ + hdr_value_list = sieve_message_header_stringlist_create(renv, hdr_list); + addr_list = sieve_header_address_list_create(renv, hdr_value_list); + value_list = sieve_address_part_stringlist_create(renv, &addrp, addr_list); - if ( (ret=sieve_match_end(&mctx)) < 0 ) - result = FALSE; - else - matched = ( ret > 0 || matched ); + /* Perform match */ + ret = sieve_match(renv, &mcht, &cmp, value_list, key_list); /* Set test result for subsequent conditional jump */ - if ( result ) { - sieve_interpreter_set_test_result(renv->interp, matched); + if ( ret >= 0 ) { + sieve_interpreter_set_test_result(renv->interp, ret > 0); return SIEVE_EXEC_OK; - } + } - sieve_runtime_trace_error(renv, "invalid string-list item"); + sieve_runtime_trace_error(renv, "invalid string-list item"); return SIEVE_EXEC_BIN_CORRUPT; } diff --git a/src/lib-sieve/tst-exists.c b/src/lib-sieve/tst-exists.c index 278faf80c..6231f4c35 100644 --- a/src/lib-sieve/tst-exists.c +++ b/src/lib-sieve/tst-exists.c @@ -6,6 +6,7 @@ #include "sieve-common.h" #include "sieve-commands.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-validator.h" #include "sieve-generator.h" @@ -105,8 +106,8 @@ static bool tst_exists_operation_dump static int tst_exists_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { - bool result = TRUE; - struct sieve_coded_stringlist *hdr_list; + int ret; + struct sieve_stringlist *hdr_list; string_t *hdr_item; bool matched; @@ -129,8 +130,7 @@ static int tst_exists_operation_execute hdr_item = NULL; matched = TRUE; while ( matched && - (result=sieve_coded_stringlist_next_item(hdr_list, &hdr_item)) - && hdr_item != NULL ) { + (ret=sieve_stringlist_next_item(hdr_list, &hdr_item)) > 0 ) { const char *const *headers; if ( mail_get_headers @@ -145,7 +145,7 @@ static int tst_exists_operation_execute } /* Set test result for subsequent conditional jump */ - if ( result ) { + if ( ret >= 0 ) { sieve_interpreter_set_test_result(renv->interp, matched); return SIEVE_EXEC_OK; } diff --git a/src/lib-sieve/tst-header.c b/src/lib-sieve/tst-header.c index 26ce9311f..9f1b85f8c 100644 --- a/src/lib-sieve/tst-header.c +++ b/src/lib-sieve/tst-header.c @@ -7,6 +7,7 @@ #include "sieve-common.h" #include "sieve-commands.h" #include "sieve-code.h" +#include "sieve-message.h" #include "sieve-comparators.h" #include "sieve-match-types.h" #include "sieve-validator.h" @@ -151,34 +152,15 @@ static bool tst_header_operation_dump * Code execution */ -static inline string_t *_header_right_trim(const char *raw) -{ - string_t *result; - int i; - - for ( i = strlen(raw)-1; i >= 0; i-- ) { - if ( raw[i] != ' ' && raw[i] != '\t' ) break; - } - - result = t_str_new(i+1); - str_append_n(result, raw, i + 1); - return result; -} - static int tst_header_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { - bool result = TRUE; int opt_code = 0; struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator); struct sieve_match_type mcht = SIEVE_COMPARATOR_DEFAULT(is_match_type); - struct sieve_match_context *mctx; - struct sieve_coded_stringlist *hdr_list; - struct sieve_coded_stringlist *key_list; - string_t *hdr_item; - bool matched; + struct sieve_stringlist *hdr_list, *key_list, *value_list; int ret; /* @@ -212,48 +194,15 @@ static int tst_header_operation_execute sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "header test"); - /* Initialize match */ - mctx = sieve_match_begin(renv, &mcht, &cmp, NULL, key_list); - - /* Iterate through all requested headers to match */ - hdr_item = NULL; - matched = FALSE; - while ( result && !matched && - (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 ) { - int i; - - for ( i = 0; !matched && headers[i] != NULL; i++ ) { - string_t *theader = _header_right_trim(headers[i]); - - if ( (ret=sieve_match_value(mctx, str_c(theader), str_len(theader))) - < 0 ) - { - result = FALSE; - break; - } - - matched = ret > 0; - } - } - } + /* Create header stringlist */ + value_list = sieve_message_header_stringlist_create(renv, hdr_list); - /* Finish match */ - if ( (ret=sieve_match_end(&mctx)) < 0 ) - result = FALSE; - else - matched = ( ret > 0 || matched ); + /* Perform match */ + ret = sieve_match(renv, &mcht, &cmp, value_list, key_list); /* Set test result for subsequent conditional jump */ - if ( result ) { - sieve_interpreter_set_test_result(renv->interp, matched); + if ( ret >= 0 ) { + sieve_interpreter_set_test_result(renv->interp, ret > 0); return SIEVE_EXEC_OK; } diff --git a/src/testsuite/testsuite-log.c b/src/testsuite/testsuite-log.c index c36a5b713..309572615 100644 --- a/src/testsuite/testsuite-log.c +++ b/src/testsuite/testsuite-log.c @@ -2,9 +2,11 @@ */ #include "lib.h" +#include "str.h" #include "array.h" #include "sieve-common.h" +#include "sieve-stringlist.h" #include "sieve-error-private.h" #include "testsuite-log.h" @@ -145,6 +147,81 @@ void testsuite_log_deinit(void) pool_unref(&_testsuite_logmsg_pool); } +/* + * Result stringlist + */ + +/* Forward declarations */ + +static int testsuite_log_stringlist_next_item + (struct sieve_stringlist *_strlist, string_t **str_r); +static void testsuite_log_stringlist_reset + (struct sieve_stringlist *_strlist); + +/* Stringlist object */ + +struct testsuite_log_stringlist { + struct sieve_stringlist strlist; + + int pos, index; +}; + +struct sieve_stringlist *testsuite_log_stringlist_create +(const struct sieve_runtime_env *renv, int index) +{ + struct testsuite_log_stringlist *strlist; + + strlist = t_new(struct testsuite_log_stringlist, 1); + strlist->strlist.runenv = renv; + strlist->strlist.next_item = testsuite_log_stringlist_next_item; + strlist->strlist.reset = testsuite_log_stringlist_reset; + + strlist->index = index; + strlist->pos = 0; + + return &strlist->strlist; +} + +static int testsuite_log_stringlist_next_item +(struct sieve_stringlist *_strlist, string_t **str_r) +{ + struct testsuite_log_stringlist *strlist = + (struct testsuite_log_stringlist *) _strlist; + const struct _testsuite_log_message *msg; + int pos; + + *str_r = NULL; + + if ( strlist->pos < 0 ) + return 0; + + if ( strlist->index > 0 ) { + pos = strlist->index - 1; + strlist->pos = -1; + } else { + pos = strlist->pos++; + } + + if ( pos >= (int) array_count(&_testsuite_log_errors) ) { + strlist->pos = -1; + return 0; + } + + msg = array_idx(&_testsuite_log_errors, (unsigned int) pos); + + *str_r = t_str_new_const(msg->message, strlen(msg->message)); + return 1; +} + +static void testsuite_log_stringlist_reset +(struct sieve_stringlist *_strlist) +{ + struct testsuite_log_stringlist *strlist = + (struct testsuite_log_stringlist *) _strlist; + + strlist->pos = 0; +} + diff --git a/src/testsuite/testsuite-log.h b/src/testsuite/testsuite-log.h index f89b54f5d..d5e8c6d59 100644 --- a/src/testsuite/testsuite-log.h +++ b/src/testsuite/testsuite-log.h @@ -15,4 +15,7 @@ void testsuite_log_clear_messages(void); void testsuite_log_get_error_init(void); const char *testsuite_log_get_error_next(bool location); +struct sieve_stringlist *testsuite_log_stringlist_create + (const struct sieve_runtime_env *renv, int index); + #endif /* __TESTSUITE_LOG_H */ diff --git a/src/testsuite/testsuite-result.c b/src/testsuite/testsuite-result.c index df38ceb57..e73d31244 100644 --- a/src/testsuite/testsuite-result.c +++ b/src/testsuite/testsuite-result.c @@ -3,9 +3,11 @@ #include "lib.h" #include "ostream.h" +#include "str.h" #include "sieve-common.h" #include "sieve-error.h" +#include "sieve-stringlist.h" #include "sieve-actions.h" #include "sieve-interpreter.h" #include "sieve-result.h" @@ -92,4 +94,82 @@ void testsuite_result_print o_stream_destroy(&out); } +/* + * Result stringlist + */ + +/* Forward declarations */ + +static int testsuite_result_stringlist_next_item + (struct sieve_stringlist *_strlist, string_t **str_r); +static void testsuite_result_stringlist_reset + (struct sieve_stringlist *_strlist); + +/* Stringlist object */ + +struct testsuite_result_stringlist { + struct sieve_stringlist strlist; + + struct sieve_result_iterate_context *result_iter; + int pos, index; +}; + +struct sieve_stringlist *testsuite_result_stringlist_create +(const struct sieve_runtime_env *renv, int index) +{ + struct testsuite_result_stringlist *strlist; + + strlist = t_new(struct testsuite_result_stringlist, 1); + strlist->strlist.runenv = renv; + strlist->strlist.next_item = testsuite_result_stringlist_next_item; + strlist->strlist.reset = testsuite_result_stringlist_reset; + + strlist->result_iter = testsuite_result_iterate_init(); + strlist->index = index; + strlist->pos = 0; + + return &strlist->strlist; +} + +static int testsuite_result_stringlist_next_item +(struct sieve_stringlist *_strlist, string_t **str_r) +{ + struct testsuite_result_stringlist *strlist = + (struct testsuite_result_stringlist *) _strlist; + const struct sieve_action *action; + const char *act_name; + bool keep; + + *str_r = NULL; + + if ( strlist->index > 0 && strlist->pos > 0 ) + return 0; + + do { + if ( (action=sieve_result_iterate_next(strlist->result_iter, &keep)) + == NULL ) + return 0; + + strlist->pos++; + } while ( strlist->pos < strlist->index ); + + if ( keep ) + act_name = "keep"; + else + act_name = ( action == NULL || action->def == NULL || + action->def->name == NULL ) ? "" : action->def->name; + + *str_r = t_str_new_const(act_name, strlen(act_name)); + return 1; +} + +static void testsuite_result_stringlist_reset +(struct sieve_stringlist *_strlist) +{ + struct testsuite_result_stringlist *strlist = + (struct testsuite_result_stringlist *) _strlist; + + strlist->result_iter = testsuite_result_iterate_init(); + strlist->pos = 0; +} diff --git a/src/testsuite/testsuite-result.h b/src/testsuite/testsuite-result.h index 60ad75de2..a74397d82 100644 --- a/src/testsuite/testsuite-result.h +++ b/src/testsuite/testsuite-result.h @@ -19,4 +19,7 @@ bool testsuite_result_execute(const struct sieve_runtime_env *renv); void testsuite_result_print (const struct sieve_runtime_env *renv ATTR_UNUSED); +struct sieve_stringlist *testsuite_result_stringlist_create + (const struct sieve_runtime_env *renv, int index); + #endif /* __TESTSUITE_RESULT_H */ diff --git a/src/testsuite/tst-test-error.c b/src/testsuite/tst-test-error.c index 52905b9da..f182203e0 100644 --- a/src/testsuite/tst-test-error.c +++ b/src/testsuite/tst-test-error.c @@ -210,14 +210,10 @@ static int tst_test_error_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { int opt_code = 0; - bool result = TRUE; struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_octet_comparator); struct sieve_match_type mcht = SIEVE_COMPARATOR_DEFAULT(is_match_type); - struct sieve_match_context *mctx; - struct sieve_coded_stringlist *key_list; - bool matched; - const char *error; - int cur_index = 0, index = 0; + struct sieve_stringlist *value_list, *key_list; + int index = -1; int ret; /* @@ -260,41 +256,17 @@ static int tst_test_error_operation_execute sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "test_error test"); - testsuite_log_get_error_init(); - - /* Initialize match */ - mctx = sieve_match_begin(renv, &mcht, &cmp, NULL, key_list); - - /* Iterate through all errors to match */ - error = NULL; - matched = FALSE; - cur_index = 1; - ret = 0; - while ( result && !matched && - (error=testsuite_log_get_error_next(FALSE)) != NULL ) { - - if ( index == 0 || index == cur_index ) { - if ( (ret=sieve_match_value(mctx, error, strlen(error))) < 0 ) { - result = FALSE; - break; - } - } - - matched = ret > 0; - cur_index++; - } - - /* Finish match */ - if ( (ret=sieve_match_end(&mctx)) < 0 ) - result = FALSE; - else - matched = ( ret > 0 || matched ); + /* Create value stringlist */ + value_list = testsuite_log_stringlist_create(renv, index); + /* Perform match */ + ret = sieve_match(renv, &mcht, &cmp, value_list, key_list); + /* Set test result for subsequent conditional jump */ - if ( result ) { - sieve_interpreter_set_test_result(renv->interp, matched); + if ( ret >= 0 ) { + sieve_interpreter_set_test_result(renv->interp, ret > 0); return SIEVE_EXEC_OK; - } + } sieve_runtime_trace_error(renv, "invalid string-list item"); return SIEVE_EXEC_BIN_CORRUPT; diff --git a/src/testsuite/tst-test-multiscript.c b/src/testsuite/tst-test-multiscript.c index 2e678d3f9..555e13c6a 100644 --- a/src/testsuite/tst-test-multiscript.c +++ b/src/testsuite/tst-test-multiscript.c @@ -7,6 +7,7 @@ #include "sieve-validator.h" #include "sieve-generator.h" #include "sieve-interpreter.h" +#include "sieve-stringlist.h" #include "sieve-code.h" #include "sieve-binary.h" #include "sieve-dump.h" @@ -107,17 +108,18 @@ static bool tst_test_multiscript_operation_dump static int tst_test_multiscript_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { - struct sieve_coded_stringlist *scripts_list; + struct sieve_stringlist *scripts_list; string_t *script_name; const char *script_path; ARRAY_TYPE (const_string) scriptfiles; bool result = TRUE; + int ret; /* * Read operands */ - if ( (scripts_list=sieve_opr_stringlist_read(renv, address, "scripts")) + if ( (scripts_list=sieve_opr_stringlist_read(renv, address, "scripts")) == NULL ) return SIEVE_EXEC_BIN_CORRUPT; @@ -130,22 +132,21 @@ static int tst_test_multiscript_operation_execute t_array_init(&scriptfiles, 16); script_path = sieve_script_dirpath(renv->script); - if ( script_path == NULL ) + if ( script_path == NULL ) return SIEVE_EXEC_FAILURE; script_name = NULL; - while ( result && - (result=sieve_coded_stringlist_next_item(scripts_list, &script_name)) - && script_name != NULL ) { + while ( result && + (ret=sieve_stringlist_next_item(scripts_list, &script_name)) > 0 ) { - const char *path = + const char *path = t_strconcat(script_path, "/", str_c(script_name), NULL); /* Attempt script compile */ - array_append(&scriptfiles, &path, 1); + array_append(&scriptfiles, &path, 1); } - result = result && testsuite_script_multiscript(renv, &scriptfiles); + result = result && (ret >= 0) && testsuite_script_multiscript(renv, &scriptfiles); /* Set result */ sieve_interpreter_set_test_result(renv->interp, result); diff --git a/src/testsuite/tst-test-result.c b/src/testsuite/tst-test-result.c index d684acc9c..1470454f7 100644 --- a/src/testsuite/tst-test-result.c +++ b/src/testsuite/tst-test-result.c @@ -215,16 +215,10 @@ static int tst_test_result_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { int opt_code = 0; - bool result = TRUE; struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_octet_comparator); - struct sieve_match_type mcht = SIEVE_COMPARATOR_DEFAULT(is_match_type); - struct sieve_match_context *mctx; - struct sieve_coded_stringlist *key_list; - bool matched; - struct sieve_result_iterate_context *rictx; - const struct sieve_action *action; - bool keep; - int cur_index = 0, index = 0; + struct sieve_match_type mcht = SIEVE_MATCH_TYPE_DEFAULT(is_match_type); + struct sieve_stringlist *value_list, *key_list; + int index = 0; int ret; /* @@ -261,49 +255,19 @@ static int tst_test_result_operation_execute */ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, - "TEST_RESULT test (index: %d)", index); - - rictx = testsuite_result_iterate_init(); - - /* Initialize match */ - mctx = sieve_match_begin(renv, &mcht, &cmp, NULL, key_list); - - /* Iterate through all errors to match */ - matched = FALSE; - cur_index = 1; - ret = 0; - while ( result && !matched && - (action=sieve_result_iterate_next(rictx, &keep)) != NULL ) { - const char *act_name; - - if ( keep ) - act_name = "keep"; - else - act_name = ( action == NULL || action->def == NULL || - action->def->name == NULL ) ? "" : action->def->name; - - if ( index == 0 || index == cur_index ) { - if ( (ret=sieve_match_value(mctx, act_name, strlen(act_name))) < 0 ) { - result = FALSE; - break; - } - } - - matched = ret > 0; - cur_index++; - } + "test_result test (index: %d)", index); - /* Finish match */ - if ( (ret=sieve_match_end(&mctx)) < 0 ) - result = FALSE; - else - matched = ( ret > 0 || matched ); + /* Create value stringlist */ + value_list = testsuite_result_stringlist_create(renv, index); + /* Perform match */ + ret = sieve_match(renv, &mcht, &cmp, value_list, key_list); + /* Set test result for subsequent conditional jump */ - if ( result ) { - sieve_interpreter_set_test_result(renv->interp, matched); + if ( ret >= 0 ) { + sieve_interpreter_set_test_result(renv->interp, ret > 0); return SIEVE_EXEC_OK; - } + } sieve_runtime_trace_error(renv, "invalid string-list item"); return SIEVE_EXEC_BIN_CORRUPT; @@ -311,4 +275,3 @@ static int tst_test_result_operation_execute - diff --git a/tests/extensions/envelope.svtest b/tests/extensions/envelope.svtest index 32c46e03a..19ea5015c 100644 --- a/tests/extensions/envelope.svtest +++ b/tests/extensions/envelope.svtest @@ -6,6 +6,10 @@ require "envelope"; * Empty envelope addresses */ +/* RFC 5228, Section 5.4: The null reverse-path is matched against as the empty + * string, regardless of the ADDRESS-PART argument specified. + */ + test "Envelope - from empty" { /* Return_path: "" */ -- GitLab