1
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
6
#include "sieve-common.h"
7
#include "sieve-code.h"
8
#include "sieve-extensions.h"
9
#include "sieve-commands.h"
10
#include "sieve-actions.h"
11
#include "sieve-validator.h"
12
#include "sieve-generator.h"
13
#include "sieve-interpreter.h"
14
#include "sieve-dump.h"
15
#include "sieve-result.h"
17
#include "ext-enotify-common.h"
20
* Forward declarations
23
static const struct sieve_argument notify_importance_tag;
24
static const struct sieve_argument notify_from_tag;
25
static const struct sieve_argument notify_options_tag;
26
static const struct sieve_argument notify_message_tag;
32
* notify [":from" string]
33
* [":importance" <"1" / "2" / "3">]
34
* [":options" string-list]
39
static bool cmd_notify_registered
40
(struct sieve_validator *valdtr,
41
struct sieve_command_registration *cmd_reg);
42
static bool cmd_notify_pre_validate
43
(struct sieve_validator *validator, struct sieve_command_context *cmd);
44
static bool cmd_notify_validate
45
(struct sieve_validator *valdtr, struct sieve_command_context *cmd);
46
static bool cmd_notify_generate
47
(const struct sieve_codegen_env *cgenv, struct sieve_command_context *ctx);
49
const struct sieve_command notify_command = {
53
cmd_notify_registered,
54
cmd_notify_pre_validate,
64
/* Forward declarations */
66
static bool cmd_notify_validate_string_tag
67
(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
68
struct sieve_command_context *cmd);
69
static bool cmd_notify_validate_stringlist_tag
70
(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
71
struct sieve_command_context *cmd);
72
static bool cmd_notify_validate_importance_tag
73
(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
74
struct sieve_command_context *cmd);
76
/* Argument objects */
78
static const struct sieve_argument notify_from_tag = {
81
cmd_notify_validate_string_tag,
85
static const struct sieve_argument notify_options_tag = {
88
cmd_notify_validate_stringlist_tag,
92
static const struct sieve_argument notify_message_tag = {
95
cmd_notify_validate_string_tag,
99
static const struct sieve_argument notify_importance_tag = {
102
cmd_notify_validate_importance_tag,
110
static bool cmd_notify_operation_dump
111
(const struct sieve_operation *op,
112
const struct sieve_dumptime_env *denv, sieve_size_t *address);
113
static int cmd_notify_operation_execute
114
(const struct sieve_operation *op,
115
const struct sieve_runtime_env *renv, sieve_size_t *address);
117
const struct sieve_operation notify_operation = {
120
EXT_ENOTIFY_OPERATION_NOTIFY,
121
cmd_notify_operation_dump,
122
cmd_notify_operation_execute
129
/* Forward declarations */
131
static int act_notify_check_duplicate
132
(const struct sieve_runtime_env *renv,
133
const struct sieve_action_data *act,
134
const struct sieve_action_data *act_other);
135
static void act_notify_print
136
(const struct sieve_action *action, const struct sieve_result_print_env *rpenv,
137
void *context, bool *keep);
138
static bool act_notify_commit
139
(const struct sieve_action *action, const struct sieve_action_exec_env *aenv,
140
void *tr_context, bool *keep);
144
const struct sieve_action act_notify = {
148
act_notify_check_duplicate,
157
* Command validation context
160
struct cmd_notify_context_data {
161
struct sieve_ast_argument *from;
162
struct sieve_ast_argument *message;
163
struct sieve_ast_argument *options;
170
static bool cmd_notify_validate_string_tag
171
(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
172
struct sieve_command_context *cmd)
174
struct sieve_ast_argument *tag = *arg;
175
struct cmd_notify_context_data *ctx_data =
176
(struct cmd_notify_context_data *) cmd->data;
178
/* Detach the tag itself */
179
*arg = sieve_ast_arguments_detach(*arg,1);
185
if ( !sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, SAAT_STRING) )
188
if ( tag->argument == ¬ify_from_tag ) {
189
ctx_data->from = *arg;
192
*arg = sieve_ast_argument_next(*arg);
194
} else if ( tag->argument == ¬ify_message_tag ) {
195
ctx_data->message = *arg;
198
*arg = sieve_ast_argument_next(*arg);
204
static bool cmd_notify_validate_stringlist_tag
205
(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
206
struct sieve_command_context *cmd)
208
struct sieve_ast_argument *tag = *arg;
209
struct cmd_notify_context_data *ctx_data =
210
(struct cmd_notify_context_data *) cmd->data;
212
/* Detach the tag itself */
213
*arg = sieve_ast_arguments_detach(*arg,1);
216
* :options string-list
218
if ( !sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, SAAT_STRING_LIST) )
222
ctx_data->options = *arg;
225
*arg = sieve_ast_argument_next(*arg);
230
static bool cmd_notify_validate_importance_tag
231
(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
232
struct sieve_command_context *cmd ATTR_UNUSED)
234
const struct sieve_ast_argument *tag = *arg;
237
/* Detach the tag itself */
238
*arg = sieve_ast_arguments_detach(*arg,1);
241
* :importance <"1" / "2" / "3">
244
if ( sieve_ast_argument_type(*arg) != SAAT_STRING ) {
246
sieve_argument_validate_error(valdtr, *arg,
247
"the :importance tag for the notify command requires a string parameter, "
248
"but %s was found", sieve_ast_argument_name(*arg));
252
impstr = sieve_ast_argument_strc(*arg);
254
if ( impstr[0] < '1' || impstr[0] > '3' || impstr[1] != '\0' ) {
255
/* Invalid importance */
256
sieve_argument_validate_error(valdtr, *arg,
257
"invalid :importance value for notify command: %s", impstr);
261
sieve_ast_argument_number_substitute(*arg, impstr[0] - '0');
262
(*arg)->arg_id_code = tag->arg_id_code;
263
(*arg)->argument = &number_argument;
266
*arg = sieve_ast_argument_next(*arg);
273
* Command registration
276
static bool cmd_notify_registered
277
(struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg)
279
sieve_validator_register_tag
280
(valdtr, cmd_reg, ¬ify_importance_tag, CMD_NOTIFY_OPT_IMPORTANCE);
281
sieve_validator_register_tag
282
(valdtr, cmd_reg, ¬ify_from_tag, CMD_NOTIFY_OPT_FROM);
283
sieve_validator_register_tag
284
(valdtr, cmd_reg, ¬ify_options_tag, CMD_NOTIFY_OPT_OPTIONS);
285
sieve_validator_register_tag
286
(valdtr, cmd_reg, ¬ify_message_tag, CMD_NOTIFY_OPT_MESSAGE);
295
static bool cmd_notify_pre_validate
296
(struct sieve_validator *validator ATTR_UNUSED,
297
struct sieve_command_context *cmd)
299
struct cmd_notify_context_data *ctx_data;
302
ctx_data = p_new(sieve_command_pool(cmd),
303
struct cmd_notify_context_data, 1);
304
cmd->data = ctx_data;
309
static bool cmd_notify_validate
310
(struct sieve_validator *valdtr, struct sieve_command_context *cmd)
312
struct sieve_ast_argument *arg = cmd->first_positional;
313
struct cmd_notify_context_data *ctx_data =
314
(struct cmd_notify_context_data *) cmd->data;
316
if ( !sieve_validate_positional_argument
317
(valdtr, cmd, arg, "method", 1, SAAT_STRING) ) {
321
if ( !sieve_validator_argument_activate(valdtr, cmd, arg, FALSE) )
324
return ext_enotify_compile_check_arguments
325
(valdtr, arg, ctx_data->message, ctx_data->from, ctx_data->options);
332
static bool cmd_notify_generate
333
(const struct sieve_codegen_env *cgenv, struct sieve_command_context *ctx)
335
sieve_operation_emit_code(cgenv->sbin, ¬ify_operation);
337
/* Emit source line */
338
sieve_code_source_line_emit(cgenv->sbin, sieve_command_source_line(ctx));
340
/* Generate arguments */
341
return sieve_generate_arguments(cgenv, ctx, NULL);
348
static bool cmd_notify_operation_dump
349
(const struct sieve_operation *op ATTR_UNUSED,
350
const struct sieve_dumptime_env *denv, sieve_size_t *address)
354
sieve_code_dumpf(denv, "NOTIFY");
355
sieve_code_descend(denv);
358
if ( !sieve_code_source_line_dump(denv, address) )
361
/* Dump optional operands */
362
if ( sieve_operand_optional_present(denv->sbin, address) ) {
363
while ( opt_code != 0 ) {
364
sieve_code_mark(denv);
366
if ( !sieve_operand_optional_read(denv->sbin, address, &opt_code) )
369
switch ( opt_code ) {
372
case CMD_NOTIFY_OPT_IMPORTANCE:
373
if ( !sieve_opr_number_dump(denv, address, "importance") )
376
case CMD_NOTIFY_OPT_FROM:
377
if ( !sieve_opr_string_dump(denv, address, "from") )
380
case CMD_NOTIFY_OPT_OPTIONS:
381
if ( !sieve_opr_stringlist_dump(denv, address, "options") )
384
case CMD_NOTIFY_OPT_MESSAGE:
385
if ( !sieve_opr_string_dump(denv, address, "message") )
394
/* Dump reason and handle operands */
396
sieve_opr_string_dump(denv, address, "method");
403
static int cmd_notify_operation_execute
404
(const struct sieve_operation *op ATTR_UNUSED,
405
const struct sieve_runtime_env *renv, sieve_size_t *address)
407
struct sieve_side_effects_list *slist = NULL;
408
struct sieve_enotify_action *act;
409
void *method_context;
411
int opt_code = 1, result = SIEVE_EXEC_OK;
412
sieve_number_t importance = 1;
413
struct sieve_coded_stringlist *options = NULL;
414
const struct sieve_enotify_method *method;
415
string_t *method_uri, *message = NULL, *from = NULL;
416
unsigned int source_line;
423
if ( !sieve_code_source_line_read(renv, address, &source_line) ) {
424
sieve_runtime_trace_error(renv, "invalid source line");
425
return SIEVE_EXEC_BIN_CORRUPT;
428
/* Optional operands */
429
if ( sieve_operand_optional_present(renv->sbin, address) ) {
430
while ( opt_code != 0 ) {
431
if ( !sieve_operand_optional_read(renv->sbin, address, &opt_code) ) {
432
sieve_runtime_trace_error(renv, "invalid optional operand");
433
return SIEVE_EXEC_BIN_CORRUPT;
436
switch ( opt_code ) {
439
case CMD_NOTIFY_OPT_IMPORTANCE:
440
if ( !sieve_opr_number_read(renv, address, &importance) ) {
441
sieve_runtime_trace_error(renv, "invalid importance operand");
442
return SIEVE_EXEC_BIN_CORRUPT;
445
/* Enforce 0 < importance < 4 (just to be sure) */
446
if ( importance < 1 )
448
else if ( importance > 3 )
451
case CMD_NOTIFY_OPT_FROM:
452
if ( !sieve_opr_string_read(renv, address, &from) ) {
453
sieve_runtime_trace_error(renv, "invalid from operand");
454
return SIEVE_EXEC_BIN_CORRUPT;
457
case CMD_NOTIFY_OPT_MESSAGE:
458
if ( !sieve_opr_string_read(renv, address, &message) ) {
459
sieve_runtime_trace_error(renv, "invalid from operand");
460
return SIEVE_EXEC_BIN_CORRUPT;
463
case CMD_NOTIFY_OPT_OPTIONS:
464
if ( (options=sieve_opr_stringlist_read(renv, address)) == NULL ) {
465
sieve_runtime_trace_error(renv, "invalid options operand");
466
return SIEVE_EXEC_BIN_CORRUPT;
470
sieve_runtime_trace_error(renv, "unknown optional operand: %d",
472
return SIEVE_EXEC_BIN_CORRUPT;
478
if ( !sieve_opr_string_read(renv, address, &method_uri) ) {
479
sieve_runtime_trace_error(renv, "invalid method operand");
480
return SIEVE_EXEC_BIN_CORRUPT;
487
sieve_runtime_trace(renv, "NOTIFY action");
491
if ( (result=ext_enotify_runtime_check_operands
492
(renv, source_line, method_uri, message, from, options, &method,
495
/* Add notify action to the result */
497
pool = sieve_result_pool(renv->result);
498
act = p_new(pool, struct sieve_enotify_action, 1);
499
act->method = method;
500
act->method_context = method_context;
501
act->importance = importance;
502
if ( message != NULL )
503
act->message = p_strdup(pool, str_c(message));
505
act->from = p_strdup(pool, str_c(from));
507
return ( sieve_result_add_action
508
(renv, &act_notify, slist, source_line, (void *) act, 0) >= 0 );
518
/* Runtime verification */
520
static int act_notify_check_duplicate
521
(const struct sieve_runtime_env *renv ATTR_UNUSED,
522
const struct sieve_action_data *act ATTR_UNUSED,
523
const struct sieve_action_data *act_other ATTR_UNUSED)
525
const struct sieve_enotify_action *nact1, *nact2;
526
struct sieve_enotify_log nlog;
528
if ( act->context == NULL || act_other->context == NULL )
531
nact1 = (const struct sieve_enotify_action *) act->context;
532
nact2 = (const struct sieve_enotify_action *) act_other->context;
534
if ( nact1->method == NULL || nact1->method->action_check_duplicates == NULL )
537
memset(&nlog, 0, sizeof(nlog));
538
nlog.location = act->location;
539
nlog.ehandler = sieve_result_get_error_handler(renv->result);
541
return nact1->method->action_check_duplicates
542
(&nlog, nact1->method_context, nact2->method_context, act_other->location);
545
/* Result printing */
547
static void act_notify_print
548
(const struct sieve_action *action ATTR_UNUSED,
549
const struct sieve_result_print_env *rpenv, void *context,
550
bool *keep ATTR_UNUSED)
552
const struct sieve_enotify_action *act =
553
(const struct sieve_enotify_action *) context;
555
sieve_result_action_printf
556
( rpenv, "send notification with method '%s:':", act->method->identifier);
558
if ( act->method->action_print != NULL ) {
559
struct sieve_enotify_print_env penv;
561
memset(&penv, 0, sizeof(penv));
562
penv.result_penv = rpenv;
564
act->method->action_print(&penv, act);
568
/* Result execution */
570
static bool act_notify_commit
571
(const struct sieve_action *action ATTR_UNUSED,
572
const struct sieve_action_exec_env *aenv, void *tr_context,
573
bool *keep ATTR_UNUSED)
575
const struct sieve_enotify_action *act =
576
(const struct sieve_enotify_action *) tr_context;
577
struct sieve_enotify_exec_env nenv;
578
struct sieve_enotify_log nlog;
580
memset(&nlog, 0, sizeof(nlog));
581
nlog.location = sieve_action_get_location(aenv);
582
nlog.ehandler = sieve_result_get_error_handler(aenv->result);
584
nenv.scriptenv = aenv->scriptenv;
585
nenv.msgdata = aenv->msgdata;
586
nenv.msgctx = aenv->msgctx;
587
nenv.notify_log = &nlog;
589
if ( act->method->action_execute != NULL )
590
return act->method->action_execute(&nenv, act);