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