diff options
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.c | 160 |
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; +} + |