45
45
static bool cmd_notify_validate
46
46
(struct sieve_validator *valdtr, struct sieve_command *cmd);
47
47
static bool cmd_notify_generate
48
(const struct sieve_codegen_env *cgenv,
48
(const struct sieve_codegen_env *cgenv,
49
49
struct sieve_command *ctx);
51
51
const struct sieve_command_def cmd_notify_old = {
69
69
(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
70
70
struct sieve_command *cmd);
71
71
static bool cmd_notify_validate_stringlist_tag
72
(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
72
(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
73
73
struct sieve_command *cmd);
75
75
/* Argument objects */
111
111
static int cmd_notify_operation_execute
112
112
(const struct sieve_runtime_env *renv, sieve_size_t *address);
114
const struct sieve_operation_def notify_old_operation = {
114
const struct sieve_operation_def notify_old_operation = {
116
116
¬ify_extension,
117
117
EXT_NOTIFY_OPERATION_NOTIFY,
118
cmd_notify_operation_dump,
118
cmd_notify_operation_dump,
119
119
cmd_notify_operation_execute
136
136
/* Forward declarations */
138
138
static int act_notify_check_duplicate
139
(const struct sieve_runtime_env *renv,
139
(const struct sieve_runtime_env *renv,
140
140
const struct sieve_action *act,
141
141
const struct sieve_action *act_other);
142
142
static void act_notify_print
143
143
(const struct sieve_action *action, const struct sieve_result_print_env *rpenv,
145
145
static bool act_notify_commit
146
(const struct sieve_action *action, const struct sieve_action_exec_env *aenv,
146
(const struct sieve_action *action, const struct sieve_action_exec_env *aenv,
147
147
void *tr_context, bool *keep);
149
149
/* Action object */
220
220
static bool cmd_notify_validate_stringlist_tag
221
(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
221
(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
222
222
struct sieve_command *cmd)
224
224
struct sieve_ast_argument *tag = *arg;
225
struct cmd_notify_context_data *ctx_data =
226
(struct cmd_notify_context_data *) cmd->data;
225
struct cmd_notify_context_data *ctx_data =
226
(struct cmd_notify_context_data *) cmd->data;
228
228
/* Detach the tag itself */
229
229
*arg = sieve_ast_arguments_detach(*arg,1);
232
232
* :options string-list
234
234
if ( !sieve_validate_tag_parameter
235
(valdtr, cmd, tag, *arg, NULL, 0, SAAT_STRING_LIST, FALSE) )
235
(valdtr, cmd, tag, *arg, NULL, 0, SAAT_STRING_LIST, FALSE) )
238
238
/* Assign context */
239
ctx_data->options = *arg;
239
ctx_data->options = *arg;
241
241
/* Skip parameter */
242
242
*arg = sieve_ast_argument_next(*arg);
319
319
/* Check :method argument */
320
320
if ( ctx_data->method != NULL ) {
321
321
const char *method = sieve_ast_argument_strc(ctx_data->method);
323
323
if ( strcasecmp(method, "mailto") != 0 ) {
324
324
sieve_command_validate_error(valdtr, cmd,
325
325
"the notify command of the deprecated notify extension "
361
361
return sieve_generate_arguments(cgenv, cmd, NULL);
368
368
static bool cmd_notify_operation_dump
369
369
(const struct sieve_dumptime_env *denv, sieve_size_t *address)
371
371
int opt_code = 1;
373
373
sieve_code_dumpf(denv, "NOTIFY");
374
sieve_code_descend(denv);
374
sieve_code_descend(denv);
376
376
/* Source line */
377
377
if ( !sieve_code_source_line_dump(denv, address) )
421
421
static int cmd_notify_operation_execute
422
422
(const struct sieve_runtime_env *renv, sieve_size_t *address)
424
424
const struct sieve_extension *this_ext = renv->oprtn.ext;
425
425
struct ext_notify_action *act;
427
427
int opt_code = 1;
428
428
sieve_number_t importance = 1;
429
429
struct sieve_coded_stringlist *options = NULL;
430
string_t *message = NULL, *id = NULL;
430
string_t *message = NULL, *id = NULL;
431
431
unsigned int source_line;
437
437
/* Source line */
438
438
if ( !sieve_code_source_line_read(renv, address, &source_line) ) {
439
439
sieve_runtime_trace_error(renv, "invalid source line");
440
440
return SIEVE_EXEC_BIN_CORRUPT;
443
/* Optional operands */
443
/* Optional operands */
444
444
if ( sieve_operand_optional_present(renv->sbin, address) ) {
445
445
while ( opt_code != 0 ) {
446
446
if ( !sieve_operand_optional_read(renv->sbin, address, &opt_code) ) {
485
sieve_runtime_trace_error(renv, "unknown optional operand: %d",
485
sieve_runtime_trace_error(renv, "unknown optional operand: %d",
487
487
return SIEVE_EXEC_BIN_CORRUPT;
493
493
* Perform operation
496
sieve_runtime_trace(renv, "NOTIFY action");
496
sieve_runtime_trace(renv, "NOTIFY action");
498
498
/* Compose action */
499
499
if ( options != NULL ) {
500
500
string_t *raw_address;
501
501
string_t *out_message;
504
504
pool = sieve_result_pool(renv->result);
505
505
act = p_new(pool, struct ext_notify_action, 1);
506
506
if ( id != NULL )
507
507
act->id = p_strdup(pool, str_c(id));
508
act->importance = importance;
508
act->importance = importance;
510
510
/* Process message */
512
512
out_message = t_str_new(1024);
513
513
ext_notify_construct_message
514
514
(renv, (message == NULL ? NULL : str_c(message)), out_message);
515
515
act->message = p_strdup(pool, str_c(out_message));
517
/* Normalize and verify all :options addresses */
517
/* Normalize and verify all :options addresses */
519
519
sieve_coded_stringlist_reset(options);
521
521
p_array_init(&act->recipients, pool, 4);
523
523
raw_address = NULL;
524
524
while ( (result=sieve_coded_stringlist_next_item(options, &raw_address))
525
525
&& raw_address != NULL ) {
526
526
const char *error = NULL;
527
527
const char *addr_norm = sieve_address_normalize(raw_address, &error);
529
529
/* Add if valid address */
530
530
if ( addr_norm != NULL ) {
531
531
const struct ext_notify_recipient *rcpts;
534
534
/* Prevent duplicates */
535
535
rcpts = array_get(&act->recipients, &rcpt_count);
537
537
for ( i = 0; i < rcpt_count; i++ ) {
538
538
if ( sieve_address_compare
539
539
(rcpts[i].normalized, addr_norm, TRUE) == 0 )
543
543
/* Add only if unique */
544
544
if ( i != rcpt_count ) {
545
sieve_runtime_warning(renv,
545
sieve_runtime_warning(renv,
546
546
sieve_error_script_location(renv->script, source_line),
547
547
"duplicate recipient '%s' specified in the :options argument of "
548
"the deprecated notify command",
548
"the deprecated notify command",
549
549
str_sanitize(str_c(raw_address), 128));
552
552
( array_count(&act->recipients) >= EXT_NOTIFY_MAX_RECIPIENTS ) {
553
sieve_runtime_warning(renv,
553
sieve_runtime_warning(renv,
554
554
sieve_error_script_location(renv->script, source_line),
555
555
"more than the maximum %u recipients are specified "
556
556
"for the deprecated notify command; "
557
557
"the rest is discarded", EXT_NOTIFY_MAX_RECIPIENTS);
561
struct ext_notify_recipient recipient;
561
struct ext_notify_recipient recipient;
563
563
recipient.full = p_strdup(pool, str_c(raw_address));
564
564
recipient.normalized = p_strdup(pool, addr_norm);
566
566
array_append(&act->recipients, &recipient, 1);
569
sieve_runtime_error(renv,
569
sieve_runtime_error(renv,
570
570
sieve_error_script_location(renv->script, source_line),
571
571
"specified :options address '%s' is invalid for "
572
"the deprecated notify command: %s",
572
"the deprecated notify command: %s",
573
573
str_sanitize(str_c(raw_address), 128), error);
574
574
return SIEVE_EXEC_FAILURE;
579
579
sieve_runtime_trace_error(renv, "invalid options stringlist");
580
580
return SIEVE_EXEC_BIN_CORRUPT;
583
583
return ( sieve_result_add_action
584
(renv, this_ext, &act_notify_old, NULL, source_line, (void *) act, 0)
584
(renv, this_ext, &act_notify_old, NULL, source_line, (void *) act, 0)
595
595
/* Runtime verification */
597
597
static int act_notify_check_duplicate
598
(const struct sieve_runtime_env *renv ATTR_UNUSED,
598
(const struct sieve_runtime_env *renv ATTR_UNUSED,
599
599
const struct sieve_action *act ATTR_UNUSED,
600
600
const struct sieve_action *act_other ATTR_UNUSED)
644
644
/* Perform pending deletion */
645
645
if ( del_len > 0 ) {
646
array_delete(&new_nact->recipients, del_start, del_len);
646
array_delete(&new_nact->recipients, del_start, del_len);
649
649
return ( array_count(&new_nact->recipients) > 0 ? 0 : 1 );
652
652
/* Result printing */
654
654
static void act_notify_print
655
(const struct sieve_action *action, const struct sieve_result_print_env *rpenv,
656
bool *keep ATTR_UNUSED)
655
(const struct sieve_action *action, const struct sieve_result_print_env *rpenv,
656
bool *keep ATTR_UNUSED)
658
const struct ext_notify_action *act =
658
const struct ext_notify_action *act =
659
659
(const struct ext_notify_action *) action->context;
660
660
const struct ext_notify_recipient *recipients;
661
661
unsigned int count, i;
663
663
sieve_result_action_printf
664
664
( rpenv, "send (depricated) notification with method 'mailto':");
666
666
/* Print main method parameters */
668
668
sieve_result_printf
712
712
static bool act_notify_send
713
(const struct sieve_action_exec_env *aenv,
713
(const struct sieve_action_exec_env *aenv,
714
714
const struct ext_notify_action *act)
716
716
const struct sieve_message_data *msgdata = aenv->msgdata;
717
717
const struct sieve_script_env *senv = aenv->scriptenv;
718
718
const struct ext_notify_recipient *recipients;
724
724
/* Get recipients */
725
725
recipients = array_get(&act->recipients, &count);
726
726
if ( count == 0 ) {
727
sieve_result_warning(aenv,
727
sieve_result_warning(aenv,
728
728
"notify action specifies no recipients; action has no effect");
732
732
/* Just to be sure */
733
733
if ( senv->smtp_open == NULL || senv->smtp_close == NULL ) {
734
sieve_result_warning(aenv,
734
sieve_result_warning(aenv,
735
735
"notify action has no means to send mail");
739
739
/* Send message to all recipients */
740
740
for ( i = 0; i < count; i++ ) {
742
742
if ( msgdata->return_path != NULL )
743
smtp_handle = senv->smtp_open(recipients[i].normalized,
743
smtp_handle = senv->smtp_open(recipients[i].normalized,
744
744
senv->postmaster_address, &f);
746
746
smtp_handle = senv->smtp_open(recipients[i].normalized, NULL, &f);
748
748
outmsgid = sieve_message_get_new_id(senv);
750
750
rfc2822_header_field_write(f, "X-Sieve", SIEVE_IMPLEMENTATION);
751
751
rfc2822_header_field_write(f, "Message-ID", outmsgid);
752
752
rfc2822_header_field_write(f, "Date", message_date_create(ioloop_time));
771
rfc2822_header_field_printf(f, "From", "%s",
771
rfc2822_header_field_printf(f, "From", "%s",
772
772
t_strdup_printf("Postmaster <%s>", senv->postmaster_address));
774
774
rfc2822_header_field_printf(f, "To", "%s", recipients[i].full);
781
781
if (contains_8bit(act->message)) {
782
782
rfc2822_header_field_write(f, "MIME-Version", "1.0");
783
rfc2822_header_field_write(f,
783
rfc2822_header_field_write(f,
784
784
"Content-Type", "text/plain; charset=UTF-8");
785
785
rfc2822_header_field_write(f, "Content-Transfer-Encoding", "8bit");
788
788
/* Generate message body */
789
789
fprintf(f, "\r\n");
790
790
fprintf(f, "%s\r\n", act->message);
792
792
if ( senv->smtp_close(smtp_handle) ) {
793
sieve_result_log(aenv,
794
"sent mail notification to <%s>",
793
sieve_result_log(aenv,
794
"sent mail notification to <%s>",
795
795
str_sanitize(recipients[i].normalized, 80));
797
797
sieve_result_error(aenv,
798
798
"failed to send mail notification to <%s> "
799
"(refer to system log for more information)",
799
"(refer to system log for more information)",
800
800
str_sanitize(recipients[i].normalized, 80));
807
807
static bool act_notify_commit
808
(const struct sieve_action *action, const struct sieve_action_exec_env *aenv,
808
(const struct sieve_action *action, const struct sieve_action_exec_env *aenv,
809
809
void *tr_context ATTR_UNUSED, bool *keep ATTR_UNUSED)
811
const struct ext_notify_action *act =
811
const struct ext_notify_action *act =
812
812
(const struct ext_notify_action *) action->context;
813
813
const struct sieve_message_data *msgdata = aenv->msgdata;
814
814
const char *const *headers;
821
821
/* Theoretically multiple headers could exist, so lets make sure */
822
822
while ( *hdsp != NULL ) {
823
823
if ( strcasecmp(*hdsp, "no") != 0 ) {
824
sieve_result_log(aenv,
825
"not sending notification for auto-submitted message from <%s>",
826
str_sanitize(msgdata->return_path, 128));
824
sieve_result_log(aenv,
825
"not sending notification for auto-submitted message from <%s>",
826
str_sanitize(msgdata->return_path, 128));