summaryrefslogtreecommitdiffstats
path: root/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
diff options
context:
space:
mode:
Diffstat (limited to 'pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c')
-rw-r--r--pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c b/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
new file mode 100644
index 0000000..20ec38b
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
@@ -0,0 +1,160 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension comparator-i;ascii-numeric
+ * ------------------------------------
+ *
+ * Author: Stephan Bosch
+ * Specification: RFC 2244
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-comparators.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include <ctype.h>
+
+/*
+ * Forward declarations
+ */
+
+static const struct sieve_operand_def my_comparator_operand;
+
+const struct sieve_comparator_def i_ascii_numeric_comparator;
+
+/*
+ * Extension
+ */
+
+static bool ext_cmp_i_ascii_numeric_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *validator);
+
+const struct sieve_extension_def comparator_i_ascii_numeric_extension = {
+ .name = "comparator-i;ascii-numeric",
+ .validator_load = ext_cmp_i_ascii_numeric_validator_load,
+ SIEVE_EXT_DEFINE_OPERAND(my_comparator_operand)
+};
+
+static bool ext_cmp_i_ascii_numeric_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *validator)
+{
+ sieve_comparator_register(validator, ext, &i_ascii_numeric_comparator);
+ return TRUE;
+}
+
+/*
+ * Operand
+ */
+
+static const struct sieve_extension_objects ext_comparators =
+ SIEVE_EXT_DEFINE_COMPARATOR(i_ascii_numeric_comparator);
+
+static const struct sieve_operand_def my_comparator_operand = {
+ .name = "comparator-i;ascii-numeric",
+ .ext_def = &comparator_i_ascii_numeric_extension,
+ .class = &sieve_comparator_operand_class,
+ .interface = &ext_comparators
+};
+
+/*
+ * Comparator
+ */
+
+/* Forward declarations */
+
+static int cmp_i_ascii_numeric_compare
+ (const struct sieve_comparator *cmp,
+ const char *val1, size_t val1_size, const char *val2, size_t val2_size);
+
+/* Comparator object */
+
+const struct sieve_comparator_def i_ascii_numeric_comparator = {
+ SIEVE_OBJECT("i;ascii-numeric",
+ &my_comparator_operand, 0),
+ .flags =
+ SIEVE_COMPARATOR_FLAG_ORDERING |
+ SIEVE_COMPARATOR_FLAG_EQUALITY,
+ .compare = cmp_i_ascii_numeric_compare
+};
+
+/* Comparator implementation */
+
+static int cmp_i_ascii_numeric_compare
+ (const struct sieve_comparator *cmp ATTR_UNUSED,
+ 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;
+ int digits, i;
+
+ /* RFC 4790: All input is valid; strings that do not start with a digit
+ * represent positive infinity.
+ */
+ if ( !i_isdigit(*vp) ) {
+ if ( i_isdigit(*kp) ) {
+ /* Value is greater */
+ return 1;
+ }
+ } else {
+ if ( !i_isdigit(*kp) ) {
+ /* Value is less */
+ return -1;
+ }
+ }
+
+ /* Ignore leading zeros */
+
+ while ( *vp == '0' && vp < vend )
+ vp++;
+
+ while ( *kp == '0' && kp < kend )
+ kp++;
+
+ /* Check whether both numbers are equally long in terms of digits */
+
+ digits = 0;
+ while ( vp < vend && kp < kend && i_isdigit(*vp) && i_isdigit(*kp) ) {
+ vp++;
+ kp++;
+ digits++;
+ }
+
+ if ( vp == vend || !i_isdigit(*vp) ) {
+ if ( kp != kend && i_isdigit(*kp) ) {
+ /* Value is less */
+ return -1;
+ }
+ } else {
+ /* Value is greater */
+ return 1;
+ }
+
+ /* Equally long: compare digits */
+
+ vp -= digits;
+ kp -= digits;
+ i = 0;
+ while ( i < digits ) {
+ if ( *vp > *kp )
+ return 1;
+ else if ( *vp < *kp )
+ return -1;
+
+ kp++;
+ vp++;
+ i++;
+ }
+
+ return 0;
+}
+