From cb095ead90c4c5d9aea7ab62443c67413861d407 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Fri, 23 Nov 2007 13:34:55 +0100
Subject: [PATCH] Finished i;ascii-numeric comparator and fixed a segfault bug
 in the process.

---
 README                                        |  2 +-
 src/lib-sieve/cmd-if.c                        |  2 +-
 .../ext-cmp-i-ascii-numeric.c                 | 63 ++++++++++---------
 .../plugins/relational/relational.sieve       | 51 +++++++++++----
 src/lib-sieve/tst-allof.c                     |  2 +-
 src/lib-sieve/tst-anyof.c                     |  2 +-
 6 files changed, 78 insertions(+), 44 deletions(-)

diff --git a/README b/README
index e56772fef..05595f836 100644
--- a/README
+++ b/README
@@ -50,7 +50,7 @@ Extensions and their implementation status:
 
   Other RFCs/drafts:
     subaddress: full
-    comparator-i;ascii-numeric: full, but fails to handle leading zeros
+    comparator-i;ascii-numeric: full
     relational: full 
     regex: full, but suboptimal
     vacation: validation, generation and interpretation; no execution
diff --git a/src/lib-sieve/cmd-if.c b/src/lib-sieve/cmd-if.c
index 6c09f0cae..06bbfa07d 100644
--- a/src/lib-sieve/cmd-if.c
+++ b/src/lib-sieve/cmd-if.c
@@ -165,7 +165,7 @@ static bool cmd_if_generate
 		 * anyway. 
 		 */
 		if ( !sieve_command_block_exits_unconditionally(ctx) ) {
-			sieve_operation_emit_code(sbin, SIEVE_OPCODE_JMP);
+			sieve_operation_emit_code(sbin, &sieve_jmp_opcode);
 			ctx_data->exit_jump = sieve_binary_emit_offset(sbin, 0);
 			ctx_data->jump_generated = TRUE;
 		}
diff --git a/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c b/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
index f8634fd74..c9a3a88e6 100644
--- a/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
+++ b/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
@@ -3,7 +3,7 @@
  *
  * Author: Stephan Bosch
  * Specification: RFC 2244
- * Implementation: full, but fails to handle leading zeros.
+ * Implementation: full
  * Status: experimental, largely untested
  * 
  */
