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