21
21
static int mcht_matches_match
22
(struct sieve_match_context *mctx, const char *val, size_t val_size,
22
(struct sieve_match_context *mctx, const char *val, size_t val_size,
23
23
const char *key, size_t key_size, int key_index);
30
30
SIEVE_OBJECT("matches", &match_type_operand, SIEVE_MATCH_TYPE_MATCHES),
33
sieve_match_substring_validate_context,
33
sieve_match_substring_validate_context,
35
35
mcht_matches_match,
46
46
#define debug_printf(...) printf ("match debug: " __VA_ARGS__)
48
#define debug_printf(...)
48
#define debug_printf(...)
51
51
/* FIXME: Naive implementation, substitute this with dovecot src/lib/str-find.c
53
static inline bool _string_find(const struct sieve_comparator *cmp,
53
static inline bool _string_find(const struct sieve_comparator *cmp,
54
54
const char **valp, const char *vend, const char **keyp, const char *kend)
56
56
while ( (*valp < vend) && (*keyp < kend) ) {
57
57
if ( !cmp->def->char_match(cmp, valp, vend, keyp, kend) )
61
61
return (*keyp == kend);
64
64
static char _scan_key_section
65
65
(string_t *section, const char **wcardp, const char *key_end)
67
/* Find next wildcard and resolve escape sequences */
67
/* Find next wildcard and resolve escape sequences */
68
68
str_truncate(section, 0);
69
69
while ( *wcardp < key_end && **wcardp != '*' && **wcardp != '?') {
70
70
if ( **wcardp == '\\' ) {
73
73
str_append_c(section, **wcardp);
77
77
/* Record wildcard character or \0 */
78
if ( *wcardp < key_end ) {
78
if ( *wcardp < key_end ) {
82
82
i_assert( *wcardp == key_end );
86
86
static int mcht_matches_match
87
(struct sieve_match_context *mctx, const char *val, size_t val_size,
87
(struct sieve_match_context *mctx, const char *val, size_t val_size,
88
88
const char *key, size_t key_size, int key_index ATTR_UNUSED)
90
90
const struct sieve_comparator *cmp = mctx->comparator;
109
109
/* Key sections */
110
110
section = t_str_new(32); /* Section (after beginning or *) */
111
111
subsection = t_str_new(32); /* Sub-section (after ?) */
113
113
/* Mark end of value and key */
114
114
vend = (const char *) val + val_size;
115
115
kend = (const char *) key + key_size;
128
128
mvalue = t_str_new(32); /* Match value (*) */
129
129
mchars = t_str_new(32); /* Match characters (.?..?.??) */
132
/* Match the pattern:
132
/* Match the pattern:
133
133
* <pattern> = <section>*<section>*<section>...
134
134
* <section> = <sub-section>?<sub-section>?<sub-section>...
136
* Escape sequences \? and \* need special attention.
136
* Escape sequences \? and \* need special attention.
139
139
debug_printf("=== Start ===\n");
140
140
debug_printf(" key: %s\n", t_strdup_until(key, kend));
141
141
debug_printf(" value: %s\n", t_strdup_until(val, vend));
143
143
/* Loop until either key or value ends */
144
144
while (kp < kend && vp < vend ) {
145
145
const char *needle, *nend;
147
147
if ( !backtrack ) {
148
148
/* Search the next '*' wildcard in the key string */
150
150
wcard = next_wcard;
152
/* Find the needle to look for in the string */
152
/* Find the needle to look for in the string */
155
155
next_wcard = _scan_key_section(section, &wp, kend);
157
if ( wcard == '\0' || str_len(section) > 0 )
157
if ( wcard == '\0' || str_len(section) > 0 )
160
if ( next_wcard == '*' ) {
160
if ( next_wcard == '*' ) {
171
debug_printf("found wildcard '%c' at pos [%d]\n",
171
debug_printf("found wildcard '%c' at pos [%d]\n",
172
172
next_wcard, (int) (wp-key));
174
if ( mvalues != NULL )
174
if ( mvalues != NULL )
175
175
str_truncate(mvalue, 0);
177
177
/* Backtracked; '*' wildcard is retained */
178
178
debug_printf("backtracked");
179
179
backtrack = FALSE;
182
182
/* Determine what we are looking for */
183
183
needle = str_c(section);
184
nend = PTR_OFFSET(needle, str_len(section));
184
nend = PTR_OFFSET(needle, str_len(section));
186
186
debug_printf(" section needle: '%s'\n", t_strdup_until(needle, nend));
187
187
debug_printf(" section key: '%s'\n", t_strdup_until(kp, kend));
188
188
debug_printf(" section remnant: '%s'\n", t_strdup_until(wp, kend));
189
189
debug_printf(" value remnant: '%s'\n", t_strdup_until(vp, vend));
190
190
debug_printf(" key offset: %d\n", key_offset);
193
193
if ( next_wcard == '\0' ) {
194
194
/* No more wildcards; find the needle substring at the end of string */
196
196
const char *qp, *qend;
198
debug_printf("next_wcard = NUL; must find needle at end\n");
200
/* Check if the value is still large enough */
198
debug_printf("next_wcard = NUL; must find needle at end\n");
200
/* Check if the value is still large enough */
201
201
if ( vend - str_len(section) < vp ) {
202
202
debug_printf(" wont match: value is too short\n");
209
209
/* Record match values */
211
211
qp = vp - key_offset;
213
213
if ( mvalues != NULL )
214
214
str_append_n(mvalue, pvp, qp-pvp);
216
216
/* Compare needle to end of value string */
217
if ( !cmp->def->char_match(cmp, &vp, vend, &needle, nend) ) {
218
debug_printf(" match at end failed\n");
217
if ( !cmp->def->char_match(cmp, &vp, vend, &needle, nend) ) {
218
debug_printf(" match at end failed\n");
222
222
/* Add match values */
223
223
if ( mvalues != NULL ) {
224
224
/* Append '*' match value */
227
227
/* Append any initial '?' match values */
228
228
for ( ; qp < qend; qp++ )
229
sieve_match_values_add_char(mvalues, *qp);
229
sieve_match_values_add_char(mvalues, *qp);
232
232
/* Finish match */
244
244
const char *chars;
246
246
/* Reset '?' match values */
247
if ( mvalues != NULL )
247
if ( mvalues != NULL )
248
248
str_truncate(mchars, 0);
250
250
if ( wcard == '\0' ) {
251
251
/* No current wildcard; match needs to happen right at the beginning */
252
252
debug_printf("wcard = NUL; needle should be found at the beginning.\n");
253
253
debug_printf(" begin needle: '%s'\n", t_strdup_until(needle, nend));
254
254
debug_printf(" begin value: '%s'\n", t_strdup_until(vp, vend));
256
if ( !cmp->def->char_match(cmp, &vp, vend, &needle, nend) ) {
257
debug_printf(" failed to find needle at beginning\n");
256
if ( !cmp->def->char_match(cmp, &vp, vend, &needle, nend) ) {
257
debug_printf(" failed to find needle at beginning\n");
263
263
debug_printf("wcard != NUL; must find needle at an offset (>= %d).\n",
266
/* Match may happen at any offset (>= key offset): find substring */
266
/* Match may happen at any offset (>= key offset): find substring */
267
267
vp += key_offset;
268
268
if ( (vp >= vend) || !_string_find(cmp, &vp, vend, &needle, nend) ) {
269
debug_printf(" failed to find needle at an offset\n");
269
debug_printf(" failed to find needle at an offset\n");
273
273
prv = vp - str_len(section);
277
277
/* Append match values */
278
278
if ( mvalues != NULL ) {
279
279
const char *qend = vp - str_len(section);
289
289
str_append_c(mchars, *qp);
293
293
/* Update wildcard and key pointers for next wildcard scan */
294
294
if ( wp < kend ) wp++;
297
297
/* Scan successive '?' wildcards */
298
298
while ( next_wcard == '?' ) {
299
299
debug_printf("next_wcard = '?'; need to match arbitrary character\n");
301
/* Add match value */
301
/* Add match value */
302
302
if ( mvalues != NULL )
303
303
str_append_c(mchars, *vp);
307
/* Scan for next '?' wildcard */
307
/* Scan for next '?' wildcard */
308
308
next_wcard = _scan_key_section(subsection, &wp, kend);
309
debug_printf("found next wildcard '%c' at pos [%d] (fixed match)\n",
309
debug_printf("found next wildcard '%c' at pos [%d] (fixed match)\n",
310
310
next_wcard, (int) (wp-key));
312
312
/* Determine what we are looking for */
313
313
needle = str_c(subsection);
314
314
nend = PTR_OFFSET(needle, str_len(subsection));
317
317
debug_printf(" value remnant: '%s'\n", vp <= vend ? t_strdup_until(vp, vend) : "");
319
319
/* Try matching the needle at fixed position */
320
if ( (needle == nend && next_wcard == '\0' && vp < vend ) ||
321
!cmp->def->char_match(cmp, &vp, vend, &needle, nend) ) {
320
if ( (needle == nend && next_wcard == '\0' && vp < vend ) ||
321
!cmp->def->char_match(cmp, &vp, vend, &needle, nend) ) {
323
323
/* Match failed: now we have a problem. We need to backtrack to the previous
324
324
* '*' wildcard occurence and start scanning for the next possible match.
327
327
debug_printf(" failed fixed match\n");
329
329
/* Start backtrack */
330
330
if ( prv != NULL && prv + 1 < vend ) {
331
331
/* Restore pointers */
336
336
/* Skip forward one value character to scan the next possible match */
337
337
if ( mvalues != NULL )
338
338
str_append_c(mvalue, *vp);
341
341
/* Set wildcard state appropriately */
343
343
next_wcard = '?';
348
348
debug_printf(" BACKTRACK\n");
351
351
/* Break '?' wildcard scanning loop */
355
355
/* Update wildcard and key pointers for next wildcard scan */
356
356
if ( wp < kend ) wp++;
360
360
if ( !backtrack ) {
363
363
if ( next_wcard == '?' ) {
364
debug_printf("failed to match '?'\n");
364
debug_printf("failed to match '?'\n");
368
368
if ( mvalues != NULL ) {
369
369
if ( prv != NULL )
370
370
sieve_match_values_add(mvalues, mvalue);
393
393
str_append_n(mvalue, vp, vend-vp);
394
394
sieve_match_values_add(mvalues, mvalue);
397
397
/* Finish match */
401
401
debug_printf("key ends with '*'\n");
405
405
debug_printf("== Loop ==\n");
413
413
/* By definition, the match is only successful if both value and key pattern
417
417
debug_printf("=== Finish ===\n");
418
418
debug_printf(" result: %s\n", (kp == kend && vp == vend) ? "true" : "false");
420
420
if (kp == kend && vp == vend) {
421
421
/* Activate new match values after successful match */
422
422
if ( mvalues != NULL ) {