/src/pigeonhole/src/lib-sieve/plugins/relational/ext-relational-common.c
Line | Count | Source |
1 | | /* Copyright (c) Pigeonhole authors, see top-level COPYING file */ |
2 | | |
3 | | /* Syntax: |
4 | | |
5 | | MATCH-TYPE =/ COUNT / VALUE |
6 | | COUNT = ":count" relational-match |
7 | | VALUE = ":value" relational-match |
8 | | relational-match = DQUOTE ( "gt" / "ge" / "lt" |
9 | | / "le" / "eq" / "ne" ) DQUOTE |
10 | | */ |
11 | | |
12 | | #include "lib.h" |
13 | | #include "str.h" |
14 | | #include "str-sanitize.h" |
15 | | |
16 | | #include "sieve-common.h" |
17 | | #include "sieve-ast.h" |
18 | | #include "sieve-code.h" |
19 | | #include "sieve-extensions.h" |
20 | | #include "sieve-commands.h" |
21 | | #include "sieve-comparators.h" |
22 | | #include "sieve-match-types.h" |
23 | | #include "sieve-validator.h" |
24 | | #include "sieve-generator.h" |
25 | | #include "sieve-interpreter.h" |
26 | | |
27 | | #include "ext-relational-common.h" |
28 | | |
29 | | /* |
30 | | * Forward declarations |
31 | | */ |
32 | | |
33 | | const struct sieve_match_type_def *rel_match_types[]; |
34 | | |
35 | | /* |
36 | | * Validation |
37 | | */ |
38 | | |
39 | | bool mcht_relational_validate(struct sieve_validator *valdtr, |
40 | | struct sieve_ast_argument **arg, |
41 | | struct sieve_match_type_context *ctx) |
42 | 0 | { |
43 | 0 | struct sieve_match_type *mcht; |
44 | 0 | enum relational_match rel_match = REL_MATCH_INVALID; |
45 | 0 | pool_t pool = sieve_ast_argument_pool(ctx->argument); |
46 | 0 | string_t *rel_match_ident; |
47 | | |
48 | | /* Check syntax: |
49 | | relational-match = DQUOTE ( "gt" / "ge" / "lt" |
50 | | / "le" / "eq" / "ne" ) DQUOTE |
51 | | |
52 | | So, actually this must be a constant string and it is implemented as |
53 | | such. |
54 | | */ |
55 | | |
56 | | /* Did we get a string in the first place? */ |
57 | 0 | if (*arg == NULL || (*arg)->type != SAAT_STRING) { |
58 | 0 | sieve_argument_validate_error( |
59 | 0 | valdtr, (*arg == NULL ? ctx->argument : *arg), |
60 | 0 | "the :%s match-type requires a constant string argument being " |
61 | 0 | "one of \"gt\", \"ge\", \"lt\", \"le\", \"eq\" or \"ne\", " |
62 | 0 | "but %s was found", |
63 | 0 | sieve_match_type_name(ctx->match_type), |
64 | 0 | (*arg == NULL ? |
65 | 0 | "none" : sieve_ast_argument_name(*arg))); |
66 | 0 | return FALSE; |
67 | 0 | } |
68 | | |
69 | | /* Check the relational match id */ |
70 | | |
71 | 0 | rel_match_ident = sieve_ast_argument_str(*arg); |
72 | 0 | if (str_len(rel_match_ident) == 2) { |
73 | 0 | const char *rel_match_id = str_c(rel_match_ident); |
74 | |
|
75 | 0 | switch (rel_match_id[0]) { |
76 | | /* "gt" or "ge" */ |
77 | 0 | case 'g': |
78 | 0 | switch (rel_match_id[1]) { |
79 | 0 | case 't': |
80 | 0 | rel_match = REL_MATCH_GREATER; |
81 | 0 | break; |
82 | 0 | case 'e': |
83 | 0 | rel_match = REL_MATCH_GREATER_EQUAL; |
84 | 0 | break; |
85 | 0 | default: |
86 | 0 | rel_match = REL_MATCH_INVALID; |
87 | 0 | } |
88 | 0 | break; |
89 | | /* "lt" or "le" */ |
90 | 0 | case 'l': |
91 | 0 | switch (rel_match_id[1]) { |
92 | 0 | case 't': |
93 | 0 | rel_match = REL_MATCH_LESS; |
94 | 0 | break; |
95 | 0 | case 'e': |
96 | 0 | rel_match = REL_MATCH_LESS_EQUAL; |
97 | 0 | break; |
98 | 0 | default: |
99 | 0 | rel_match = REL_MATCH_INVALID; |
100 | 0 | } |
101 | 0 | break; |
102 | | /* "eq" */ |
103 | 0 | case 'e': |
104 | 0 | if (rel_match_id[1] == 'q') |
105 | 0 | rel_match = REL_MATCH_EQUAL; |
106 | 0 | else |
107 | 0 | rel_match = REL_MATCH_INVALID; |
108 | 0 | break; |
109 | | /* "ne" */ |
110 | 0 | case 'n': |
111 | 0 | if (rel_match_id[1] == 'e') |
112 | 0 | rel_match = REL_MATCH_NOT_EQUAL; |
113 | 0 | else |
114 | 0 | rel_match = REL_MATCH_INVALID; |
115 | 0 | break; |
116 | | /* invalid */ |
117 | 0 | default: |
118 | 0 | rel_match = REL_MATCH_INVALID; |
119 | 0 | } |
120 | 0 | } |
121 | | |
122 | 0 | if (rel_match >= REL_MATCH_INVALID) { |
123 | 0 | sieve_argument_validate_error( |
124 | 0 | valdtr, *arg, |
125 | 0 | "the :%s match-type requires a constant string argument being " |
126 | 0 | "one of \"gt\", \"ge\", \"lt\", \"le\", \"eq\" or \"ne\", " |
127 | 0 | "but \"%s\" was found", |
128 | 0 | sieve_match_type_name(ctx->match_type), |
129 | 0 | str_sanitize(str_c(rel_match_ident), 32)); |
130 | 0 | return FALSE; |
131 | 0 | } |
132 | | |
133 | | /* Delete argument */ |
134 | 0 | *arg = sieve_ast_arguments_detach(*arg, 1); |
135 | | |
136 | | /* Not used just yet */ |
137 | 0 | ctx->ctx_data = (void *)rel_match; |
138 | | |
139 | | /* Override the actual match type with a parameter-specific one |
140 | | * FIXME: ugly! |
141 | | */ |
142 | 0 | mcht = p_new(pool, struct sieve_match_type, 1); |
143 | 0 | mcht->object.ext = ctx->match_type->object.ext; |
144 | 0 | SIEVE_OBJECT_SET_DEF(mcht, rel_match_types[ |
145 | 0 | REL_MATCH_INDEX(ctx->match_type->object.def->code, rel_match)]); |
146 | 0 | ctx->match_type = mcht; |
147 | |
|
148 | 0 | return TRUE; |
149 | 0 | } |
150 | | |
151 | | /* |
152 | | * Relational match-type operand |
153 | | */ |
154 | | |
155 | | const struct sieve_match_type_def *rel_match_types[] = { |
156 | | &rel_match_value_gt, &rel_match_value_ge, &rel_match_value_lt, |
157 | | &rel_match_value_le, &rel_match_value_eq, &rel_match_value_ne, |
158 | | &rel_match_count_gt, &rel_match_count_ge, &rel_match_count_lt, |
159 | | &rel_match_count_le, &rel_match_count_eq, &rel_match_count_ne, |
160 | | }; |
161 | | |
162 | | static const struct sieve_extension_objects ext_match_types = |
163 | | SIEVE_EXT_DEFINE_MATCH_TYPES(rel_match_types); |
164 | | |
165 | | const struct sieve_operand_def rel_match_type_operand = { |
166 | | .name = "relational match", |
167 | | .ext_def = &relational_extension, |
168 | | .class = &sieve_match_type_operand_class, |
169 | | .interface = &ext_match_types, |
170 | | }; |