61
61
* Notify method registry
64
64
static const struct sieve_enotify_method *ext_enotify_method_register
65
(struct sieve_instance *svinst, struct ext_enotify_context *ectx,
66
const struct sieve_enotify_method_def *nmth_def)
65
(struct sieve_instance *svinst, struct ext_enotify_context *ectx,
66
const struct sieve_enotify_method_def *nmth_def)
68
68
struct sieve_enotify_method *nmth;
69
69
int nmth_id = (int) array_count(&ectx->notify_methods);
104
104
const struct sieve_enotify_method *sieve_enotify_method_register
105
(struct sieve_instance *svinst,
105
(struct sieve_instance *svinst,
106
106
const struct sieve_enotify_method_def *nmth_def)
108
108
const struct sieve_extension *ntfy_ext =
109
109
sieve_extension_get_by_name(svinst, "enotify");
111
111
if ( ntfy_ext != NULL ) {
112
struct ext_enotify_context *ectx =
112
struct ext_enotify_context *ectx =
113
113
(struct ext_enotify_context *) ntfy_ext->context;
115
115
return ext_enotify_method_register(svinst, ectx, nmth_def);
126
126
sieve_extension_get_by_name(svinst, "enotify");
128
128
if ( ntfy_ext != NULL ) {
129
struct ext_enotify_context *ectx =
129
struct ext_enotify_context *ectx =
130
130
(struct ext_enotify_context *) ntfy_ext->context;
131
131
int nmth_id = nmth->id;
133
133
if ( nmth_id >= 0 && nmth_id < (int)array_count(&ectx->notify_methods) ) {
134
134
struct sieve_enotify_method *nmth_mod =
135
135
array_idx_modifiable(&ectx->notify_methods, nmth_id);
137
137
nmth_mod->def = NULL;
142
142
const struct sieve_enotify_method *ext_enotify_method_find
143
(const struct sieve_extension *ntfy_ext, const char *identifier)
143
(const struct sieve_extension *ntfy_ext, const char *identifier)
145
struct ext_enotify_context *ectx =
145
struct ext_enotify_context *ectx =
146
146
(struct ext_enotify_context *) ntfy_ext->context;
147
147
unsigned int meth_count, i;
148
148
const struct sieve_enotify_method *methods;
150
150
methods = array_get(&ectx->notify_methods, &meth_count);
152
152
for ( i = 0; i < meth_count; i++ ) {
153
153
if ( methods[i].def == NULL ) continue;
156
156
return &methods[i];
163
163
static const char *ext_notify_get_methods_string
164
164
(const struct sieve_extension *ntfy_ext)
166
struct ext_enotify_context *ectx =
166
struct ext_enotify_context *ectx =
167
167
(struct ext_enotify_context *) ntfy_ext->context;
168
168
unsigned int meth_count, i;
169
169
const struct sieve_enotify_method *methods;
170
170
string_t *result = t_str_new(128);
172
172
methods = array_get(&ectx->notify_methods, &meth_count);
174
174
if ( meth_count > 0 ) {
175
175
for ( i = 0; i < meth_count; i++ ) {
176
176
if ( str_len(result) > 0 )
179
179
if ( methods[i].def != NULL )
180
180
str_append(result, methods[i].def->identifier);
183
183
return str_c(result);
190
190
* Compile-time argument validation
193
193
static const char *ext_enotify_uri_scheme_parse(const char **uri_p)
195
195
string_t *scheme = t_str_new(EXT_ENOTIFY_MAX_SCHEME_LEN);
196
196
const char *p = *uri_p;
197
197
unsigned int len = 0;
201
201
* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
203
203
* FIXME: we do not allow '%' in schemes. Is this correct?
206
206
if ( !i_isalpha(*p) )
209
209
str_append_c(scheme, *p);
212
212
while ( *p != '\0' && len < EXT_ENOTIFY_MAX_SCHEME_LEN ) {
214
214
if ( !i_isalnum(*p) && *p != '+' && *p != '-' && *p != '.' )
217
217
str_append_c(scheme, *p);
227
227
return str_c(scheme);
232
232
const char **opt_name_r, const char **opt_value_r)
234
234
const char *p = option;
236
236
/* "<optionname>=<value>".
238
238
* l-d = ALPHA / DIGIT
239
239
* l-d-p = l-d / "." / "-" / "_"
240
240
* optionname = l-d *l-d-p
241
241
* value = *(%x01-09 / %x0B-0C / %x0E-FF)
247
247
* optionname = l-d *l-d-p
250
250
/* Explicitly report empty option as such */
251
251
if ( *p == '\0' ) {
252
252
sieve_enotify_error(nenv, "empty option specified");
256
256
/* l-d = ALPHA / DIGIT */
257
257
if ( i_isalnum(*p) ) {
260
260
/* l-d-p = l-d / "." / "-" / "_" */
261
261
while ( i_isalnum(*p) || *p == '.' || *p == '-' || *p == '_' )
265
265
/* Parsing must end at '=' and we must parse at least one character */
266
266
if ( *p != '=' || p == option ) {
267
267
sieve_enotify_error(nenv, "invalid option name specified in option '%s'",
268
268
str_sanitize(option, 80));
272
272
/* Assign option name */
273
if ( opt_name_r != NULL )
273
if ( opt_name_r != NULL )
274
274
*opt_name_r = t_strdup_until(option, p);
279
279
/* Exit now if only the option name is of interest */
284
284
* Parse option value
287
287
/* value = *(%x01-09 / %x0B-0C / %x0E-FF) */
288
288
while ( *p != '\0' && *p != 0x0A && *p != 0x0D )
291
291
/* Parse must end at end of string */
292
292
if ( *p != '\0' ) {
293
sieve_enotify_error(nenv,
293
sieve_enotify_error(nenv,
294
294
"notify command: invalid option value specified in option '%s'",
295
295
str_sanitize(option, 80));
299
299
/* Assign option value */
300
300
if ( opt_value_r != NULL )
301
301
*opt_value_r = p;
306
306
struct _ext_enotify_option_check_context {
307
307
struct sieve_validator *valdtr;
311
311
static int _ext_enotify_option_check
312
312
(void *context, struct sieve_ast_argument *arg)
314
struct _ext_enotify_option_check_context *optn_context =
314
struct _ext_enotify_option_check_context *optn_context =
315
315
(struct _ext_enotify_option_check_context *) context;
316
316
struct sieve_validator *valdtr = optn_context->valdtr;
317
317
const struct sieve_enotify_method *method = optn_context->method;
319
319
const char *option = sieve_ast_argument_strc(arg);
320
320
const char *opt_name = NULL, *opt_value = NULL;
321
321
bool result = TRUE, check = TRUE;
323
323
/* Compose log structure */
324
324
memset(&nenv, 0, sizeof(nenv));
325
nenv.method = method;
325
nenv.method = method;
326
326
nenv.ehandler = sieve_prefix_ehandler_create
327
(sieve_validator_error_handler(valdtr),
327
(sieve_validator_error_handler(valdtr),
328
328
sieve_error_script_location
329
(sieve_validator_script(valdtr), arg->source_line),
329
(sieve_validator_script(valdtr), arg->source_line),
330
330
"notify command");
332
332
/* Parse option */
333
333
if ( !sieve_argument_is_string_literal(arg) ) {
334
334
/* Variable string: partial option parse
336
336
* If the string item is not a string literal, it cannot be validated fully
337
337
* at compile time. We can however check whether the '=' is in the string
338
338
* specification and whether the part before the '=' is a valid option name.
339
339
* In that case, the method option check function is called with the value
340
340
* parameter equal to NULL, meaning that it should only check the validity
341
341
* of the option itself and not the assigned value.
343
343
if ( !ext_enotify_option_parse(NULL, option, TRUE, &opt_name, &opt_value) )
348
348
(&nenv, option, FALSE, &opt_name, &opt_value) )
352
352
/* Call method's option check function */
353
if ( result && check && method->def != NULL &&
354
method->def->compile_check_option != NULL )
355
result = method->def->compile_check_option(&nenv, opt_name, opt_value);
353
if ( result && check && method->def != NULL &&
354
method->def->compile_check_option != NULL )
355
result = method->def->compile_check_option(&nenv, opt_name, opt_value);
357
357
sieve_error_handler_unref(&nenv.ehandler);
362
362
bool ext_enotify_compile_check_arguments
363
363
(struct sieve_validator *valdtr, struct sieve_command *cmd,
364
struct sieve_ast_argument *uri_arg, struct sieve_ast_argument *msg_arg,
364
struct sieve_ast_argument *uri_arg, struct sieve_ast_argument *msg_arg,
365
365
struct sieve_ast_argument *from_arg, struct sieve_ast_argument *options_arg)
367
367
const struct sieve_extension *this_ext = cmd->ext;
377
377
if ( !sieve_argument_is_string_literal(uri_arg) )
380
380
/* Parse scheme part of URI */
381
381
if ( (scheme=ext_enotify_uri_scheme_parse(&uri)) == NULL ) {
382
sieve_argument_validate_error(valdtr, uri_arg,
383
"notify command: invalid scheme part for method URI '%s'",
382
sieve_argument_validate_error(valdtr, uri_arg,
383
"notify command: invalid scheme part for method URI '%s'",
384
384
str_sanitize(sieve_ast_argument_strc(uri_arg), 80));
388
388
/* Find used method with the parsed scheme identifier */
389
389
if ( (method=ext_enotify_method_find(this_ext, scheme)) == NULL ) {
390
sieve_argument_validate_error(valdtr, uri_arg,
390
sieve_argument_validate_error(valdtr, uri_arg,
391
391
"notify command: invalid method '%s'", scheme);
397
397
/* Compose log structure */
398
398
memset(&nenv, 0, sizeof(nenv));
399
nenv.method = method;
399
nenv.method = method;
401
401
/* Check URI itself */
402
402
if ( result && method->def->compile_check_uri != NULL ) {
403
403
/* Set log location to location of URI argument */
404
404
nenv.ehandler = sieve_prefix_ehandler_create
405
(sieve_validator_error_handler(valdtr),
405
(sieve_validator_error_handler(valdtr),
406
406
sieve_error_script_location
407
(sieve_validator_script(valdtr), uri_arg->source_line),
407
(sieve_validator_script(valdtr), uri_arg->source_line),
408
408
"notify command");
410
410
/* Execute method check function */
418
418
/* Set log location to location of :message argument */
419
419
sieve_error_handler_unref(&nenv.ehandler);
420
420
nenv.ehandler = sieve_prefix_ehandler_create
421
(sieve_validator_error_handler(valdtr),
421
(sieve_validator_error_handler(valdtr),
422
422
sieve_error_script_location
423
(sieve_validator_script(valdtr), msg_arg->source_line),
423
(sieve_validator_script(valdtr), msg_arg->source_line),
424
424
"notify command");
426
426
/* Execute method check function */
434
434
/* Set log location to location of :from argument */
435
435
sieve_error_handler_unref(&nenv.ehandler);
436
436
nenv.ehandler = sieve_prefix_ehandler_create
437
(sieve_validator_error_handler(valdtr),
437
(sieve_validator_error_handler(valdtr),
438
438
sieve_error_script_location
439
(sieve_validator_script(valdtr), from_arg->source_line),
439
(sieve_validator_script(valdtr), from_arg->source_line),
440
440
"notify command");
442
442
/* Execute method check function */
447
447
sieve_error_handler_unref(&nenv.ehandler);
449
449
/* Check :options argument */
450
450
if ( result && options_arg != NULL ) {
451
451
struct sieve_ast_argument *option = options_arg;
452
452
struct _ext_enotify_option_check_context optn_context = { valdtr, method };
454
454
/* Parse and check options */
455
455
result = ( sieve_ast_stringlist_map
456
456
(&option, (void *) &optn_context, _ext_enotify_option_check) > 0 );
458
458
/* Discard argument if options are not accepted by method */
459
459
if ( result && method->def->compile_check_option == NULL ) {
460
sieve_argument_validate_warning(valdtr, options_arg,
460
sieve_argument_validate_warning(valdtr, options_arg,
461
461
"notify command: method '%s' accepts no options", scheme);
462
462
(void)sieve_ast_arguments_detach(options_arg,1);
470
470
* Runtime operand checking
473
473
bool ext_enotify_runtime_method_validate
474
474
(const struct sieve_runtime_env *renv, unsigned int source_line,
475
475
string_t *method_uri)
479
479
const char *uri = str_c(method_uri);
480
480
const char *scheme;
481
481
bool result = TRUE;
483
483
/* Get the method */
485
485
if ( (scheme=ext_enotify_uri_scheme_parse(&uri)) == NULL )
488
488
if ( (method=ext_enotify_method_find(this_ext, scheme)) == NULL )
491
491
/* Validate the provided URI */
493
493
if ( method->def != NULL && method->def->runtime_check_uri != NULL ) {
494
struct sieve_enotify_env nenv;
494
struct sieve_enotify_env nenv;
496
496
memset(&nenv, 0, sizeof(nenv));
497
497
nenv.method = method;
498
498
nenv.ehandler = sieve_prefix_ehandler_create
499
(sieve_interpreter_get_error_handler(renv->interp),
500
sieve_error_script_location(renv->script, source_line),
499
(sieve_interpreter_get_error_handler(renv->interp),
500
sieve_error_script_location(renv->script, source_line),
501
501
"valid_notify_method test");
503
503
/* Use the method check function to validate the URI */
517
517
const struct sieve_enotify_method *method;
518
518
const char *uri = str_c(method_uri);
519
519
const char *scheme;
521
521
/* Parse part before ':' of the uri (the scheme) and use it to identify
524
524
if ( (scheme=ext_enotify_uri_scheme_parse(&uri)) == NULL ) {
525
525
sieve_runtime_error
526
526
(renv, sieve_error_script_location(renv->script, source_line),
527
"invalid scheme part for method URI '%s'",
527
"invalid scheme part for method URI '%s'",
528
528
str_sanitize(str_c(method_uri), 80));
532
532
/* Find the notify method */
533
533
if ( (method=ext_enotify_method_find(this_ext, scheme)) == NULL ) {
534
534
sieve_runtime_error
549
549
const struct sieve_enotify_method *method;
550
550
const char *uri_body;
551
551
const char *result = NULL;
554
554
method = ext_enotify_get_method(renv, source_line, method_uri, &uri_body);
555
555
if ( method == NULL ) return NULL;
557
557
/* Get requested capability */
558
if ( method->def != NULL &&
558
if ( method->def != NULL &&
559
559
method->def->runtime_get_method_capability != NULL ) {
560
struct sieve_enotify_env nenv;
560
struct sieve_enotify_env nenv;
562
562
memset(&nenv, 0, sizeof(nenv));
563
563
nenv.method = method;
564
564
nenv.ehandler = sieve_prefix_ehandler_create
565
(sieve_interpreter_get_error_handler(renv->interp),
566
sieve_error_script_location(renv->script, source_line),
565
(sieve_interpreter_get_error_handler(renv->interp),
566
sieve_error_script_location(renv->script, source_line),
567
567
"notify_method_capability test");
569
569
/* Execute method function to acquire capability value */
570
570
result = method->def->runtime_get_method_capability
571
571
(&nenv, str_c(method_uri), uri_body, capability);
579
579
int ext_enotify_runtime_check_operands
580
580
(const struct sieve_runtime_env *renv, unsigned int source_line,
581
string_t *method_uri, string_t *message, string_t *from,
582
struct sieve_coded_stringlist *options,
581
string_t *method_uri, string_t *message, string_t *from,
582
struct sieve_coded_stringlist *options,
583
583
const struct sieve_enotify_method **method_r, void **method_context)
585
585
const struct sieve_enotify_method *method;
586
586
const char *uri_body;
589
589
method = ext_enotify_get_method(renv, source_line, method_uri, &uri_body);
590
590
if ( method == NULL ) return SIEVE_EXEC_FAILURE;
592
592
/* Check provided operands */
593
593
if ( method->def != NULL && method->def->runtime_check_operands != NULL ) {
594
struct sieve_enotify_env nenv;
594
struct sieve_enotify_env nenv;
595
595
int ret = SIEVE_EXEC_OK;
597
597
memset(&nenv, 0, sizeof(nenv));
598
598
nenv.method = method;
599
599
nenv.ehandler = sieve_prefix_ehandler_create
600
(sieve_interpreter_get_error_handler(renv->interp),
601
sieve_error_script_location(renv->script, source_line),
600
(sieve_interpreter_get_error_handler(renv->interp),
601
sieve_error_script_location(renv->script, source_line),
602
602
"notify action");
604
604
/* Execute check function */
605
605
if ( method->def->runtime_check_operands
606
(&nenv, str_c(method_uri), uri_body, message, from,
606
(&nenv, str_c(method_uri), uri_body, message, from,
607
607
sieve_result_pool(renv->result), method_context) ) {
609
609
/* Check any provided options */
610
if ( options != NULL ) {
610
if ( options != NULL ) {
611
611
int result = TRUE;
612
612
string_t *option = NULL;
614
614
/* Iterate through all provided options */
616
(result=sieve_coded_stringlist_next_item(options, &option)) &&
616
(result=sieve_coded_stringlist_next_item(options, &option)) &&
617
617
option != NULL ) {
618
618
const char *opt_name = NULL, *opt_value = NULL;
620
620
/* Parse option into <optionname> and <value> */
621
621
if ( ext_enotify_option_parse
622
622
(&nenv, str_c(option), FALSE, &opt_name, &opt_value) ) {
625
625
if ( method->def->runtime_set_option != NULL ) {
626
626
(void) method->def->runtime_set_option