1
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
6
#include "str-sanitize.h"
12
#include "sieve-common.h"
13
#include "sieve-extensions.h"
14
#include "sieve-script.h"
15
#include "sieve-ast.h"
16
#include "sieve-commands.h"
17
#include "sieve-validator.h"
19
#include "sieve-comparators.h"
20
#include "sieve-address-parts.h"
23
* Forward declarations
26
static void sieve_validator_register_core_commands
27
(struct sieve_validator *validator);
28
static void sieve_validator_register_core_tests
29
(struct sieve_validator *validator);
35
/* Tag registration */
37
struct sieve_tag_registration {
38
const struct sieve_argument *tag;
39
const char *identifier;
43
/* Command registration */
45
struct sieve_command_registration {
46
const struct sieve_command *command;
48
ARRAY_DEFINE(normal_tags, struct sieve_tag_registration *);
49
ARRAY_DEFINE(instanced_tags, struct sieve_tag_registration *);
50
ARRAY_DEFINE(persistent_tags, struct sieve_tag_registration *);
53
/* Default (literal) arguments */
55
struct sieve_default_argument {
56
const struct sieve_argument *argument;
57
struct sieve_default_argument *overrides;
64
struct sieve_validator_extension_reg {
65
const struct sieve_validator_extension *val_ext;
66
struct sieve_ast_argument *arg;
76
struct sieve_validator {
79
struct sieve_ast *ast;
80
struct sieve_script *script;
82
struct sieve_error_handler *ehandler;
84
bool finished_require;
88
struct hash_table *commands;
90
ARRAY_DEFINE(extensions, struct sieve_validator_extension_reg);
92
/* This is currently a wee bit ugly and needs more thought */
93
struct sieve_default_argument default_arguments[SAT_COUNT];
95
/* Default argument processing state (FIXME: ugly) */
96
struct sieve_default_argument *current_defarg;
97
enum sieve_argument_type current_defarg_type;
98
bool current_defarg_constant;
105
void sieve_validator_warning
106
(struct sieve_validator *validator, unsigned int source_line,
107
const char *fmt, ...)
112
sieve_vwarning(validator->ehandler,
113
sieve_error_script_location(validator->script, source_line),
119
void sieve_validator_error
120
(struct sieve_validator *validator, unsigned int source_line,
121
const char *fmt, ...)
126
sieve_verror(validator->ehandler,
127
sieve_error_script_location(validator->script, source_line),
132
void sieve_validator_critical
133
(struct sieve_validator *validator, unsigned int source_line,
134
const char *fmt, ...)
139
sieve_vcritical(validator->ehandler,
140
sieve_error_script_location(validator->script, source_line),
149
struct sieve_validator *sieve_validator_create
150
(struct sieve_ast *ast, struct sieve_error_handler *ehandler)
154
struct sieve_validator *validator;
156
pool = pool_alloconly_create("sieve_validator", 8192);
157
validator = p_new(pool, struct sieve_validator, 1);
158
validator->pool = pool;
160
validator->ehandler = ehandler;
161
sieve_error_handler_ref(ehandler);
163
validator->ast = ast;
164
validator->script = sieve_ast_script(ast);
167
/* Setup default arguments */
168
validator->default_arguments[SAT_NUMBER].
169
argument = &number_argument;
170
validator->default_arguments[SAT_VAR_STRING].
171
argument = &string_argument;
172
validator->default_arguments[SAT_CONST_STRING].
173
argument = &string_argument;
174
validator->default_arguments[SAT_STRING_LIST].
175
argument = &string_list_argument;
177
/* Setup storage for extension contexts */
178
p_array_init(&validator->extensions, pool, sieve_extensions_get_count());
180
/* Setup command registry */
181
validator->commands = hash_table_create
182
(default_pool, pool, 0, strcase_hash, (hash_cmp_callback_t *)strcasecmp);
183
sieve_validator_register_core_commands(validator);
184
sieve_validator_register_core_tests(validator);
186
/* Pre-load core language features implemented as 'extensions' */
187
for ( i = 0; i < sieve_preloaded_extensions_count; i++ ) {
188
const struct sieve_extension *ext = sieve_preloaded_extensions[i];
190
if ( ext->validator_load != NULL )
191
(void)ext->validator_load(validator);
197
void sieve_validator_free(struct sieve_validator **validator)
199
const struct sieve_validator_extension_reg *extrs;
200
unsigned int ext_count, i;
202
hash_table_destroy(&(*validator)->commands);
203
sieve_ast_unref(&(*validator)->ast);
205
sieve_error_handler_unref(&(*validator)->ehandler);
207
/* Signal registered extensions that the validator is being destroyed */
208
extrs = array_get(&(*validator)->extensions, &ext_count);
209
for ( i = 0; i < ext_count; i++ ) {
210
if ( extrs[i].val_ext != NULL && extrs[i].val_ext->free != NULL )
211
extrs[i].val_ext->free(*validator, extrs[i].context);
214
pool_unref(&(*validator)->pool);
223
pool_t sieve_validator_pool(struct sieve_validator *validator)
225
return validator->pool;
228
struct sieve_error_handler *sieve_validator_error_handler
229
(struct sieve_validator *validator)
231
return validator->ehandler;
234
struct sieve_ast *sieve_validator_ast
235
(struct sieve_validator *validator)
237
return validator->ast;
240
struct sieve_script *sieve_validator_script
241
(struct sieve_validator *validator)
243
return validator->script;
250
/* Dummy command object to mark unknown commands in the registry */
252
static bool _cmd_unknown_validate
253
(struct sieve_validator *validator ATTR_UNUSED,
254
struct sieve_command_context *cmd ATTR_UNUSED)
260
static const struct sieve_command unknown_command = {
261
"", SCT_NONE, 0, 0, FALSE, FALSE ,
262
NULL, NULL, _cmd_unknown_validate, NULL, NULL
265
/* Registration of the core commands of the language */
267
static void sieve_validator_register_core_tests
268
(struct sieve_validator *validator)
272
for ( i = 0; i < sieve_core_tests_count; i++ ) {
273
sieve_validator_register_command(validator, sieve_core_tests[i]);
277
static void sieve_validator_register_core_commands
278
(struct sieve_validator *validator)
282
for ( i = 0; i < sieve_core_commands_count; i++ ) {
283
sieve_validator_register_command(validator, sieve_core_commands[i]);
287
/* Registry functions */
289
static struct sieve_command_registration *
290
sieve_validator_find_command_registration
291
(struct sieve_validator *validator, const char *command)
293
return (struct sieve_command_registration *)
294
hash_table_lookup(validator->commands, command);
297
static struct sieve_command_registration *_sieve_validator_register_command
298
(struct sieve_validator *validator, const struct sieve_command *command,
299
const char *identifier)
301
struct sieve_command_registration *record =
302
p_new(validator->pool, struct sieve_command_registration, 1);
303
record->command = command;
304
hash_table_insert(validator->commands, (void *) identifier, (void *) record);
309
void sieve_validator_register_command
310
(struct sieve_validator *validator, const struct sieve_command *command)
312
struct sieve_command_registration *cmd_reg =
313
sieve_validator_find_command_registration(validator, command->identifier);
315
if ( cmd_reg == NULL )
316
cmd_reg = _sieve_validator_register_command
317
(validator, command, command->identifier);
319
cmd_reg->command = command;
321
if ( command->registered != NULL )
322
command->registered(validator, cmd_reg);
325
static void sieve_validator_register_unknown_command
326
(struct sieve_validator *validator, const char *command)
328
(void)_sieve_validator_register_command(validator, &unknown_command, command);
331
const struct sieve_command *sieve_validator_find_command
332
(struct sieve_validator *validator, const char *command)
334
struct sieve_command_registration *record =
335
sieve_validator_find_command_registration(validator, command);
337
return ( record == NULL ? NULL : record->command );
341
* Per-command tagged argument registry
344
/* Dummy argument object to mark unknown arguments in the registry */
346
static bool _unknown_tag_validate
347
(struct sieve_validator *validator ATTR_UNUSED,
348
struct sieve_ast_argument **arg ATTR_UNUSED,
349
struct sieve_command_context *tst ATTR_UNUSED)
355
static const struct sieve_argument _unknown_tag = {
358
_unknown_tag_validate,
362
/* Registry functions */
364
static void _sieve_validator_register_tag
365
(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg,
366
const struct sieve_argument *tag, const char *identifier, int id_code)
368
struct sieve_tag_registration *reg;
370
reg = p_new(validator->pool, struct sieve_tag_registration, 1);
372
reg->id_code = id_code;
373
if ( identifier == NULL )
374
reg->identifier = tag->identifier;
376
reg->identifier = p_strdup(validator->pool, identifier);
378
if ( !array_is_created(&cmd_reg->normal_tags) )
379
p_array_init(&cmd_reg->normal_tags, validator->pool, 4);
381
array_append(&cmd_reg->normal_tags, ®, 1);
384
void sieve_validator_register_persistent_tag
385
(struct sieve_validator *validator, const struct sieve_argument *tag,
388
struct sieve_command_registration *cmd_reg =
389
sieve_validator_find_command_registration(validator, command);
390
struct sieve_tag_registration *reg =
391
p_new(validator->pool, struct sieve_tag_registration, 1);
396
if ( cmd_reg == NULL ) {
397
cmd_reg = _sieve_validator_register_command(validator, NULL, command);
400
/* Add the tag to the persistent tags list if necessary */
401
if ( tag->validate_persistent != NULL ) {
402
if ( !array_is_created(&cmd_reg->persistent_tags) )
403
p_array_init(&cmd_reg->persistent_tags, validator->pool, 4);
405
array_append(&cmd_reg->persistent_tags, ®, 1);
409
void sieve_validator_register_external_tag
410
(struct sieve_validator *validator, const struct sieve_argument *tag,
411
const char *command, int id_code)
413
struct sieve_command_registration *cmd_reg =
414
sieve_validator_find_command_registration(validator, command);
416
if ( cmd_reg == NULL ) {
417
cmd_reg = _sieve_validator_register_command(validator, NULL, command);
420
_sieve_validator_register_tag
421
(validator, cmd_reg, tag, NULL, id_code);
424
void sieve_validator_register_tag
425
(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg,
426
const struct sieve_argument *tag, int id_code)
428
if ( tag->is_instance_of == NULL )
429
_sieve_validator_register_tag(validator, cmd_reg, tag, NULL, id_code);
431
struct sieve_tag_registration *reg =
432
p_new(validator->pool, struct sieve_tag_registration, 1);
434
reg->id_code = id_code;
436
if ( !array_is_created(&cmd_reg->instanced_tags) )
437
p_array_init(&cmd_reg->instanced_tags, validator->pool, 4);
439
array_append(&cmd_reg->instanced_tags, ®, 1);
443
static void sieve_validator_register_unknown_tag
444
(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg,
447
_sieve_validator_register_tag(validator, cmd_reg, &_unknown_tag, tag, 0);
450
static const struct sieve_argument *sieve_validator_find_tag
451
(struct sieve_validator *valdtr, struct sieve_command_context *cmd,
452
struct sieve_ast_argument *arg, int *id_code)
454
struct sieve_command_registration *cmd_reg = cmd->cmd_reg;
455
const char *tag = sieve_ast_argument_tag(arg);
458
if ( id_code != NULL )
461
/* First check normal tags */
462
if ( array_is_created(&cmd_reg->normal_tags) ) {
463
for ( i = 0; i < array_count(&cmd_reg->normal_tags); i++ ) {
464
struct sieve_tag_registration * const *reg =
465
array_idx(&cmd_reg->normal_tags, i);
467
if ( (*reg)->tag != NULL && strcasecmp((*reg)->identifier,tag) == 0) {
468
if ( id_code != NULL )
469
*id_code = (*reg)->id_code;
476
/* Not found so far, try the instanced tags */
477
if ( array_is_created(&cmd_reg->instanced_tags) ) {
478
for ( i = 0; i < array_count(&cmd_reg->instanced_tags); i++ ) {
479
struct sieve_tag_registration * const *reg =
480
array_idx(&cmd_reg->instanced_tags, i);
482
if ( (*reg)->tag != NULL &&
483
(*reg)->tag->is_instance_of(valdtr, cmd, arg) ) {
484
if ( id_code != NULL )
485
*id_code = (*reg)->id_code;
495
static const struct sieve_argument *sieve_validator_find_tag_by_identifier
496
(struct sieve_validator *valdtr, struct sieve_command_context *cmd,
499
struct sieve_ast_argument *arg;
501
/* Construct dummy argument */
502
arg = t_new(struct sieve_ast_argument, 1);
503
arg->type = SAAT_TAG;
504
arg->_value.tag = tag;
506
return sieve_validator_find_tag(valdtr, cmd, arg, NULL);
513
const struct sieve_extension *sieve_validator_extension_load
514
(struct sieve_validator *valdtr, struct sieve_command_context *cmd,
515
struct sieve_ast_argument *ext_arg, string_t *ext_name)
518
struct sieve_validator_extension_reg *reg;
519
const struct sieve_extension *ext;
520
const char *name = str_c(ext_name);
522
if ( str_len(ext_name) > 128 ) {
523
sieve_argument_validate_error(valdtr, ext_arg,
524
"%s %s: unknown Sieve capability '%s' (name is impossibly long)",
525
cmd->command->identifier, sieve_command_type_name(cmd->command),
526
str_sanitize(name, 128));
530
ext = sieve_extension_get_by_name(name);
534
bool core_test = FALSE;
535
bool core_command = FALSE;
537
for ( i = 0; !core_command && i < sieve_core_commands_count; i++ ) {
538
if ( strcasecmp(sieve_core_commands[i]->identifier, name) == 0 )
542
for ( i = 0; !core_test && i < sieve_core_tests_count; i++ ) {
543
if ( strcasecmp(sieve_core_tests[i]->identifier, name) == 0 )
547
if ( core_test || core_command ) {
548
sieve_argument_validate_error(valdtr, ext_arg,
549
"%s %s: '%s' is not known as a Sieve capability, "
550
"but it is known as a Sieve %s that is always available",
551
cmd->command->identifier, sieve_command_type_name(cmd->command),
552
name, ( core_test ? "test" : "command" ));
554
sieve_argument_validate_error(valdtr, ext_arg,
555
"%s %s: unknown Sieve capability '%s'",
556
cmd->command->identifier, sieve_command_type_name(cmd->command),
562
sieve_ast_extension_link(valdtr->ast, ext);
564
if ( ext->validator_load != NULL && !ext->validator_load(valdtr) ) {
565
sieve_argument_validate_error(valdtr, ext_arg,
566
"%s %s: failed to load Sieve capability '%s'",
567
cmd->command->identifier, sieve_command_type_name(cmd->command),
572
/* Register extension no matter what and store the AST argument registering it */
573
ext_id = SIEVE_EXT_ID(ext);
575
reg = array_idx_modifiable(&valdtr->extensions, (unsigned int) ext_id);
583
void sieve_validator_extension_register
584
(struct sieve_validator *valdtr,
585
const struct sieve_validator_extension *val_ext, void *context)
587
struct sieve_validator_extension_reg *reg;
588
int ext_id = SIEVE_EXT_ID(val_ext->ext);
590
if ( ext_id < 0 ) return;
592
reg = array_idx_modifiable(&valdtr->extensions, (unsigned int) ext_id);
593
reg->val_ext = val_ext;
594
reg->context = context;
597
bool sieve_validator_extension_loaded
598
(struct sieve_validator *valdtr, const struct sieve_extension *ext)
600
int ext_id = SIEVE_EXT_ID(ext);
601
const struct sieve_validator_extension_reg *reg;
603
if ( ext_id < 0 || ext_id >= (int) array_count(&valdtr->extensions))
606
reg = array_idx(&valdtr->extensions, (unsigned int) ext_id);
608
return ( reg->loaded );
611
void sieve_validator_extension_set_context
612
(struct sieve_validator *valdtr, const struct sieve_extension *ext,
615
struct sieve_validator_extension_reg *reg;
616
int ext_id = SIEVE_EXT_ID(ext);
618
if ( ext_id < 0 ) return;
620
reg = array_idx_modifiable(&valdtr->extensions, (unsigned int) ext_id);
621
reg->context = context;
624
void *sieve_validator_extension_get_context
625
(struct sieve_validator *valdtr, const struct sieve_extension *ext)
627
int ext_id = SIEVE_EXT_ID(ext);
628
const struct sieve_validator_extension_reg *reg;
630
if ( ext_id < 0 || ext_id >= (int) array_count(&valdtr->extensions) )
633
reg = array_idx(&valdtr->extensions, (unsigned int) ext_id);
639
* Overriding the default literal arguments
642
void sieve_validator_argument_override
643
(struct sieve_validator *validator, enum sieve_argument_type type,
644
const struct sieve_argument *argument)
646
struct sieve_default_argument *arg;
648
if ( validator->default_arguments[type].argument != NULL ) {
649
arg = p_new(validator->pool, struct sieve_default_argument, 1);
650
*arg = validator->default_arguments[type];
652
validator->default_arguments[type].overrides = arg;
655
validator->default_arguments[type].argument = argument;
658
static bool sieve_validator_argument_default_activate
659
(struct sieve_validator *validator, struct sieve_command_context *cmd,
660
struct sieve_default_argument *defarg, struct sieve_ast_argument *arg)
663
struct sieve_default_argument *prev_defarg;
665
prev_defarg = validator->current_defarg;
666
validator->current_defarg = defarg;
668
arg->argument = defarg->argument;
669
if (defarg->argument != NULL && defarg->argument->validate != NULL )
670
result = defarg->argument->validate(validator, &arg, cmd);
672
validator->current_defarg = prev_defarg;
677
bool sieve_validator_argument_activate_super
678
(struct sieve_validator *validator, struct sieve_command_context *cmd,
679
struct sieve_ast_argument *arg, bool constant ATTR_UNUSED)
681
struct sieve_default_argument *defarg;
683
if ( validator->current_defarg == NULL ||
684
validator->current_defarg->overrides == NULL )
687
if ( validator->current_defarg->overrides->argument == &string_argument ) {
688
switch ( validator->current_defarg_type) {
689
case SAT_CONST_STRING:
690
if ( !validator->current_defarg_constant ) {
691
validator->current_defarg_type = SAT_VAR_STRING;
692
defarg = &validator->default_arguments[SAT_VAR_STRING];
694
defarg = validator->current_defarg->overrides;
697
defarg = validator->current_defarg->overrides;
703
defarg = validator->current_defarg->overrides;
705
return sieve_validator_argument_default_activate
706
(validator, cmd, defarg, arg);
710
* Argument Validation API
713
bool sieve_validator_argument_activate
714
(struct sieve_validator *validator, struct sieve_command_context *cmd,
715
struct sieve_ast_argument *arg, bool constant)
717
struct sieve_default_argument *defarg;
719
switch ( sieve_ast_argument_type(arg) ) {
721
validator->current_defarg_type = SAT_NUMBER;
724
validator->current_defarg_type = SAT_CONST_STRING;
726
case SAAT_STRING_LIST:
727
validator->current_defarg_type = SAT_STRING_LIST;
733
validator->current_defarg_constant = constant;
734
defarg = &validator->default_arguments[validator->current_defarg_type];
736
if ( !constant && defarg->argument == &string_argument ) {
737
validator->current_defarg_type = SAT_VAR_STRING;
738
defarg = &validator->default_arguments[SAT_VAR_STRING];
741
return sieve_validator_argument_default_activate(validator, cmd, defarg, arg);
744
bool sieve_validate_positional_argument
745
(struct sieve_validator *validator, struct sieve_command_context *cmd,
746
struct sieve_ast_argument *arg, const char *arg_name, unsigned int arg_pos,
747
enum sieve_ast_argument_type req_type)
749
if ( sieve_ast_argument_type(arg) != req_type &&
750
(sieve_ast_argument_type(arg) != SAAT_STRING ||
751
req_type != SAAT_STRING_LIST) )
753
sieve_argument_validate_error(validator, arg,
754
"the %s %s expects %s as argument %d (%s), but %s was found",
755
cmd->command->identifier, sieve_command_type_name(cmd->command),
756
sieve_ast_argument_type_name(req_type),
757
arg_pos, arg_name, sieve_ast_argument_name(arg));
764
bool sieve_validate_tag_parameter
765
(struct sieve_validator *validator, struct sieve_command_context *cmd,
766
struct sieve_ast_argument *tag, struct sieve_ast_argument *param,
767
enum sieve_ast_argument_type req_type)
769
if ( param == NULL ) {
770
sieve_argument_validate_error(validator, tag,
771
"the :%s tag for the %s %s requires %s as parameter, "
772
"but no more arguments were found", sieve_ast_argument_tag(tag),
773
cmd->command->identifier, sieve_command_type_name(cmd->command),
774
sieve_ast_argument_type_name(req_type));
778
if ( sieve_ast_argument_type(param) != req_type &&
779
(sieve_ast_argument_type(param) != SAAT_STRING ||
780
req_type != SAAT_STRING_LIST) )
782
sieve_argument_validate_error(validator, param,
783
"the :%s tag for the %s %s requires %s as parameter, "
784
"but %s was found", sieve_ast_argument_tag(tag),
785
cmd->command->identifier, sieve_command_type_name(cmd->command),
786
sieve_ast_argument_type_name(req_type), sieve_ast_argument_name(param));
790
param->arg_id_code = tag->arg_id_code;
792
return sieve_validator_argument_activate(validator, cmd, param, FALSE);
796
* Command argument validation
799
static bool sieve_validate_command_arguments
800
(struct sieve_validator *validator, struct sieve_command_context *cmd)
802
int arg_count = cmd->command->positional_arguments;
804
struct sieve_ast_argument *arg;
805
struct sieve_command_registration *cmd_reg = cmd->cmd_reg;
807
/* Validate any tags that might be present */
808
arg = sieve_ast_argument_first(cmd->ast_node);
810
/* Visit tagged and optional arguments */
811
while ( sieve_ast_argument_type(arg) == SAAT_TAG ) {
813
struct sieve_ast_argument *parg;
814
const struct sieve_argument *tag =
815
sieve_validator_find_tag(validator, cmd, arg, &id_code);
818
sieve_argument_validate_error(validator, arg,
819
"unknown tagged argument ':%s' for the %s %s "
820
"(reported only once at first occurence)",
821
sieve_ast_argument_tag(arg), cmd->command->identifier,
822
sieve_command_type_name(cmd->command));
823
sieve_validator_register_unknown_tag
824
(validator, cmd_reg, sieve_ast_argument_tag(arg));
828
/* Check whether previously tagged as unknown */
829
if ( tag->identifier != NULL && *(tag->identifier) == '\0' )
832
/* Assign the tagged argument type to the ast for later reference
836
arg->arg_id_code = id_code;
838
/* Scan backwards for any duplicates */
839
parg = sieve_ast_argument_prev(arg);
840
while ( parg != NULL ) {
841
if ( (sieve_ast_argument_type(parg) == SAAT_TAG && parg->argument == tag)
842
|| (id_code > 0 && parg->arg_id_code == id_code) )
844
const char *tag_id = sieve_ast_argument_tag(arg);
845
const char *tag_desc =
846
strcmp(tag->identifier, tag_id) != 0 ?
847
t_strdup_printf("%s argument (:%s)", tag->identifier, tag_id) :
848
t_strdup_printf(":%s argument", tag->identifier);
850
sieve_argument_validate_error(validator, arg,
851
"encountered duplicate %s for the %s %s",
852
tag_desc, cmd->command->identifier,
853
sieve_command_type_name(cmd->command));
858
parg = sieve_ast_argument_prev(parg);
861
/* Call the validation function for the tag (if present)
862
* Fail if the validation fails:
863
* Let's not whine multiple times about a single command having multiple
866
if ( tag->validate != NULL ) {
867
if ( !tag->validate(validator, &arg, cmd) )
870
arg = sieve_ast_argument_next(arg);
873
/* Remaining arguments should be positional (tags are not allowed here) */
874
cmd->first_positional = arg;
876
while ( arg != NULL ) {
877
if ( sieve_ast_argument_type(arg) == SAAT_TAG ) {
878
sieve_argument_validate_error(validator, arg,
879
"encountered an unexpected tagged argument ':%s' "
880
"while validating positional arguments for the %s %s",
881
sieve_ast_argument_tag(arg), cmd->command->identifier,
882
sieve_command_type_name(cmd->command));
888
arg = sieve_ast_argument_next(arg);
891
/* Check the required count versus the real number of arguments */
892
if ( arg_count >= 0 && real_count != arg_count ) {
893
sieve_command_validate_error(validator, cmd,
894
"the %s %s requires %d positional argument(s), but %d is/are specified",
895
cmd->command->identifier, sieve_command_type_name(cmd->command),
896
arg_count, real_count);
900
/* Call initial validation for persistent arguments */
901
if ( array_is_created(&cmd_reg->persistent_tags) ) {
904
for ( i = 0; i < array_count(&cmd_reg->persistent_tags); i++ ) {
905
struct sieve_tag_registration * const *reg =
906
array_idx(&cmd_reg->persistent_tags, i);
907
const struct sieve_argument *tag = (*reg)->tag;
909
if ( tag != NULL && tag->validate_persistent != NULL ) { /* To be sure */
910
if ( !tag->validate_persistent(validator, cmd) )
919
static bool sieve_validate_arguments_context
920
(struct sieve_validator *validator, struct sieve_command_context *cmd)
922
struct sieve_ast_argument *arg =
923
sieve_command_first_argument(cmd);
925
while ( arg != NULL ) {
926
const struct sieve_argument *argument = arg->argument;
928
if ( argument != NULL && argument->validate_context != NULL ) {
929
if ( !argument->validate_context(validator, arg, cmd) )
933
arg = sieve_ast_argument_next(arg);
940
* Command Validation API
943
static bool sieve_validate_command_subtests
944
(struct sieve_validator *valdtr, struct sieve_command_context *cmd,
945
const unsigned int count)
950
if ( sieve_ast_test_count(cmd->ast_node) > 0 ) {
951
/* Unexpected command specified */
952
enum sieve_command_type ctype = SCT_NONE;
953
struct sieve_command_registration *cmd_reg;
954
struct sieve_ast_node *test = sieve_ast_test_first(cmd->ast_node);
956
cmd_reg = sieve_validator_find_command_registration
957
(valdtr, test->identifier);
959
/* First check what we are dealing with */
960
if ( cmd_reg != NULL && cmd_reg->command != NULL )
961
ctype = cmd_reg->command->type;
964
case SCT_TEST: /* Spurious test */
966
sieve_command_validate_error(valdtr, cmd,
967
"the %s %s accepts no sub-tests, but tests are specified",
968
cmd->command->identifier, sieve_command_type_name(cmd->command));
971
case SCT_NONE: /* Unknown command */
973
/* Is it perhaps a tag for which the ':' was omitted ? */
974
if ( sieve_validator_find_tag_by_identifier
975
(valdtr, cmd, test->identifier) != NULL ) {
976
sieve_command_validate_error(valdtr, cmd,
977
"missing colon ':' before ':%s' tag in %s %s", test->identifier,
978
cmd->command->identifier, sieve_command_type_name(cmd->command));
984
sieve_command_validate_error(valdtr, cmd,
985
"missing semicolon ';' after %s %s",
986
cmd->command->identifier, sieve_command_type_name(cmd->command));
993
if ( sieve_ast_test_count(cmd->ast_node) == 0 ) {
994
sieve_command_validate_error(valdtr, cmd,
995
"the %s %s requires one sub-test, but none is specified",
996
cmd->command->identifier, sieve_command_type_name(cmd->command));
1000
} else if ( sieve_ast_test_count(cmd->ast_node) > 1 ||
1001
cmd->ast_node->test_list ) {
1003
sieve_command_validate_error(valdtr, cmd,
1004
"the %s %s requires one sub-test, but a list of tests is specified",
1005
cmd->command->identifier, sieve_command_type_name(cmd->command));
1012
if ( sieve_ast_test_count(cmd->ast_node) == 0 ) {
1013
sieve_command_validate_error(valdtr, cmd,
1014
"the %s %s requires a list of sub-tests, but none is specified",
1015
cmd->command->identifier, sieve_command_type_name(cmd->command));
1019
} else if ( sieve_ast_test_count(cmd->ast_node) == 1 &&
1020
!cmd->ast_node->test_list ) {
1022
sieve_command_validate_error(valdtr, cmd,
1023
"the %s %s requires a list of sub-tests, "
1024
"but a single test is specified",
1025
cmd->command->identifier, sieve_command_type_name(cmd->command) );
1035
static bool sieve_validate_command_block
1036
(struct sieve_validator *validator, struct sieve_command_context *cmd,
1037
bool block_allowed, bool block_required)
1039
i_assert( cmd->ast_node->type == SAT_COMMAND );
1041
if ( block_required ) {
1042
if ( !cmd->ast_node->block ) {
1043
sieve_command_validate_error(validator, cmd,
1044
"the %s command requires a command block, but it is missing",
1045
cmd->command->identifier);
1049
} else if ( !block_allowed && cmd->ast_node->block ) {
1050
sieve_command_validate_error(validator, cmd,
1051
"the %s command does not accept a command block, "
1052
"but one is specified anyway",
1053
cmd->command->identifier );
1065
static bool sieve_validate_test_list
1066
(struct sieve_validator *validator, struct sieve_ast_node *test_list);
1067
static bool sieve_validate_block
1068
(struct sieve_validator *validator, struct sieve_ast_node *block);
1069
static bool sieve_validate_command
1070
(struct sieve_validator *validator, struct sieve_ast_node *cmd_node);
1072
static bool sieve_validate_command_context
1073
(struct sieve_validator *valdtr, struct sieve_ast_node *cmd_node)
1075
enum sieve_ast_type ast_type = sieve_ast_node_type(cmd_node);
1076
struct sieve_command_registration *cmd_reg;
1078
i_assert( ast_type == SAT_TEST || ast_type == SAT_COMMAND );
1080
/* Verify the command specified by this node */
1082
cmd_reg = sieve_validator_find_command_registration
1083
(valdtr, cmd_node->identifier);
1085
if ( cmd_reg != NULL && cmd_reg->command != NULL ) {
1086
const struct sieve_command *command = cmd_reg->command;
1088
/* Identifier = "" when the command was previously marked as unknown */
1089
if ( *(command->identifier) != '\0' ) {
1090
if ( (command->type == SCT_COMMAND && ast_type == SAT_TEST)
1091
|| (command->type == SCT_TEST && ast_type == SAT_COMMAND) ) {
1092
sieve_validator_error(
1093
valdtr, cmd_node->source_line, "attempted to use %s '%s' as %s",
1094
sieve_command_type_name(command), cmd_node->identifier,
1095
sieve_ast_type_name(ast_type));
1100
struct sieve_command_context *ctx =
1101
sieve_command_context_create(cmd_node, command, cmd_reg);
1102
cmd_node->context = ctx;
1109
sieve_validator_error(
1110
valdtr, cmd_node->source_line,
1111
"unknown %s '%s' (only reported once at first occurence)",
1112
sieve_ast_type_name(ast_type), cmd_node->identifier);
1114
sieve_validator_register_unknown_command(valdtr, cmd_node->identifier);
1122
static bool sieve_validate_command
1123
(struct sieve_validator *valdtr, struct sieve_ast_node *cmd_node)
1125
enum sieve_ast_type ast_type = sieve_ast_node_type(cmd_node);
1126
struct sieve_command_context *ctx = cmd_node->context;
1127
const struct sieve_command *command = ( ctx != NULL ? ctx->command : NULL );
1130
i_assert( ast_type == SAT_TEST || ast_type == SAT_COMMAND );
1132
if ( command != NULL && *(command->identifier) != '\0' ) {
1134
if ( command->pre_validate == NULL
1135
|| command->pre_validate(valdtr, ctx) ) {
1137
/* Check argument syntax */
1138
if ( !sieve_validate_command_arguments(valdtr, ctx) ) {
1141
/* A missing ':' causes a tag to become a test. This can be the cause
1142
* of the arguments validation failing. Therefore we must produce an
1143
* error for the sub-tests as well if appropriate.
1145
(void)sieve_validate_command_subtests(valdtr, ctx, command->subtests);
1148
!sieve_validate_command_subtests(valdtr, ctx, command->subtests) ||
1149
(ast_type == SAT_COMMAND && !sieve_validate_command_block
1150
(valdtr, ctx, command->block_allowed, command->block_required)) ) {
1155
/* Call command validation function if specified */
1156
if ( command->validate != NULL )
1157
result = command->validate(valdtr, ctx) && result;
1160
/* If pre-validation fails, don't bother to validate further
1161
* as context might be missing and doing so is not very useful for
1162
* further error reporting anyway
1167
result = result && sieve_validate_arguments_context(valdtr, ctx);
1172
* Descend further into the AST
1175
if ( command != NULL ) {
1177
if ( command->subtests > 0 &&
1178
(result || sieve_errors_more_allowed(valdtr->ehandler)) )
1179
result = sieve_validate_test_list(valdtr, cmd_node) && result;
1182
if ( command->block_allowed && ast_type == SAT_COMMAND &&
1183
(result || sieve_errors_more_allowed(valdtr->ehandler)) )
1184
result = sieve_validate_block(valdtr, cmd_node) && result;
1190
static bool sieve_validate_test_list
1191
(struct sieve_validator *valdtr, struct sieve_ast_node *test_list)
1194
struct sieve_ast_node *test;
1196
test = sieve_ast_test_first(test_list);
1197
while ( test != NULL
1198
&& (result || sieve_errors_more_allowed(valdtr->ehandler)) ) {
1201
sieve_validate_command_context(valdtr, test) &&
1202
sieve_validate_command(valdtr, test) &&
1205
test = sieve_ast_test_next(test);
1211
static bool sieve_validate_block
1212
(struct sieve_validator *valdtr, struct sieve_ast_node *block)
1214
bool result = TRUE, fatal = FALSE;
1215
struct sieve_ast_node *command, *next;
1218
command = sieve_ast_command_first(block);
1219
while ( !fatal && command != NULL
1220
&& (result || sieve_errors_more_allowed(valdtr->ehandler)) ) {
1221
bool command_success;
1223
next = sieve_ast_command_next(command);
1224
command_success = sieve_validate_command_context(valdtr, command);
1225
result = command_success && result;
1227
/* Check if this is the first non-require command */
1228
if ( command_success && sieve_ast_node_type(block) == SAT_ROOT
1229
&& !valdtr->finished_require && command->context != NULL
1230
&& command->context->command != &cmd_require ) {
1231
const struct sieve_validator_extension_reg *extrs;
1232
unsigned int ext_count, i;
1234
valdtr->finished_require = TRUE;
1236
/* Validate all 'require'd extensions */
1237
extrs = array_get(&valdtr->extensions, &ext_count);
1238
for ( i = 0; i < ext_count; i++ ) {
1239
if ( extrs[i].val_ext != NULL
1240
&& extrs[i].val_ext->validate != NULL ) {
1242
if ( !extrs[i].val_ext->validate
1243
(valdtr, extrs[i].context, extrs[i].arg) )
1250
result = !fatal && sieve_validate_command(valdtr, command) && result;
1256
return result && !fatal;
1259
bool sieve_validator_run(struct sieve_validator *validator)
1261
return sieve_validate_block(validator, sieve_ast_root(validator->ast));
1265
* Validator object registry
1268
struct sieve_validator_object_registry {
1269
struct sieve_validator *validator;
1270
ARRAY_DEFINE(registrations, const struct sieve_object *);
1273
struct sieve_validator_object_registry *sieve_validator_object_registry_get
1274
(struct sieve_validator *validator, const struct sieve_extension *ext)
1276
return (struct sieve_validator_object_registry *)
1277
sieve_validator_extension_get_context(validator, ext);
1280
void sieve_validator_object_registry_add
1281
(struct sieve_validator_object_registry *regs,
1282
const struct sieve_object *object)
1284
array_append(®s->registrations, &object, 1);
1287
const struct sieve_object *sieve_validator_object_registry_find
1288
(struct sieve_validator_object_registry *regs, const char *identifier)
1292
for ( i = 0; i < array_count(®s->registrations); i++ ) {
1293
const struct sieve_object * const *obj = array_idx(®s->registrations, i);
1295
if ( strcasecmp((*obj)->identifier, identifier) == 0)
1302
struct sieve_validator_object_registry *sieve_validator_object_registry_create
1303
(struct sieve_validator *validator)
1305
pool_t pool = validator->pool;
1306
struct sieve_validator_object_registry *regs =
1307
p_new(pool, struct sieve_validator_object_registry, 1);
1309
/* Setup registry */
1310
p_array_init(®s->registrations, validator->pool, 4);
1312
regs->validator = validator;
1317
struct sieve_validator_object_registry *sieve_validator_object_registry_init
1318
(struct sieve_validator *validator, const struct sieve_extension *ext)
1320
struct sieve_validator_object_registry *regs =
1321
sieve_validator_object_registry_create(validator);
1323
sieve_validator_extension_set_context(validator, ext, regs);