@@ -97,35 +97,40 @@ static bool ext_cmp_i_ascii_numeric_interpreter_load
 
 static int cmp_i_ascii_numeric_compare
 	(const struct sieve_comparator *cmp ATTR_UNUSED, 
-		const char *val1, size_t val1_size, const char *val2, size_t val2_size)
-{
-	unsigned int i = 0;
-	int result = 0;
-	const char *nval1 = (const char *) val1, *nval2 = (const char *) val2;
-
-	while ( i < val1_size && i < val2_size ) {	
-		if ( isdigit(nval1[i]) )  {
-			if ( isdigit(nval2[i]) ) {
-				if ( result == 0 && nval1[i] != nval2[i] ) { 
-					if ( nval1[i] > nval2[i] )
-						result = 1;
-					else
-						result = 0;
-				}
-			} else {
-				return 1;
-			}
-		} else {
-			if ( isdigit(nval2[i]) ) {
-				return -1;
-			} else {
-				return result;
-			}
-		}
-				
-		i++;
+		const char *val, size_t val_size, const char *key, size_t key_size)
+{	
+	const char *vend = val + val_size;
+	const char *kend = key + key_size;
+	const char *vp = val;
+	const char *kp = key;
+	
+	/* Ignore leading zeros */
+
+	while ( *vp == '0' && vp < vend )  
+		vp++;
+
+	while ( *kp == '0' && kp < kend )  
+		kp++;
+
+	while ( vp < vend && kp < kend ) {
+		if ( !isdigit(*vp) || !isdigit(*kp) ) 
+			break;
+
+		if ( *vp != *kp ) 
+			break;
+
+		vp++;
+		kp++;	
 	}
+
+	if ( vp == vend || !isdigit(*vp) ) {
+		if ( kp == kend || !isdigit(*kp) ) 
+			return 0;
+		else	
+			return -1;
+	} else if ( kp == kend || !isdigit(*kp) )  
+		return 1;
 		
-	return result;
+	return (*vp > *kp);
 }
 
diff --git a/src/lib-sieve/plugins/relational/relational.sieve b/src/lib-sieve/plugins/relational/relational.sieve
index 520ff5502..22f655dad 100644
--- a/src/lib-sieve/plugins/relational/relational.sieve
+++ b/src/lib-sieve/plugins/relational/relational.sieve
@@ -1,28 +1,57 @@
-require ["comparator-i;ascii-numeric", "relational"];
+require ["comparator-i;ascii-numeric", "relational", "fileinto"];
 
 if header :value "eq" :comparator "i;ascii-numeric" "x-spam-score" "2" {
-	discard;
-	stop;
+	fileinto "INBOX.fail";
+} else {
+	fileinto "INBOX.succeed";
 }
 
 if header :value "lt" :comparator "i;ascii-numeric" "x-spam-score" "2" {
-	discard;
-	stop;
+	fileinto "INBOX.fail";
+} else {
+	fileinto "INBOX.succeed";
 }
 
 if header :value "lt" :comparator "i;ascii-numeric" "x-spam-score" "2" {
-	discard;
-	stop;
+	fileinto "INBOX.fail";
+} else {
+    fileinto "INBOX.succeed";
+}
+
+if header :value "le" :comparator "i;ascii-numeric" "x-spam-score" "300" {
+    fileinto "INBOX.succeed";
+} else {
+    fileinto "INBOX.fail";
+}
+
+if header :value "le" :comparator "i;ascii-numeric" "x-spam-score" "302" {
+    fileinto "INBOX.succeed";
+} else {
+    fileinto "INBOX.fail";
+}
+
+if header :value "le" :comparator "i;ascii-numeric" "x-spam-score" "00302" {
+    fileinto "INBOX.succeed";
+} else {
+    fileinto "INBOX.fail";
 }
 
 if header :count "ne" :comparator "i;ascii-numeric" "to" "2" {
-	discard;
-	stop;
+	fileinto "INBOX.fail";
+} else {
+    fileinto "INBOX.succeed";
 }
 
 if header :count "ge" :comparator "i;ascii-numeric" "to" "2" {
-	discard;
-	stop;
+	fileinto "INBOX.succeed";
+} else {
+    fileinto "INBOX.fail";
+}
+
+if header :count "ge" :comparator "i;ascii-numeric" "to" "002" {
+    fileinto "INBOX.succeed";
+} else {
+    fileinto "INBOX.fail";
 }
 
 keep;
diff --git a/src/lib-sieve/tst-allof.c b/src/lib-sieve/tst-allof.c
index 9fd899524..d23090ab1 100644
--- a/src/lib-sieve/tst-allof.c
+++ b/src/lib-sieve/tst-allof.c
@@ -56,7 +56,7 @@ static bool tst_allof_generate
 	
 	if ( jump_true ) {
 		/* All tests succeeded, jump to case TRUE */
-		sieve_generator_emit_opcode(generator, SIEVE_OPCODE_JMP);
+		sieve_generator_emit_opcode(generator, &sieve_jmp_opcode);
 		sieve_jumplist_add(jumps, sieve_binary_emit_offset(sbin, 0));
 		
 		/* All false exits jump here */
diff --git a/src/lib-sieve/tst-anyof.c b/src/lib-sieve/tst-anyof.c
index 17f5dbaad..55fca774b 100644
--- a/src/lib-sieve/tst-anyof.c
+++ b/src/lib-sieve/tst-anyof.c
@@ -54,7 +54,7 @@ static bool tst_anyof_generate
 	
 	if ( !jump_true ) {
 		/* All tests failed, jump to case FALSE */
-		sieve_operation_emit_code(sbin, SIEVE_OPCODE_JMP);
+		sieve_operation_emit_code(sbin, &sieve_jmp_opcode);
 		sieve_jumplist_add(jumps, sieve_binary_emit_offset(sbin, 0));
 		
 		/* All true exits jump here */
-- 
GitLab