From eaae9678b20f0b9893c3f71f27263f66025f6f24 Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Sun, 23 Mar 2008 11:20:50 +0100 Subject: [PATCH] Exported match type implementations to separate files. --- src/lib-sieve/Makefile.am | 6 + src/lib-sieve/mcht-contains.c | 63 ++++ src/lib-sieve/mcht-is.c | 49 +++ src/lib-sieve/mcht-matches.c | 314 +++++++++++++++++ src/lib-sieve/plugins/body/ext-body-common.c | 3 +- src/lib-sieve/sieve-match-types.c | 349 +------------------ src/lib-sieve/sieve-match-types.h | 5 + 7 files changed, 439 insertions(+), 350 deletions(-) create mode 100644 src/lib-sieve/mcht-contains.c create mode 100644 src/lib-sieve/mcht-is.c create mode 100644 src/lib-sieve/mcht-matches.c diff --git a/src/lib-sieve/Makefile.am b/src/lib-sieve/Makefile.am index b17925420..2cf105300 100644 --- a/src/lib-sieve/Makefile.am +++ b/src/lib-sieve/Makefile.am @@ -30,6 +30,11 @@ exts = \ ext-envelope.c \ ext-encoded-character.c +mchts = \ + mcht-is.c \ + mcht-contains.c \ + mcht-matches.c + # These are not actual plugins just yet... plugins = \ ./plugins/vacation/libsieve_ext_vacation.la \ @@ -60,6 +65,7 @@ libsieve_la_SOURCES = \ sieve-error.c \ sieve-comparators.c \ sieve-match-types.c \ + $(mchts) \ sieve-address-parts.c \ sieve-commands.c \ sieve-code.c \ diff --git a/src/lib-sieve/mcht-contains.c b/src/lib-sieve/mcht-contains.c new file mode 100644 index 000000000..ec0baf63c --- /dev/null +++ b/src/lib-sieve/mcht-contains.c @@ -0,0 +1,63 @@ +/* Match-type ':contains' + */ + +#include "lib.h" + +#include "sieve-match-types.h" +#include "sieve-comparators.h" + +#include <string.h> +#include <stdio.h> + +/* + * Forward declarations + */ + +static bool mcht_contains_match + (struct sieve_match_context *mctx, const char *val, size_t val_size, + const char *key, size_t key_size, int key_index); + +/* + * Match-type object + */ + +const struct sieve_match_type contains_match_type = { + "contains", TRUE, + NULL, + SIEVE_MATCH_TYPE_CONTAINS, + NULL, + sieve_match_substring_validate_context, + NULL, + mcht_contains_match, + NULL +}; + +/* + * Match-type implementation + */ + +/* FIXME: Naive substring match implementation. Should switch to more + * efficient algorithm if large values need to be searched (e.g. message body). + */ +static bool mcht_contains_match +(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 struct sieve_comparator *cmp = mctx->comparator; + const char *vend = (const char *) val + val_size; + const char *kend = (const char *) key + key_size; + const char *vp = val; + const char *kp = key; + + if ( mctx->comparator->char_match == NULL ) + return FALSE; + + while ( (vp < vend) && (kp < kend) ) { + if ( !cmp->char_match(cmp, &vp, vend, &kp, kend) ) + vp++; + } + + return (kp == kend); +} + + diff --git a/src/lib-sieve/mcht-is.c b/src/lib-sieve/mcht-is.c new file mode 100644 index 000000000..1468e3982 --- /dev/null +++ b/src/lib-sieve/mcht-is.c @@ -0,0 +1,49 @@ +/* Match-type ':is': + * + */ + +#include "lib.h" + +#include "sieve-match-types.h" +#include "sieve-comparators.h" + +#include <string.h> +#include <stdio.h> + +/* + * Forward declarations + */ + +static bool mcht_is_match + (struct sieve_match_context *mctx, const char *val1, size_t val1_size, + const char *key, size_t key_size, int key_index); + +/* + * Match-type object + */ + +const struct sieve_match_type is_match_type = { + "is", TRUE, + NULL, + SIEVE_MATCH_TYPE_IS, + NULL, NULL, NULL, + mcht_is_match, + NULL +}; + +/* + * Match-type implementation + */ + +static bool mcht_is_match +(struct sieve_match_context *mctx ATTR_UNUSED, + const char *val1, size_t val1_size, + const char *key, size_t key_size, int key_index ATTR_UNUSED) +{ + if ( mctx->comparator->compare != NULL ) + return (mctx->comparator->compare(mctx->comparator, + val1, val1_size, key, key_size) == 0); + + return FALSE; +} + diff --git a/src/lib-sieve/mcht-matches.c b/src/lib-sieve/mcht-matches.c new file mode 100644 index 000000000..18da6ee2d --- /dev/null +++ b/src/lib-sieve/mcht-matches.c @@ -0,0 +1,314 @@ +/* Match-type ':matches' + */ + +#include "lib.h" +#include "str.h" + +#include "sieve-match-types.h" +#include "sieve-comparators.h" + +#include <string.h> +#include <stdio.h> + +/* + * Forward declarations + */ + +static bool mcht_matches_match + (struct sieve_match_context *mctx, const char *val, size_t val_size, + const char *key, size_t key_size, int key_index); + +/* + * Match-type object + */ + +const struct sieve_match_type matches_match_type = { + "matches", TRUE, + NULL, + SIEVE_MATCH_TYPE_MATCHES, + NULL, + sieve_match_substring_validate_context, + NULL, + mcht_matches_match, + NULL +}; + +/* + * Match-type implementation + */ + +/* Quick 'n dirty debug */ +//#define MATCH_DEBUG +#ifdef MATCH_DEBUG +#define debug_printf(...) printf (__VA_ARGS__) +#else +#define debug_printf(...) +#endif + +/* FIXME: Naive implementation, substitute this with dovecot src/lib/str-find.c + */ +static inline bool _string_find(const struct sieve_comparator *cmp, + const char **valp, const char *vend, const char **keyp, const char *kend) +{ + while ( (*valp < vend) && (*keyp < kend) ) { + if ( !cmp->char_match(cmp, valp, vend, keyp, kend) ) + (*valp)++; + } + + return (*keyp == kend); +} + +static char _scan_key_section + (string_t *section, const char **wcardp, const char *key_end) +{ + /* Find next wildcard and resolve escape sequences */ + str_truncate(section, 0); + while ( *wcardp < key_end && **wcardp != '*' && **wcardp != '?') { + if ( **wcardp == '\\' ) { + (*wcardp)++; + } + str_append_c(section, **wcardp); + (*wcardp)++; + } + + /* Record wildcard character or \0 */ + if ( *wcardp < key_end ) { + return **wcardp; + } + + i_assert( *wcardp == key_end ); + return '\0'; +} + +static bool mcht_matches_match +(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 struct sieve_comparator *cmp = mctx->comparator; + struct sieve_match_values *mvalues; + + string_t *mvalue = t_str_new(32); /* Match value (*) */ + string_t *mchars = t_str_new(32); /* Match characters (.?..?.??) */ + string_t *section = t_str_new(32); /* Section (after beginning or *) */ + string_t *subsection = t_str_new(32); /* Sub-section (after ?) */ + + const char *vend = (const char *) val + val_size; + const char *kend = (const char *) key + key_size; + const char *vp = val; /* Value pointer */ + const char *kp = key; /* Key pointer */ + const char *wp = key; /* Wildcard (key) pointer */ + const char *pvp = val; /* Previous value Pointer */ + + bool backtrack = FALSE; /* TRUE: match of '?'-connected sections failed */ + char wcard = '\0'; /* Current wildcard */ + char next_wcard = '\0'; /* Next widlcard */ + unsigned int key_offset = 0; + unsigned int j = 0; + + /* Reset match values list */ + mvalues = sieve_match_values_start(mctx->interp); + sieve_match_values_add(mvalues, NULL); + + /* Match the pattern: + * <pattern> = <section>*<section>*<section>.... + * <section> = [text]?[text]?[text].... + * + * Escape sequences \? and \* need special attention. + */ + + debug_printf("MATCH key: %s\n", t_strdup_until(key, kend)); + debug_printf("MATCH val: %s\n", t_strdup_until(val, vend)); + + /* Loop until either key or value ends */ + while (kp < kend && vp < vend && j < 40) { + const char *needle, *nend; + + if ( !backtrack ) { + wcard = next_wcard; + + /* Find the needle to look for in the string */ + key_offset = 0; + for (;;) { + next_wcard = _scan_key_section(section, &wp, kend); + + if ( wcard == '\0' || str_len(section) > 0 ) + break; + + if ( next_wcard == '*' ) { + break; + } + + if ( wp < kend ) + wp++; + else + break; + key_offset++; + } + + debug_printf("MATCH found wildcard '%c' at pos [%d]\n", + next_wcard, (int) (wp-key)); + + str_truncate(mvalue, 0); + } else + backtrack = FALSE; + + needle = str_c(section); + nend = PTR_OFFSET(needle, str_len(section)); + + debug_printf("MATCH sneedle: '%s'\n", t_strdup_until(needle, nend)); + debug_printf("MATCH skey: '%s'\n", t_strdup_until(kp, kend)); + debug_printf("MATCH swp: '%s'\n", t_strdup_until(wp, kend)); + debug_printf("MATCH sval: '%s'\n", t_strdup_until(vp, vend)); + + pvp = vp; + if ( next_wcard == '\0' ) { + const char *qp, *qend; + + debug_printf("MATCH find end.\n"); + + /* Find substring at the end of string */ + if ( vend - str_len(section) < vp ) { + break; + } + + vp = PTR_OFFSET(vend, -str_len(section)); + qend = vp; + qp = vp - key_offset; + str_append_n(mvalue, pvp, qp-pvp); + + if ( !cmp->char_match(cmp, &vp, vend, &needle, nend) ) { + debug_printf("MATCH failed end\n"); + break; + } + + sieve_match_values_add(mvalues, mvalue); + for ( ; qp < qend; qp++ ) + sieve_match_values_add_char(mvalues, *qp); + + kp = kend; + vp = vend; + break; + } else { + const char *prv = NULL; + const char *prk = NULL; + const char *prw = NULL; + const char *chars; + debug_printf("MATCH find.\n"); + + str_truncate(mchars, 0); + + if ( wcard == '\0' ) { + /* Match needs to happen right at the beginning */ + debug_printf("MATCH bkey: '%s'\n", t_strdup_until(needle, nend)); + debug_printf("MATCH bval: '%s'\n", t_strdup_until(vp, vend)); + + if ( !cmp->char_match(cmp, &vp, vend, &needle, nend) ) { + debug_printf("MATCH failed begin\n"); + break; + } + + } else { + const char *qp, *qend; + + /* Match may happen at any offset: find substring */ + if ( !_string_find(cmp, &vp, vend, &needle, nend) ) { + debug_printf("MATCH failed find\n"); + break; + } + + prv = vp - str_len(section); + prk = kp; + prw = wp; + + qend = vp - str_len(section); + qp = qend - key_offset; + str_append_n(mvalue, pvp, qp-pvp); + for ( ; qp < qend; qp++ ) + str_append_c(mchars, *qp); + //sieve_match_values_add_char(mvalues, *qp); + debug_printf("MATCH :: %s\n", str_c(mvalue)); + } + + if ( wp < kend ) wp++; + kp = wp; + + while ( next_wcard == '?' ) { + debug_printf("MATCH ?\n"); + + /* Add match value */ + str_append_c(mchars, *vp); + vp++; + + next_wcard = _scan_key_section(subsection, &wp, kend); + debug_printf("MATCH found next wildcard '%c' at pos [%d]\n", + next_wcard, (int) (wp-key)); + + needle = str_c(subsection); + nend = PTR_OFFSET(needle, str_len(subsection)); + + debug_printf("MATCH fkey: '%s'\n", t_strdup_until(needle, nend)); + debug_printf("MATCH fval: '%s'\n", t_strdup_until(vp, vend)); + + if ( !cmp->char_match(cmp, &vp, vend, &needle, nend) ) { + if ( prv != NULL && prv + 1 < vend ) { + vp = prv; + kp = prk; + wp = prw; + + str_append_c(mvalue, *vp); + vp++; + + wcard = '*'; + next_wcard = '?'; + + backtrack = TRUE; + } + debug_printf("MATCH failed fixed\n"); + break; + } + + if ( wp < kend ) wp++; + kp = wp; + } + + if ( !backtrack ) { + unsigned int i; + + if ( next_wcard != '*' && next_wcard != '\0' ) { + debug_printf("MATCH failed '?'\n"); + break; + } + + if ( prv != NULL ) + sieve_match_values_add(mvalues, mvalue); + chars = (const char *) str_data(mchars); + for ( i = 0; i < str_len(mchars); i++ ) { + sieve_match_values_add_char(mvalues, chars[i]); + } + } + } + + /* Check whether string ends in a wildcard + * (avoid scanning the rest of the string) + */ + if ( kp == kend && next_wcard == '*' ) { + str_truncate(mvalue, 0); + str_append_n(mvalue, vp, vend-vp); + sieve_match_values_add(mvalues, mvalue); + kp = kend; + vp = vend; + break; + } + + debug_printf("MATCH loop\n"); + j++; + } + + debug_printf("MATCH loop ended\n"); + + /* By definition, the match is only successful if both value and key pattern + * are exhausted. + */ + return (kp == kend && vp == vend); +} + diff --git a/src/lib-sieve/plugins/body/ext-body-common.c b/src/lib-sieve/plugins/body/ext-body-common.c index d2a53c15d..38505a3ff 100644 --- a/src/lib-sieve/plugins/body/ext-body-common.c +++ b/src/lib-sieve/plugins/body/ext-body-common.c @@ -227,8 +227,7 @@ static bool ext_body_parts_add_missing have_all = ext_body_get_return_parts(ctx, content_types, decode_to_plain); i_assert(have_all); - if (message_parser_deinit(&parser, &parts) < 0) - i_unreached(); + (void)message_parser_deinit(&parser, &parts); if (decoder != NULL) message_decoder_deinit(&decoder); return ( input->stream_errno == 0 ); diff --git a/src/lib-sieve/sieve-match-types.c b/src/lib-sieve/sieve-match-types.c index 8fe555291..5c901e12e 100644 --- a/src/lib-sieve/sieve-match-types.c +++ b/src/lib-sieve/sieve-match-types.c @@ -588,23 +588,7 @@ bool sieve_match_end(struct sieve_match_context *mctx) * Matching */ -/* :is */ - -static bool mtch_is_match -(struct sieve_match_context *mctx ATTR_UNUSED, - const char *val1, size_t val1_size, - const char *key, size_t key_size, int key_index ATTR_UNUSED) -{ - if ( mctx->comparator->compare != NULL ) - return (mctx->comparator->compare(mctx->comparator, - val1, val1_size, key, key_size) == 0); - - return FALSE; -} - -/* :contains */ - -static bool mtch_contains_validate_context +bool sieve_match_substring_validate_context (struct sieve_validator *validator, struct sieve_ast_argument *arg, struct sieve_match_type_context *ctx, struct sieve_ast_argument *key_arg ATTR_UNUSED) @@ -634,307 +618,6 @@ static bool mtch_contains_validate_context return TRUE; } -/* FIXME: Naive substring match implementation. Should switch to more - * efficient algorithm if large values need to be searched (e.g. message body). - */ -static bool mtch_contains_match -(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 struct sieve_comparator *cmp = mctx->comparator; - const char *vend = (const char *) val + val_size; - const char *kend = (const char *) key + key_size; - const char *vp = val; - const char *kp = key; - - if ( mctx->comparator->char_match == NULL ) - return FALSE; - - while ( (vp < vend) && (kp < kend) ) { - if ( !cmp->char_match(cmp, &vp, vend, &kp, kend) ) - vp++; - } - - return (kp == kend); -} - -/* :matches */ - -/* Quick 'n dirty debug */ -//#define MATCH_DEBUG -#ifdef MATCH_DEBUG -#define debug_printf(...) printf (__VA_ARGS__) -#else -#define debug_printf(...) -#endif - -/* FIXME: Naive implementation, substitute this with dovecot src/lib/str-find.c - */ -static inline bool _string_find(const struct sieve_comparator *cmp, - const char **valp, const char *vend, const char **keyp, const char *kend) -{ - while ( (*valp < vend) && (*keyp < kend) ) { - if ( !cmp->char_match(cmp, valp, vend, keyp, kend) ) - (*valp)++; - } - - return (*keyp == kend); -} - -static char _scan_key_section - (string_t *section, const char **wcardp, const char *key_end) -{ - /* Find next wildcard and resolve escape sequences */ - str_truncate(section, 0); - while ( *wcardp < key_end && **wcardp != '*' && **wcardp != '?') { - if ( **wcardp == '\\' ) { - (*wcardp)++; - } - str_append_c(section, **wcardp); - (*wcardp)++; - } - - /* Record wildcard character or \0 */ - if ( *wcardp < key_end ) { - return **wcardp; - } - - i_assert( *wcardp == key_end ); - return '\0'; -} - -static bool mtch_matches_match -(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 struct sieve_comparator *cmp = mctx->comparator; - struct sieve_match_values *mvalues; - - string_t *mvalue = t_str_new(32); /* Match value (*) */ - string_t *mchars = t_str_new(32); /* Match characters (.?..?.??) */ - string_t *section = t_str_new(32); /* Section (after beginning or *) */ - string_t *subsection = t_str_new(32); /* Sub-section (after ?) */ - - const char *vend = (const char *) val + val_size; - const char *kend = (const char *) key + key_size; - const char *vp = val; /* Value pointer */ - const char *kp = key; /* Key pointer */ - const char *wp = key; /* Wildcard (key) pointer */ - const char *pvp = val; /* Previous value Pointer */ - - bool backtrack = FALSE; /* TRUE: match of '?'-connected sections failed */ - char wcard = '\0'; /* Current wildcard */ - char next_wcard = '\0'; /* Next widlcard */ - unsigned int key_offset = 0; - unsigned int j = 0; - - /* Reset match values list */ - mvalues = sieve_match_values_start(mctx->interp); - sieve_match_values_add(mvalues, NULL); - - /* Match the pattern: - * <pattern> = <section>*<section>*<section>.... - * <section> = [text]?[text]?[text].... - * - * Escape sequences \? and \* need special attention. - */ - - debug_printf("MATCH key: %s\n", t_strdup_until(key, kend)); - debug_printf("MATCH val: %s\n", t_strdup_until(val, vend)); - - /* Loop until either key or value ends */ - while (kp < kend && vp < vend && j < 40) { - const char *needle, *nend; - - if ( !backtrack ) { - wcard = next_wcard; - - /* Find the needle to look for in the string */ - key_offset = 0; - for (;;) { - next_wcard = _scan_key_section(section, &wp, kend); - - if ( wcard == '\0' || str_len(section) > 0 ) - break; - - if ( next_wcard == '*' ) { - break; - } - - if ( wp < kend ) - wp++; - else - break; - key_offset++; - } - - debug_printf("MATCH found wildcard '%c' at pos [%d]\n", - next_wcard, (int) (wp-key)); - - str_truncate(mvalue, 0); - } else - backtrack = FALSE; - - needle = str_c(section); - nend = PTR_OFFSET(needle, str_len(section)); - - debug_printf("MATCH sneedle: '%s'\n", t_strdup_until(needle, nend)); - debug_printf("MATCH skey: '%s'\n", t_strdup_until(kp, kend)); - debug_printf("MATCH swp: '%s'\n", t_strdup_until(wp, kend)); - debug_printf("MATCH sval: '%s'\n", t_strdup_until(vp, vend)); - - pvp = vp; - if ( next_wcard == '\0' ) { - const char *qp, *qend; - - debug_printf("MATCH find end.\n"); - - /* Find substring at the end of string */ - if ( vend - str_len(section) < vp ) { - break; - } - - vp = PTR_OFFSET(vend, -str_len(section)); - qend = vp; - qp = vp - key_offset; - str_append_n(mvalue, pvp, qp-pvp); - - if ( !cmp->char_match(cmp, &vp, vend, &needle, nend) ) { - debug_printf("MATCH failed end\n"); - break; - } - - sieve_match_values_add(mvalues, mvalue); - for ( ; qp < qend; qp++ ) - sieve_match_values_add_char(mvalues, *qp); - - kp = kend; - vp = vend; - break; - } else { - const char *prv = NULL; - const char *prk = NULL; - const char *prw = NULL; - const char *chars; - debug_printf("MATCH find.\n"); - - str_truncate(mchars, 0); - - if ( wcard == '\0' ) { - /* Match needs to happen right at the beginning */ - debug_printf("MATCH bkey: '%s'\n", t_strdup_until(needle, nend)); - debug_printf("MATCH bval: '%s'\n", t_strdup_until(vp, vend)); - - if ( !cmp->char_match(cmp, &vp, vend, &needle, nend) ) { - debug_printf("MATCH failed begin\n"); - break; - } - - } else { - const char *qp, *qend; - - /* Match may happen at any offset: find substring */ - if ( !_string_find(cmp, &vp, vend, &needle, nend) ) { - debug_printf("MATCH failed find\n"); - break; - } - - prv = vp - str_len(section); - prk = kp; - prw = wp; - - qend = vp - str_len(section); - qp = qend - key_offset; - str_append_n(mvalue, pvp, qp-pvp); - for ( ; qp < qend; qp++ ) - str_append_c(mchars, *qp); - //sieve_match_values_add_char(mvalues, *qp); - debug_printf("MATCH :: %s\n", str_c(mvalue)); - } - - if ( wp < kend ) wp++; - kp = wp; - - while ( next_wcard == '?' ) { - debug_printf("MATCH ?\n"); - - /* Add match value */ - str_append_c(mchars, *vp); - vp++; - - next_wcard = _scan_key_section(subsection, &wp, kend); - debug_printf("MATCH found next wildcard '%c' at pos [%d]\n", - next_wcard, (int) (wp-key)); - - needle = str_c(subsection); - nend = PTR_OFFSET(needle, str_len(subsection)); - - debug_printf("MATCH fkey: '%s'\n", t_strdup_until(needle, nend)); - debug_printf("MATCH fval: '%s'\n", t_strdup_until(vp, vend)); - - if ( !cmp->char_match(cmp, &vp, vend, &needle, nend) ) { - if ( prv != NULL && prv + 1 < vend ) { - vp = prv; - kp = prk; - wp = prw; - - str_append_c(mvalue, *vp); - vp++; - - wcard = '*'; - next_wcard = '?'; - - backtrack = TRUE; - } - debug_printf("MATCH failed fixed\n"); - break; - } - - if ( wp < kend ) wp++; - kp = wp; - } - - if ( !backtrack ) { - unsigned int i; - - if ( next_wcard != '*' && next_wcard != '\0' ) { - debug_printf("MATCH failed '?'\n"); - break; - } - - if ( prv != NULL ) - sieve_match_values_add(mvalues, mvalue); - chars = (const char *) str_data(mchars); - for ( i = 0; i < str_len(mchars); i++ ) { - sieve_match_values_add_char(mvalues, chars[i]); - } - } - } - - /* Check whether string ends in a wildcard - * (avoid scanning the rest of the string) - */ - if ( kp == kend && next_wcard == '*' ) { - str_truncate(mvalue, 0); - str_append_n(mvalue, vp, vend-vp); - sieve_match_values_add(mvalues, mvalue); - kp = kend; - vp = vend; - break; - } - - debug_printf("MATCH loop\n"); - j++; - } - - debug_printf("MATCH loop ended\n"); - - /* By definition, the match is only successful if both value and key pattern - * are exhausted. - */ - return (kp == kend && vp == vend); -} - /* * Core match-type modifiers */ @@ -947,33 +630,3 @@ const struct sieve_argument match_type_tag = { tag_match_type_generate }; -const struct sieve_match_type is_match_type = { - "is", TRUE, - NULL, - SIEVE_MATCH_TYPE_IS, - NULL, NULL, NULL, - mtch_is_match, - NULL -}; - -const struct sieve_match_type contains_match_type = { - "contains", TRUE, - NULL, - SIEVE_MATCH_TYPE_CONTAINS, - NULL, - mtch_contains_validate_context, - NULL, - mtch_contains_match, - NULL -}; - -const struct sieve_match_type matches_match_type = { - "matches", TRUE, - NULL, - SIEVE_MATCH_TYPE_MATCHES, - NULL, - mtch_contains_validate_context, - NULL, - mtch_matches_match, - NULL -}; diff --git a/src/lib-sieve/sieve-match-types.h b/src/lib-sieve/sieve-match-types.h index 1fd8e66ed..96263f63d 100644 --- a/src/lib-sieve/sieve-match-types.h +++ b/src/lib-sieve/sieve-match-types.h @@ -121,6 +121,11 @@ const struct sieve_match_type *sieve_opr_match_type_read (const struct sieve_runtime_env *renv, sieve_size_t *address); bool sieve_opr_match_type_dump (const struct sieve_dumptime_env *denv, sieve_size_t *address); + +bool sieve_match_substring_validate_context + (struct sieve_validator *validator, struct sieve_ast_argument *arg, + struct sieve_match_type_context *ctx, + struct sieve_ast_argument *key_arg); /* Match Utility */ -- GitLab