/src/pigeonhole/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c
Line | Count | Source |
1 | | /* Copyright (c) Pigeonhole authors, see top-level COPYING file */ |
2 | | |
3 | | /* Extension comparator-i;ascii-numeric |
4 | | * ------------------------------------ |
5 | | * |
6 | | * Author: Stephan Bosch |
7 | | * Specification: RFC 2244 |
8 | | * Implementation: full |
9 | | * Status: testing |
10 | | * |
11 | | */ |
12 | | |
13 | | #include "sieve-common.h" |
14 | | |
15 | | #include "sieve-code.h" |
16 | | #include "sieve-extensions.h" |
17 | | #include "sieve-comparators.h" |
18 | | #include "sieve-validator.h" |
19 | | #include "sieve-generator.h" |
20 | | #include "sieve-interpreter.h" |
21 | | |
22 | | #include <ctype.h> |
23 | | |
24 | | /* |
25 | | * Forward declarations |
26 | | */ |
27 | | |
28 | | static const struct sieve_operand_def my_comparator_operand; |
29 | | |
30 | | const struct sieve_comparator_def i_ascii_numeric_comparator; |
31 | | |
32 | | /* |
33 | | * Extension |
34 | | */ |
35 | | |
36 | | static bool |
37 | | ext_cmp_i_ascii_numeric_validator_load(const struct sieve_extension *ext, |
38 | | struct sieve_validator *validator); |
39 | | |
40 | | const struct sieve_extension_def comparator_i_ascii_numeric_extension = { |
41 | | .name = "comparator-i;ascii-numeric", |
42 | | .validator_load = ext_cmp_i_ascii_numeric_validator_load, |
43 | | SIEVE_EXT_DEFINE_OPERAND(my_comparator_operand) |
44 | | }; |
45 | | |
46 | | static bool |
47 | | ext_cmp_i_ascii_numeric_validator_load(const struct sieve_extension *ext, |
48 | | struct sieve_validator *validator) |
49 | 0 | { |
50 | 0 | sieve_comparator_register(validator, ext, &i_ascii_numeric_comparator); |
51 | 0 | return TRUE; |
52 | 0 | } |
53 | | |
54 | | /* |
55 | | * Operand |
56 | | */ |
57 | | |
58 | | static const struct sieve_extension_objects ext_comparators = |
59 | | SIEVE_EXT_DEFINE_COMPARATOR(i_ascii_numeric_comparator); |
60 | | |
61 | | static const struct sieve_operand_def my_comparator_operand = { |
62 | | .name = "comparator-i;ascii-numeric", |
63 | | .ext_def = &comparator_i_ascii_numeric_extension, |
64 | | .class = &sieve_comparator_operand_class, |
65 | | .interface = &ext_comparators, |
66 | | }; |
67 | | |
68 | | /* |
69 | | * Comparator |
70 | | */ |
71 | | |
72 | | /* Forward declarations */ |
73 | | |
74 | | static int |
75 | | cmp_i_ascii_numeric_compare(const struct sieve_comparator *cmp, |
76 | | const char *val1, size_t val1_size, |
77 | | const char *val2, size_t val2_size); |
78 | | |
79 | | /* Comparator object */ |
80 | | |
81 | | const struct sieve_comparator_def i_ascii_numeric_comparator = { |
82 | | SIEVE_OBJECT("i;ascii-numeric", &my_comparator_operand, 0), |
83 | | .flags = |
84 | | SIEVE_COMPARATOR_FLAG_ORDERING | |
85 | | SIEVE_COMPARATOR_FLAG_EQUALITY, |
86 | | .compare = cmp_i_ascii_numeric_compare, |
87 | | }; |
88 | | |
89 | | /* Comparator implementation */ |
90 | | |
91 | | static int |
92 | | cmp_i_ascii_numeric_compare(const struct sieve_comparator *cmp ATTR_UNUSED, |
93 | | const char *val, size_t val_size, |
94 | | const char *key, size_t key_size) |
95 | 0 | { |
96 | 0 | const char *vend = val + val_size; |
97 | 0 | const char *kend = key + key_size; |
98 | 0 | const char *vp = val; |
99 | 0 | const char *kp = key; |
100 | 0 | int digits, i; |
101 | | |
102 | | /* RFC 4790: All input is valid; strings that do not start with a digit |
103 | | represent positive infinity. |
104 | | */ |
105 | 0 | if (!i_isdigit(*vp)) { |
106 | 0 | if (i_isdigit(*kp)) { |
107 | | /* Value is greater */ |
108 | 0 | return 1; |
109 | 0 | } |
110 | 0 | } else { |
111 | 0 | if (!i_isdigit(*kp)) { |
112 | | /* Value is less */ |
113 | 0 | return -1; |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | | /* Ignore leading zeros */ |
118 | | |
119 | 0 | while (*vp == '0' && vp < vend) |
120 | 0 | vp++; |
121 | 0 | while (*kp == '0' && kp < kend) |
122 | 0 | kp++; |
123 | | |
124 | | /* Check whether both numbers are equally long in terms of digits */ |
125 | |
|
126 | 0 | digits = 0; |
127 | 0 | while (vp < vend && kp < kend && i_isdigit(*vp) && i_isdigit(*kp)) { |
128 | 0 | vp++; |
129 | 0 | kp++; |
130 | 0 | digits++; |
131 | 0 | } |
132 | |
|
133 | 0 | if (vp == vend || !i_isdigit(*vp)) { |
134 | 0 | if (kp != kend && i_isdigit(*kp)) { |
135 | | /* Value is less */ |
136 | 0 | return -1; |
137 | 0 | } |
138 | 0 | } else { |
139 | | /* Value is greater */ |
140 | 0 | return 1; |
141 | 0 | } |
142 | | |
143 | | /* Equally long: compare digits */ |
144 | | |
145 | 0 | vp -= digits; |
146 | 0 | kp -= digits; |
147 | 0 | i = 0; |
148 | 0 | while (i < digits) { |
149 | 0 | if (*vp > *kp) |
150 | 0 | return 1; |
151 | 0 | else if (*vp < *kp) |
152 | 0 | return -1; |
153 | | |
154 | 0 | kp++; |
155 | 0 | vp++; |
156 | 0 | i++; |
157 | 0 | } |
158 | | |
159 | 0 | return 0; |
160 | 0 | } |