1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2 */
3
4 #include "lib.h"
5 #include "mempool.h"
6 #include "ostream.h"
7 #include "hash.h"
8 #include "str.h"
9 #include "llist.h"
10 #include "strfuncs.h"
11 #include "str-sanitize.h"
12 #include "var-expand.h"
13 #include "message-address.h"
14 #include "mail-storage.h"
15
16 #include "sieve-common.h"
17 #include "sieve-limits.h"
18 #include "sieve-script.h"
19 #include "sieve-error.h"
20 #include "sieve-interpreter.h"
21 #include "sieve-actions.h"
22 #include "sieve-message.h"
23
24 #include "sieve-result.h"
25
26 #include <stdio.h>
27
28 struct event_category event_category_sieve_action = {
29 .parent = &event_category_sieve,
30 .name = "sieve-action",
31 };
32
33 /*
34 * Types
35 */
36
37 enum sieve_action_execution_state {
38 SIEVE_ACTION_EXECUTION_STATE_INIT = 0,
39 SIEVE_ACTION_EXECUTION_STATE_STARTED,
40 SIEVE_ACTION_EXECUTION_STATE_EXECUTED,
41 SIEVE_ACTION_EXECUTION_STATE_FINALIZED,
42 };
43
44 struct sieve_result_action {
45 struct sieve_action action;
46
47 struct sieve_side_effects_list *seffects;
48
49 struct sieve_result_action *prev, *next;
50 };
51
52 struct sieve_side_effects_list {
53 struct sieve_result *result;
54
55 struct sieve_result_side_effect *first_effect;
56 struct sieve_result_side_effect *last_effect;
57 };
58
59 struct sieve_result_side_effect {
60 struct sieve_side_effect seffect;
61
62 struct sieve_result_side_effect *prev, *next;
63 };
64
65 struct sieve_result_action_context {
66 const struct sieve_action_def *action;
67 struct sieve_side_effects_list *seffects;
68 };
69
70 /*
71 * Result object
72 */
73
74 struct sieve_result {
75 pool_t pool;
76 int refcount;
77
78 struct sieve_instance *svinst;
79 struct event *event;
80
81 /* Context data for extensions */
82 ARRAY(void *) ext_contexts;
83
84 const struct sieve_execute_env *exec_env;
85 struct sieve_error_handler *ehandler;
86 struct sieve_message_context *msgctx;
87
88 unsigned int exec_seq;
89 struct sieve_result_execution *exec;
90
91 struct sieve_action keep_action;
92 struct sieve_action failure_action;
93
94 unsigned int action_count;
95 struct sieve_result_action *actions_head, *actions_tail;
96
97 HASH_TABLE(const struct sieve_action_def *,
98 struct sieve_result_action_context *) action_contexts;
99 };
100
101 static const char *
sieve_result_event_log_message(struct sieve_result * result,enum log_type log_type,const char * message)102 sieve_result_event_log_message(struct sieve_result *result,
103 enum log_type log_type, const char *message)
104 {
105 const struct sieve_script_env *senv = result->exec_env->scriptenv;
106
107 i_assert(senv->result_amend_log_message != NULL);
108 return senv->result_amend_log_message(senv, log_type, message);
109 }
110
111 struct sieve_result *
sieve_result_create(struct sieve_instance * svinst,pool_t pool,const struct sieve_execute_env * eenv)112 sieve_result_create(struct sieve_instance *svinst, pool_t pool,
113 const struct sieve_execute_env *eenv)
114 {
115 const struct sieve_script_env *senv = eenv->scriptenv;
116 const struct sieve_message_data *msgdata = eenv->msgdata;
117 struct sieve_result *result;
118
119 pool_ref(pool);
120
121 result = p_new(pool, struct sieve_result, 1);
122 result->refcount = 1;
123 result->pool = pool;
124 result->svinst = svinst;
125
126 result->event = event_create(eenv->event);
127 event_add_category(result->event, &event_category_sieve_action);
128 if (senv->result_amend_log_message != NULL) {
129 event_set_log_message_callback(
130 result->event, sieve_result_event_log_message, result);
131 }
132
133 p_array_init(&result->ext_contexts, pool, 4);
134
135 result->exec_env = eenv;
136 result->msgctx =
137 sieve_message_context_create(svinst, senv->user, msgdata);
138
139 result->keep_action.def = &act_store;
140 result->keep_action.ext = NULL;
141 result->failure_action.def = &act_store;
142 result->failure_action.ext = NULL;
143
144 result->action_count = 0;
145 result->actions_head = NULL;
146 result->actions_tail = NULL;
147
148 return result;
149 }
150
sieve_result_ref(struct sieve_result * result)151 void sieve_result_ref(struct sieve_result *result)
152 {
153 result->refcount++;
154 }
155
156 static void
sieve_result_action_deinit(struct sieve_result_action * ract)157 sieve_result_action_deinit(struct sieve_result_action *ract)
158 {
159 event_unref(&ract->action.event);
160 }
161
sieve_result_unref(struct sieve_result ** _result)162 void sieve_result_unref(struct sieve_result **_result)
163 {
164 struct sieve_result *result = *_result;
165 struct sieve_result_action *ract;
166
167 i_assert(result->refcount > 0);
168
169 if (--result->refcount != 0)
170 return;
171
172 sieve_message_context_unref(&result->msgctx);
173
174 hash_table_destroy(&result->action_contexts);
175
176 ract = result->actions_head;
177 while (ract != NULL) {
178 sieve_result_action_deinit(ract);
179 ract = ract->next;
180 }
181 event_unref(&result->event);
182
183 pool_unref(&result->pool);
184 *_result = NULL;
185 }
186
sieve_result_pool(struct sieve_result * result)187 pool_t sieve_result_pool(struct sieve_result *result)
188 {
189 return result->pool;
190 }
191
192 /*
193 * Getters/Setters
194 */
195
196 const struct sieve_script_env *
sieve_result_get_script_env(struct sieve_result * result)197 sieve_result_get_script_env(struct sieve_result *result)
198 {
199 return result->exec_env->scriptenv;
200 }
201
202 const struct sieve_message_data *
sieve_result_get_message_data(struct sieve_result * result)203 sieve_result_get_message_data(struct sieve_result *result)
204 {
205 return result->exec_env->msgdata;
206 }
207
208 struct sieve_message_context *
sieve_result_get_message_context(struct sieve_result * result)209 sieve_result_get_message_context(struct sieve_result *result)
210 {
211 return result->msgctx;
212 }
213
sieve_result_get_exec_seq(struct sieve_result * result)214 unsigned int sieve_result_get_exec_seq(struct sieve_result *result)
215 {
216 return result->exec_seq;
217 }
218
219 /*
220 * Extension support
221 */
222
sieve_result_extension_set_context(struct sieve_result * result,const struct sieve_extension * ext,void * context)223 void sieve_result_extension_set_context(struct sieve_result *result,
224 const struct sieve_extension *ext,
225 void *context)
226 {
227 if (ext->id < 0)
228 return;
229
230 array_idx_set(&result->ext_contexts, (unsigned int) ext->id, &context);
231 }
232
233 const void *
sieve_result_extension_get_context(struct sieve_result * result,const struct sieve_extension * ext)234 sieve_result_extension_get_context(struct sieve_result *result,
235 const struct sieve_extension *ext)
236 {
237 void * const *ctx;
238
239 if (ext->id < 0 || ext->id >= (int) array_count(&result->ext_contexts))
240 return NULL;
241
242 ctx = array_idx(&result->ext_contexts, (unsigned int) ext->id);
243
244 return *ctx;
245 }
246
247 /*
248 * Result composition
249 */
250
251 static void
sieve_result_init_action_event(struct sieve_result * result,struct sieve_action * action,bool add_prefix)252 sieve_result_init_action_event(struct sieve_result *result,
253 struct sieve_action *action, bool add_prefix)
254 {
255 const char *name = sieve_action_name(action);
256
257 if (action->event != NULL)
258 return;
259
260 action->event = event_create(result->event);
261 if (add_prefix && name != NULL) {
262 event_set_append_log_prefix(
263 action->event, t_strconcat(name, " action: ", NULL));
264 }
265 event_add_str(action->event, "action_name", name);
266 event_add_str(action->event, "script_location", action->location);
267 }
268
sieve_result_add_implicit_side_effect(struct sieve_result * result,const struct sieve_action_def * to_action,bool to_keep,const struct sieve_extension * ext,const struct sieve_side_effect_def * seff_def,void * context)269 void sieve_result_add_implicit_side_effect(
270 struct sieve_result *result, const struct sieve_action_def *to_action,
271 bool to_keep, const struct sieve_extension *ext,
272 const struct sieve_side_effect_def *seff_def, void *context)
273 {
274 struct sieve_result_action_context *actctx = NULL;
275 struct sieve_side_effect seffect;
276
277 to_action = to_keep ? &act_store : to_action;
278
279 if (!hash_table_is_created(result->action_contexts)) {
280 hash_table_create_direct(&result->action_contexts,
281 result->pool, 0);
282 } else {
283 actctx = hash_table_lookup(result->action_contexts, to_action);
284 }
285
286 if (actctx == NULL) {
287 actctx = p_new(result->pool,
288 struct sieve_result_action_context, 1);
289 actctx->action = to_action;
290 actctx->seffects = sieve_side_effects_list_create(result);
291
292 hash_table_insert(result->action_contexts, to_action, actctx);
293 }
294
295 seffect.object.def = &seff_def->obj_def;
296 seffect.object.ext = ext;
297 seffect.def = seff_def;
298 seffect.context = context;
299
300 sieve_side_effects_list_add(actctx->seffects, &seffect);
301 }
302
303 static int
sieve_result_side_effects_merge(const struct sieve_runtime_env * renv,const struct sieve_action * action,struct sieve_result_action * old_action,struct sieve_side_effects_list * new_seffects)304 sieve_result_side_effects_merge(const struct sieve_runtime_env *renv,
305 const struct sieve_action *action,
306 struct sieve_result_action *old_action,
307 struct sieve_side_effects_list *new_seffects)
308 {
309 struct sieve_side_effects_list *old_seffects = old_action->seffects;
310 int ret;
311 struct sieve_result_side_effect *rsef, *nrsef;
312
313 /* Allow side-effects to merge with existing copy */
314
315 /* Merge existing side effects */
316 rsef = old_seffects != NULL ? old_seffects->first_effect : NULL;
317 while (rsef != NULL) {
318 struct sieve_side_effect *seffect = &rsef->seffect;
319 bool found = FALSE;
320
321 i_assert(seffect->def != NULL);
322 if (seffect->def->merge != NULL) {
323 /* Try to find it among the new */
324 nrsef = (new_seffects != NULL ?
325 new_seffects->first_effect : NULL);
326 while (nrsef != NULL) {
327 struct sieve_side_effect *nseffect = &nrsef->seffect;
328
329 if (nseffect->def == seffect->def) {
330 if (seffect->def->merge(
331 renv, action, seffect, nseffect,
332 &seffect->context) < 0)
333 return -1;
334
335 found = TRUE;
336 break;
337 }
338 nrsef = nrsef->next;
339 }
340
341 /* Not found? */
342 if (!found && seffect->def->merge(
343 renv, action, seffect, NULL,
344 &rsef->seffect.context) < 0)
345 return -1;
346 }
347 rsef = rsef->next;
348 }
349
350 /* Merge new Side effects */
351 nrsef = new_seffects != NULL ? new_seffects->first_effect : NULL;
352 while (nrsef != NULL) {
353 struct sieve_side_effect *nseffect = &nrsef->seffect;
354 bool found = FALSE;
355
356 i_assert(nseffect->def != NULL);
357 if (nseffect->def->merge != NULL) {
358 /* Try to find it among the exising */
359 rsef = (old_seffects != NULL ?
360 old_seffects->first_effect : NULL);
361 while (rsef != NULL) {
362 if (rsef->seffect.def == nseffect->def) {
363 found = TRUE;
364 break;
365 }
366 rsef = rsef->next;
367 }
368
369 /* Not found? */
370 if (!found) {
371 void *new_context = NULL;
372
373 if ((ret = nseffect->def->merge(
374 renv, action, nseffect, nseffect,
375 &new_context)) < 0)
376 return -1;
377
378 if (ret != 0) {
379 if (old_action->seffects == NULL) {
380 old_action->seffects = old_seffects =
381 sieve_side_effects_list_create(renv->result);
382 }
383
384 nseffect->context = new_context;
385
386 /* Add side effect */
387 sieve_side_effects_list_add(old_seffects,
388 nseffect);
389 }
390 }
391 }
392 nrsef = nrsef->next;
393 }
394
395 return 1;
396 }
397
398 static void
sieve_result_action_detach(struct sieve_result * result,struct sieve_result_action * raction)399 sieve_result_action_detach(struct sieve_result *result,
400 struct sieve_result_action *raction)
401 {
402 if (result->actions_head == raction)
403 result->actions_head = raction->next;
404
405 if (result->actions_tail == raction)
406 result->actions_tail = raction->prev;
407
408 if (raction->next != NULL)
409 raction->next->prev = raction->prev;
410 if (raction->prev != NULL)
411 raction->prev->next = raction->next;
412
413 raction->next = NULL;
414 raction->prev = NULL;
415
416 if (result->action_count > 0)
417 result->action_count--;
418 }
419
420 static int
_sieve_result_add_action(const struct sieve_runtime_env * renv,const struct sieve_extension * ext,const char * name,const struct sieve_action_def * act_def,struct sieve_side_effects_list * seffects,void * context,unsigned int instance_limit,bool preserve_mail,bool keep)421 _sieve_result_add_action(const struct sieve_runtime_env *renv,
422 const struct sieve_extension *ext, const char *name,
423 const struct sieve_action_def *act_def,
424 struct sieve_side_effects_list *seffects,
425 void *context, unsigned int instance_limit,
426 bool preserve_mail, bool keep)
427 {
428 int ret = 0;
429 unsigned int instance_count = 0;
430 struct sieve_instance *svinst = renv->exec_env->svinst;
431 struct sieve_result *result = renv->result;
432 struct sieve_result_action *raction = NULL, *kaction = NULL;
433 struct sieve_action action;
434
435 i_assert(name != NULL || act_def != NULL);
436 action.name = name;
437 action.def = act_def;
438 action.ext = ext;
439 action.location = sieve_runtime_get_full_command_location(renv);
440 action.context = context;
441 action.exec_seq = result->exec_seq;
442
443 /* First, check for duplicates or conflicts */
444 raction = result->actions_head;
445 while (raction != NULL) {
446 const struct sieve_action *oact = &raction->action;
447 bool oact_new = (oact->exec_seq == result->exec_seq);
448
449 if (keep && raction->action.keep) {
450 /* Duplicate keep */
451 if (oact->def == NULL || !oact_new) {
452 /* Keep action from preceeding execution */
453
454 /* Detach existing keep action */
455 sieve_result_action_detach(result, raction);
456
457 /* Merge existing side-effects with new keep action */
458 if (kaction == NULL)
459 kaction = raction;
460
461 if ((ret = sieve_result_side_effects_merge(
462 renv, &action, kaction, seffects)) <= 0)
463 return ret;
464 } else {
465 /* True duplicate */
466 return sieve_result_side_effects_merge(
467 renv, &action, raction, seffects);
468 }
469 } else if ( act_def != NULL && raction->action.def == act_def ) {
470 instance_count++;
471
472 /* Possible duplicate */
473 if (act_def->check_duplicate != NULL) {
474 if ((ret = act_def->check_duplicate(
475 renv, &action, &raction->action)) < 0)
476 return ret;
477
478 /* Duplicate */
479 if (ret == 1) {
480 if (keep && !oact->keep) {
481 /* New keep has higher precedence than
482 existing duplicate non-keep action.
483 So, take over the result action object
484 and transform it into a keep.
485 */
486 if ((ret = sieve_result_side_effects_merge(
487 renv, &action, raction, seffects)) < 0)
488 return ret;
489
490 if (kaction == NULL) {
491 raction->action.context = NULL;
492 raction->action.location =
493 p_strdup(result->pool, action.location);
494
495 /* Note that existing execution
496 status is retained, making sure
497 that keep is not executed
498 multiple times.
499 */
500 kaction = raction;
501 } else {
502 sieve_result_action_detach(result, raction);
503
504 if ((ret = sieve_result_side_effects_merge(
505 renv, &action, kaction,
506 raction->seffects)) < 0)
507 return ret;
508 }
509 } else {
510 /* Merge side-effects, but don't add new action
511 */
512 return sieve_result_side_effects_merge(
513 renv, &action, raction, seffects);
514 }
515 }
516 }
517 } else {
518 if (act_def != NULL && oact->def != NULL) {
519 /* Check conflict */
520 if (act_def->check_conflict != NULL &&
521 (ret = act_def->check_conflict(
522 renv, &action, &raction->action)) != 0)
523 return ret;
524
525 if (oact_new &&
526 oact->def->check_conflict != NULL &&
527 (ret = oact->def->check_conflict(
528 renv, &raction->action, &action)) != 0)
529 return ret;
530 }
531 }
532 raction = raction->next;
533 }
534
535 if (kaction != NULL) {
536 /* Use existing keep action to define new one */
537 raction = kaction;
538 } else {
539 /* Check policy limit on total number of actions */
540 if (svinst->max_actions > 0 &&
541 result->action_count >= svinst->max_actions)
542 {
543 sieve_runtime_error(
544 renv, action.location,
545 "total number of actions exceeds policy limit "
546 "(%u > %u)",
547 result->action_count+1, svinst->max_actions);
548 return -1;
549 }
550
551 /* Check policy limit on number of this class of actions */
552 if (instance_limit > 0 && instance_count >= instance_limit) {
553 sieve_runtime_error(
554 renv, action.location,
555 "number of %s actions exceeds policy limit "
556 "(%u > %u)",
557 act_def->name, instance_count+1,
558 instance_limit);
559 return -1;
560 }
561
562 /* Create new action object */
563 raction = p_new(result->pool, struct sieve_result_action, 1);
564 raction->seffects = seffects;
565 }
566
567 raction->action.name = (action.name == NULL ?
568 act_def->name :
569 p_strdup(result->pool, action.name));
570 raction->action.context = context;
571 raction->action.def = act_def;
572 raction->action.ext = ext;
573 raction->action.location = p_strdup(result->pool, action.location);
574 raction->action.keep = keep;
575 raction->action.exec_seq = result->exec_seq;
576
577 if (raction->prev == NULL && raction != result->actions_head) {
578 /* Add */
579 if (result->actions_head == NULL) {
580 result->actions_head = raction;
581 result->actions_tail = raction;
582 raction->prev = NULL;
583 raction->next = NULL;
584 } else {
585 result->actions_tail->next = raction;
586 raction->prev = result->actions_tail;
587 result->actions_tail = raction;
588 raction->next = NULL;
589 }
590 result->action_count++;
591
592 /* Apply any implicit side effects */
593 if (hash_table_is_created(result->action_contexts)) {
594 struct sieve_result_action_context *actctx;
595
596 /* Check for implicit side effects to this particular
597 action */
598 actctx = hash_table_lookup(
599 result->action_contexts,
600 (keep ? &act_store : act_def));
601
602 if (actctx != NULL) {
603 struct sieve_result_side_effect *iseff;
604
605 /* Iterate through all implicit side effects and
606 add those that are missing.
607 */
608 iseff = actctx->seffects->first_effect;
609 while (iseff != NULL) {
610 struct sieve_result_side_effect *seff;
611 bool exists = FALSE;
612
613 /* Scan for presence */
614 if (seffects != NULL) {
615 seff = seffects->first_effect;
616 while (seff != NULL) {
617 if (seff->seffect.def == iseff->seffect.def) {
618 exists = TRUE;
619 break;
620 }
621
622 seff = seff->next;
623 }
624 } else {
625 raction->seffects = seffects =
626 sieve_side_effects_list_create(result);
627 }
628
629 /* If not present, add it */
630 if (!exists) {
631 sieve_side_effects_list_add(seffects, &iseff->seffect);
632 }
633
634 iseff = iseff->next;
635 }
636 }
637 }
638 }
639
640 if (preserve_mail) {
641 raction->action.mail = sieve_message_get_mail(renv->msgctx);
642 sieve_message_snapshot(renv->msgctx);
643 } else {
644 raction->action.mail = NULL;
645 }
646
647 sieve_result_init_action_event(result, &raction->action, !keep);
648 return 0;
649 }
650
sieve_result_add_action(const struct sieve_runtime_env * renv,const struct sieve_extension * ext,const char * name,const struct sieve_action_def * act_def,struct sieve_side_effects_list * seffects,void * context,unsigned int instance_limit,bool preserve_mail)651 int sieve_result_add_action(const struct sieve_runtime_env *renv,
652 const struct sieve_extension *ext, const char *name,
653 const struct sieve_action_def *act_def,
654 struct sieve_side_effects_list *seffects,
655 void *context, unsigned int instance_limit,
656 bool preserve_mail)
657 {
658 return _sieve_result_add_action(renv, ext, name, act_def, seffects,
659 context, instance_limit, preserve_mail,
660 FALSE);
661 }
662
sieve_result_add_keep(const struct sieve_runtime_env * renv,struct sieve_side_effects_list * seffects)663 int sieve_result_add_keep(const struct sieve_runtime_env *renv,
664 struct sieve_side_effects_list *seffects)
665 {
666 return _sieve_result_add_action(renv, renv->result->keep_action.ext,
667 "keep", renv->result->keep_action.def,
668 seffects, NULL, 0, TRUE, TRUE);
669 }
670
sieve_result_set_keep_action(struct sieve_result * result,const struct sieve_extension * ext,const struct sieve_action_def * act_def)671 void sieve_result_set_keep_action(struct sieve_result *result,
672 const struct sieve_extension *ext,
673 const struct sieve_action_def *act_def)
674 {
675 result->keep_action.def = act_def;
676 result->keep_action.ext = ext;
677 }
678
sieve_result_set_failure_action(struct sieve_result * result,const struct sieve_extension * ext,const struct sieve_action_def * act_def)679 void sieve_result_set_failure_action(struct sieve_result *result,
680 const struct sieve_extension *ext,
681 const struct sieve_action_def *act_def)
682 {
683 result->failure_action.def = act_def;
684 result->failure_action.ext = ext;
685 }
686
687 /*
688 * Result printing
689 */
690
sieve_result_vprintf(const struct sieve_result_print_env * penv,const char * fmt,va_list args)691 void sieve_result_vprintf(const struct sieve_result_print_env *penv,
692 const char *fmt, va_list args)
693 {
694 string_t *outbuf = t_str_new(128);
695
696 str_vprintfa(outbuf, fmt, args);
697
698 o_stream_nsend(penv->stream, str_data(outbuf), str_len(outbuf));
699 }
700
sieve_result_printf(const struct sieve_result_print_env * penv,const char * fmt,...)701 void sieve_result_printf(const struct sieve_result_print_env *penv,
702 const char *fmt, ...)
703 {
704 va_list args;
705
706 va_start(args, fmt);
707 sieve_result_vprintf(penv, fmt, args);
708 va_end(args);
709 }
710
sieve_result_action_printf(const struct sieve_result_print_env * penv,const char * fmt,...)711 void sieve_result_action_printf(const struct sieve_result_print_env *penv,
712 const char *fmt, ...)
713 {
714 string_t *outbuf = t_str_new(128);
715 va_list args;
716
717 va_start(args, fmt);
718 str_append(outbuf, " * ");
719 str_vprintfa(outbuf, fmt, args);
720 str_append_c(outbuf, '\n');
721 va_end(args);
722
723 o_stream_nsend(penv->stream, str_data(outbuf), str_len(outbuf));
724 }
725
sieve_result_seffect_printf(const struct sieve_result_print_env * penv,const char * fmt,...)726 void sieve_result_seffect_printf(const struct sieve_result_print_env *penv,
727 const char *fmt, ...)
728 {
729 string_t *outbuf = t_str_new(128);
730 va_list args;
731
732 va_start(args, fmt);
733 str_append(outbuf, " + ");
734 str_vprintfa(outbuf, fmt, args);
735 str_append_c(outbuf, '\n');
736 va_end(args);
737
738 o_stream_nsend(penv->stream, str_data(outbuf), str_len(outbuf));
739 }
740
741 static void
sieve_result_print_side_effects(struct sieve_result_print_env * rpenv,const struct sieve_action * action,struct sieve_side_effects_list * slist,bool * implicit_keep)742 sieve_result_print_side_effects(struct sieve_result_print_env *rpenv,
743 const struct sieve_action *action,
744 struct sieve_side_effects_list *slist,
745 bool *implicit_keep)
746 {
747 struct sieve_result_side_effect *rsef;
748
749 /* Print side effects */
750 rsef = (slist != NULL ? slist->first_effect : NULL);
751 while (rsef != NULL) {
752 const struct sieve_side_effect *sef = &rsef->seffect;
753
754 i_assert(sef->def != NULL);
755
756 if (sef->def->print != NULL) {
757 sef->def->print(sef, action, rpenv,
758 implicit_keep);
759 }
760 rsef = rsef->next;
761 }
762 }
763
764 static void
sieve_result_print_implicit_side_effects(struct sieve_result_print_env * rpenv)765 sieve_result_print_implicit_side_effects(struct sieve_result_print_env *rpenv)
766 {
767 struct sieve_result *result = rpenv->result;
768 bool dummy = TRUE;
769
770 /* Print any implicit side effects if applicable */
771 if (hash_table_is_created(result->action_contexts)) {
772 struct sieve_result_action_context *actctx;
773
774 /* Check for implicit side effects to keep action */
775 actctx = hash_table_lookup(rpenv->result->action_contexts,
776 &act_store);
777
778 if (actctx != NULL && actctx->seffects != NULL) {
779 sieve_result_print_side_effects(
780 rpenv, &result->keep_action,
781 actctx->seffects, &dummy);
782 }
783 }
784 }
785
sieve_result_print(struct sieve_result * result,const struct sieve_script_env * senv,struct ostream * stream,bool * keep)786 bool sieve_result_print(struct sieve_result *result,
787 const struct sieve_script_env *senv,
788 struct ostream *stream, bool *keep)
789 {
790 struct sieve_action act_keep = result->keep_action;
791 struct sieve_result_print_env penv;
792 bool implicit_keep = TRUE, printed_any = FALSE;
793 struct sieve_result_action *rac;
794
795 if (keep != NULL)
796 *keep = FALSE;
797
798 /* Prepare environment */
799
800 penv.result = result;
801 penv.stream = stream;
802 penv.scriptenv = senv;
803
804 sieve_result_printf(&penv, "\nPerformed actions:\n\n");
805
806 rac = result->actions_head;
807 while (rac != NULL) {
808 bool impl_keep = TRUE;
809 const struct sieve_action *act = &rac->action;
810
811 if (act->exec_seq < result->exec_seq) {
812 rac = rac->next;
813 continue;
814 }
815
816 if (rac->action.keep && keep != NULL)
817 *keep = TRUE;
818
819 if (act->def != NULL) {
820 if (act->def->print != NULL)
821 act->def->print(act, &penv, &impl_keep);
822 else {
823 sieve_result_action_printf(
824 &penv, "%s", act->def->name);
825 }
826 } else {
827 if (act->keep) {
828 sieve_result_action_printf(&penv, "keep");
829 impl_keep = FALSE;
830 } else {
831 sieve_result_action_printf(&penv, "[NULL]");
832 }
833 }
834 printed_any = TRUE;
835
836 /* Print side effects */
837 sieve_result_print_side_effects(
838 &penv, &rac->action, rac->seffects, &impl_keep);
839
840 implicit_keep = implicit_keep && impl_keep;
841
842 rac = rac->next;
843 }
844 if (!printed_any)
845 sieve_result_printf(&penv, " (none)\n");
846
847 if (implicit_keep && keep != NULL)
848 *keep = TRUE;
849
850 sieve_result_printf(&penv, "\nImplicit keep:\n\n");
851
852 if (implicit_keep) {
853 bool dummy = TRUE;
854
855 if (act_keep.def == NULL) {
856 sieve_result_action_printf(&penv, "keep");
857
858 sieve_result_print_implicit_side_effects(&penv);
859 } else {
860 /* Scan for execution of keep-equal actions */
861 rac = result->actions_head;
862 while (act_keep.def != NULL && rac != NULL) {
863 if (rac->action.def == act_keep.def &&
864 act_keep.def->equals != NULL &&
865 act_keep.def->equals(senv, NULL, &rac->action) &&
866 sieve_action_is_executed(&rac->action,
867 result))
868 act_keep.def = NULL;
869
870 rac = rac->next;
871 }
872
873 if (act_keep.def == NULL) {
874 sieve_result_printf(&penv,
875 " (none; keep or equivalent action executed earlier)\n");
876 } else {
877 act_keep.def->print(&act_keep, &penv, &dummy);
878
879 sieve_result_print_implicit_side_effects(&penv);
880 }
881 }
882 } else {
883 sieve_result_printf(&penv, " (none)\n");
884 }
885
886 sieve_result_printf(&penv, "\n");
887
888 return TRUE;
889 }
890
891 /*
892 * Result execution
893 */
894
895 struct sieve_side_effect_execution {
896 struct sieve_result_side_effect *seffect;
897
898 void *tr_context;
899
900 struct sieve_side_effect_execution *prev, *next;
901 };
902
903 struct sieve_action_execution {
904 struct sieve_result_action *action;
905 unsigned int exec_seq;
906 struct sieve_action_execution *prev, *next;
907
908 struct sieve_side_effect_execution *seffects_head, *seffects_tail;
909
910 struct sieve_error_handler *ehandler;
911 void *tr_context;
912 enum sieve_action_execution_state state;
913 int status;
914
915 bool commit:1;
916 };
917
918 struct sieve_result_execution {
919 pool_t pool;
920 struct sieve_action_exec_env action_env;
921 struct sieve_error_handler *ehandler;
922 struct event *event;
923
924 int status;
925
926 struct sieve_action_execution *actions_head, *actions_tail;
927
928 struct sieve_result_action keep_action;
929 struct sieve_action_execution keep;
930 struct sieve_action_execution *keep_equiv_action;
931 int keep_status;
932
933 bool keep_success:1;
934 bool keep_explicit:1;
935 bool keep_implicit:1;
936 bool keep_finalizing:1;
937 bool seen_delivery:1;
938 bool executed:1;
939 bool executed_delivery:1;
940 bool committed:1;
941 };
942
sieve_result_mark_executed(struct sieve_result * result)943 void sieve_result_mark_executed(struct sieve_result *result)
944 {
945 result->exec_seq++;
946 }
947
948 /* Side effect */
949
950 static int
sieve_result_side_effect_pre_execute(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec,struct sieve_side_effect_execution * seexec)951 sieve_result_side_effect_pre_execute(struct sieve_result_execution *rexec,
952 struct sieve_action_execution *aexec,
953 struct sieve_side_effect_execution *seexec)
954 {
955 struct sieve_result_side_effect *rsef = seexec->seffect;
956 struct sieve_side_effect *sef = &rsef->seffect;
957
958 i_assert(sef->def != NULL);
959 if (sef->def->pre_execute == NULL)
960 return SIEVE_EXEC_OK;
961
962 return sef->def->pre_execute(sef, &rexec->action_env,
963 aexec->tr_context, &seexec->tr_context);
964 }
965
966 static int
sieve_result_side_effect_post_execute(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec,struct sieve_side_effect_execution * seexec,bool * impl_keep)967 sieve_result_side_effect_post_execute(
968 struct sieve_result_execution *rexec,
969 struct sieve_action_execution *aexec,
970 struct sieve_side_effect_execution *seexec, bool *impl_keep)
971 {
972 struct sieve_result_side_effect *rsef = seexec->seffect;
973 struct sieve_side_effect *sef = &rsef->seffect;
974
975 i_assert(sef->def != NULL);
976 if (sef->def->post_execute == NULL)
977 return SIEVE_EXEC_OK;
978
979 return sef->def->post_execute(sef, &rexec->action_env,
980 aexec->tr_context, seexec->tr_context,
981 impl_keep);
982 }
983
984 static void
sieve_result_side_effect_post_commit(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec,struct sieve_side_effect_execution * seexec,int commit_status)985 sieve_result_side_effect_post_commit(struct sieve_result_execution *rexec,
986 struct sieve_action_execution *aexec,
987 struct sieve_side_effect_execution *seexec,
988 int commit_status)
989 {
990 struct sieve_result_side_effect *rsef = seexec->seffect;
991 struct sieve_side_effect *sef = &rsef->seffect;
992
993 i_assert(sef->def != NULL);
994 if (sef->def->post_commit == NULL)
995 return;
996
997 sef->def->post_commit(sef, &rexec->action_env,
998 aexec->tr_context, seexec->tr_context,
999 commit_status);
1000 }
1001
1002 static void
sieve_result_side_effect_rollback(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec,struct sieve_side_effect_execution * seexec)1003 sieve_result_side_effect_rollback(struct sieve_result_execution *rexec,
1004 struct sieve_action_execution *aexec,
1005 struct sieve_side_effect_execution *seexec)
1006 {
1007 struct sieve_result_side_effect *rsef = seexec->seffect;
1008 struct sieve_side_effect *sef = &rsef->seffect;
1009
1010 i_assert(sef->def != NULL);
1011 if (sef->def->rollback == NULL)
1012 return;
1013
1014 sef->def->rollback(sef, &rexec->action_env,
1015 aexec->tr_context, seexec->tr_context,
1016 (aexec->status == SIEVE_EXEC_OK));
1017 }
1018
1019 static void
sieve_action_execution_add_side_effect(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec,struct sieve_result_side_effect * seffect)1020 sieve_action_execution_add_side_effect(struct sieve_result_execution *rexec,
1021 struct sieve_action_execution *aexec,
1022 struct sieve_result_side_effect *seffect)
1023 {
1024 struct sieve_side_effect_execution *seexec;
1025
1026 seexec = aexec->seffects_head;
1027 while (seexec != NULL) {
1028 if (seexec->seffect == seffect)
1029 return;
1030 seexec = seexec->next;
1031 }
1032
1033 seexec = p_new(rexec->pool, struct sieve_side_effect_execution, 1);
1034 seexec->seffect = seffect;
1035
1036 DLLIST2_APPEND(&aexec->seffects_head, &aexec->seffects_tail, seexec);
1037 }
1038
1039 static void
sieve_action_execution_add_side_effects(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec,struct sieve_result_action * rac)1040 sieve_action_execution_add_side_effects(struct sieve_result_execution *rexec,
1041 struct sieve_action_execution *aexec,
1042 struct sieve_result_action *rac)
1043 {
1044 struct sieve_result_side_effect *rsef;
1045
1046 rsef = (rac->seffects == NULL ? NULL : rac->seffects->first_effect);
1047 while (rsef != NULL) {
1048 sieve_action_execution_add_side_effect(rexec, aexec, rsef);
1049 rsef = rsef->next;
1050 }
1051 }
1052
1053 /* Action */
1054
1055 static void
sieve_action_execution_pre(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec)1056 sieve_action_execution_pre(struct sieve_result_execution *rexec,
1057 struct sieve_action_execution *aexec)
1058 {
1059 if (aexec->ehandler == NULL)
1060 aexec->ehandler = rexec->ehandler;
1061 rexec->action_env.action = &aexec->action->action;
1062 rexec->action_env.event = aexec->action->action.event;
1063 rexec->action_env.ehandler = aexec->ehandler;
1064 }
1065
1066 static void
sieve_action_execution_post(struct sieve_result_execution * rexec)1067 sieve_action_execution_post(struct sieve_result_execution *rexec)
1068 {
1069 rexec->action_env.action = NULL;
1070 rexec->action_env.event = rexec->action_env.result->event;
1071 rexec->action_env.ehandler = NULL;
1072 }
1073
1074 static int
sieve_result_action_start(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec)1075 sieve_result_action_start(struct sieve_result_execution *rexec,
1076 struct sieve_action_execution *aexec)
1077 {
1078 struct sieve_result_action *rac = aexec->action;
1079 struct sieve_action *act = &rac->action;
1080 int status = SIEVE_EXEC_OK;
1081
1082 /* Skip actions that are already started. */
1083 if (aexec->state >= SIEVE_ACTION_EXECUTION_STATE_STARTED)
1084 return status;
1085 aexec->state = SIEVE_ACTION_EXECUTION_STATE_STARTED;
1086 aexec->status = status;
1087
1088 /* Skip non-actions (inactive keep). */
1089 if (act->def == NULL)
1090 return status;
1091
1092 if (act->def->start != NULL) {
1093 sieve_action_execution_pre(rexec, aexec);
1094 status = act->def->start(&rexec->action_env,
1095 &aexec->tr_context);
1096 aexec->status = status;
1097 sieve_action_execution_post(rexec);
1098 }
1099 return status;
1100 }
1101
1102 static int
sieve_result_action_execute(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec,int start_status)1103 sieve_result_action_execute(struct sieve_result_execution *rexec,
1104 struct sieve_action_execution *aexec,
1105 int start_status)
1106 {
1107 struct sieve_result_action *rac = aexec->action;
1108 struct sieve_action *act = &rac->action;
1109 struct sieve_side_effect_execution *seexec;
1110 int status = start_status;
1111 bool impl_keep = TRUE;
1112
1113 /* Skip actions that are already executed. */
1114 if (aexec->state >= SIEVE_ACTION_EXECUTION_STATE_EXECUTED)
1115 return status;
1116 aexec->state = SIEVE_ACTION_EXECUTION_STATE_EXECUTED;
1117
1118 /* Record explicit keep when it is not the final implicit keep */
1119 if (act->keep && aexec != &rexec->keep)
1120 rexec->keep_explicit = TRUE;
1121
1122 /* Skip non-actions (inactive keep) */
1123 if (act->def == NULL) {
1124 i_assert(aexec != &rexec->keep);
1125 if (act->keep)
1126 e_debug(rexec->event, "Executed explicit keep");
1127 return status;
1128 }
1129
1130 /* Don't execute if others already failed */
1131 if (status != SIEVE_EXEC_OK)
1132 return status;
1133
1134 if (aexec == &rexec->keep)
1135 e_debug(rexec->event, "Executing implicit keep action");
1136 else {
1137 e_debug(rexec->event, "Executing %s action%s",
1138 sieve_action_name(act),
1139 (act->keep ? " (explicit keep)" : ""));
1140 }
1141
1142 sieve_action_execution_pre(rexec, aexec);
1143
1144 /* Execute pre-execute event of side effects */
1145 seexec = aexec->seffects_head;
1146 while (status == SIEVE_EXEC_OK && seexec != NULL) {
1147 status = sieve_result_side_effect_pre_execute(
1148 rexec, aexec, seexec);
1149 seexec = seexec->next;
1150 }
1151
1152 /* Execute the action itself */
1153 if (status == SIEVE_EXEC_OK && act->def != NULL &&
1154 act->def->execute != NULL) {
1155 status = act->def->execute(&rexec->action_env,
1156 aexec->tr_context,
1157 &impl_keep);
1158 if (status == SIEVE_EXEC_OK)
1159 rexec->executed = TRUE;
1160 }
1161
1162 /* Execute post-execute event of side effects */
1163 seexec = aexec->seffects_head;
1164 while (status == SIEVE_EXEC_OK && seexec != NULL) {
1165 status = sieve_result_side_effect_post_execute(
1166 rexec, aexec, seexec, &impl_keep);
1167 seexec = seexec->next;
1168 }
1169
1170 if (aexec == &rexec->keep) {
1171 e_debug(rexec->event,
1172 "Finished executing implicit keep action (status=%s)",
1173 sieve_execution_exitcode_to_str(status));
1174 } else {
1175 e_debug(rexec->event, "Finished executing %s action "
1176 "(status=%s, keep=%s)", sieve_action_name(act),
1177 sieve_execution_exitcode_to_str(status),
1178 (act->keep ? "explicit" :
1179 (impl_keep && rexec->keep_implicit ?
1180 "implicit" : "canceled")));
1181 }
1182
1183 if (status == SIEVE_EXEC_OK &&
1184 (act->def->flags & SIEVE_ACTFLAG_TRIES_DELIVER) != 0)
1185 rexec->seen_delivery = TRUE;
1186
1187 /* Update implicit keep status (but only when we're not running the
1188 implicit keep right now). */
1189 if (aexec != &rexec->keep)
1190 rexec->keep_implicit = rexec->keep_implicit && impl_keep;
1191
1192 sieve_action_execution_post(rexec);
1193
1194 aexec->status = status;
1195 return status;
1196 }
1197
1198 static int
sieve_result_action_commit(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec)1199 sieve_result_action_commit(struct sieve_result_execution *rexec,
1200 struct sieve_action_execution *aexec)
1201 {
1202 struct sieve_result_action *rac = aexec->action;
1203 struct sieve_action *act = &rac->action;
1204 struct sieve_side_effect_execution *seexec;
1205 int cstatus = SIEVE_EXEC_OK;
1206
1207 if (aexec == &rexec->keep) {
1208 e_debug(rexec->event, "Commit implicit keep action");
1209 } else {
1210 e_debug(rexec->event, "Commit %s action%s",
1211 sieve_action_name(act),
1212 (act->keep ? " (explicit keep)" : ""));
1213 }
1214
1215 sieve_action_execution_pre(rexec, aexec);
1216
1217 if (act->def->commit != NULL) {
1218 cstatus = act->def->commit(&rexec->action_env,
1219 aexec->tr_context);
1220 if (cstatus == SIEVE_EXEC_OK)
1221 rexec->committed = TRUE;
1222 }
1223
1224 /* Execute post_commit event of side effects */
1225 seexec = aexec->seffects_head;
1226 while (seexec != NULL) {
1227 sieve_result_side_effect_post_commit(
1228 rexec, aexec, seexec, cstatus);
1229 seexec = seexec->next;
1230 }
1231
1232 sieve_action_execution_post(rexec);
1233
1234 return cstatus;
1235 }
1236
1237 static void
sieve_result_action_rollback(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec)1238 sieve_result_action_rollback(struct sieve_result_execution *rexec,
1239 struct sieve_action_execution *aexec)
1240 {
1241 struct sieve_result_action *rac = aexec->action;
1242 struct sieve_action *act = &rac->action;
1243 struct sieve_side_effect_execution *seexec;
1244
1245 if (aexec == &rexec->keep) {
1246 e_debug(rexec->event, "Roll back implicit keep action");
1247 } else {
1248 e_debug(rexec->event, "Roll back %s action%s",
1249 sieve_action_name(act),
1250 (act->keep ? " (explicit keep)" : ""));
1251 }
1252
1253 sieve_action_execution_pre(rexec, aexec);
1254
1255 if (act->def->rollback != NULL) {
1256 act->def->rollback(&rexec->action_env, aexec->tr_context,
1257 (aexec->status == SIEVE_EXEC_OK));
1258 }
1259
1260 /* Rollback side effects */
1261 seexec = aexec->seffects_head;
1262 while (seexec != NULL) {
1263 sieve_result_side_effect_rollback(rexec, aexec, seexec);
1264 seexec = seexec->next;
1265 }
1266
1267 sieve_action_execution_post(rexec);
1268 }
1269
1270 static int
sieve_result_action_commit_or_rollback(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec,int status,int * commit_status)1271 sieve_result_action_commit_or_rollback(struct sieve_result_execution *rexec,
1272 struct sieve_action_execution *aexec,
1273 int status, int *commit_status)
1274 {
1275 struct sieve_result_action *rac = aexec->action;
1276 struct sieve_action *act = &rac->action;
1277
1278 /* Skip actions that are already finalized. */
1279 if (aexec->state >= SIEVE_ACTION_EXECUTION_STATE_FINALIZED)
1280 return status;
1281 aexec->state = SIEVE_ACTION_EXECUTION_STATE_FINALIZED;
1282
1283 if (aexec == &rexec->keep) {
1284 e_debug(rexec->event, "Finalize implicit keep action"
1285 "(status=%s, action_status=%s, commit_status=%s)",
1286 sieve_execution_exitcode_to_str(status),
1287 sieve_execution_exitcode_to_str(aexec->status),
1288 sieve_execution_exitcode_to_str(*commit_status));
1289 } else {
1290 e_debug(rexec->event, "Finalize %s action "
1291 "(%sstatus=%s, action_status=%s, commit_status=%s, "
1292 "pre-commit=%s)",
1293 sieve_action_name(act),
1294 (act->keep ? "explicit keep, " : ""),
1295 sieve_execution_exitcode_to_str(status),
1296 sieve_execution_exitcode_to_str(aexec->status),
1297 sieve_execution_exitcode_to_str(*commit_status),
1298 (aexec->commit ? "yes" : "no"));
1299 }
1300
1301 /* Skip non-actions (inactive keep) */
1302 if (act->def == NULL)
1303 return status;
1304
1305 if (aexec->status == SIEVE_EXEC_OK &&
1306 (status == SIEVE_EXEC_OK ||
1307 (aexec->commit && *commit_status == SIEVE_EXEC_OK))) {
1308 int cstatus = SIEVE_EXEC_OK;
1309
1310 cstatus = sieve_result_action_commit(rexec, aexec);
1311 if (cstatus != SIEVE_EXEC_OK) {
1312 /* This is bad; try to salvage as much as possible */
1313 if (*commit_status == SIEVE_EXEC_OK) {
1314 *commit_status = cstatus;
1315 if (!rexec->committed) {
1316 /* We haven't executed anything yet;
1317 continue as rollback */
1318 status = cstatus;
1319 }
1320 }
1321 }
1322 } else {
1323 sieve_result_action_rollback(rexec, aexec);
1324 }
1325
1326 if (act->keep) {
1327 if (status == SIEVE_EXEC_FAILURE)
1328 status = SIEVE_EXEC_KEEP_FAILED;
1329 if (*commit_status == SIEVE_EXEC_FAILURE)
1330 *commit_status = SIEVE_EXEC_KEEP_FAILED;
1331 }
1332
1333 return status;
1334 }
1335
1336 static void
sieve_result_action_finish(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec,int status)1337 sieve_result_action_finish(struct sieve_result_execution *rexec,
1338 struct sieve_action_execution *aexec, int status)
1339 {
1340 struct sieve_result_action *rac = aexec->action;
1341 struct sieve_action *act = &rac->action;
1342
1343 /* Skip non-actions (inactive keep) */
1344 if (act->def == NULL)
1345 return;
1346
1347 if (aexec == &rexec->keep) {
1348 e_debug(rexec->event, "Finish implicit keep action");
1349 } else {
1350 e_debug(rexec->event, "Finish %s action%s",
1351 sieve_action_name(act),
1352 (act->keep ? " (explicit keep)" : ""));
1353 }
1354
1355 if (act->def->finish != NULL) {
1356 sieve_action_execution_pre(rexec, aexec);
1357 act->def->finish(&rexec->action_env, aexec->tr_context, status);
1358 sieve_action_execution_post(rexec);
1359 }
1360 }
1361
1362 static void
sieve_result_action_abort(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec)1363 sieve_result_action_abort(struct sieve_result_execution *rexec,
1364 struct sieve_action_execution *aexec)
1365 {
1366 if (aexec->state > SIEVE_ACTION_EXECUTION_STATE_INIT &&
1367 aexec->state < SIEVE_ACTION_EXECUTION_STATE_FINALIZED)
1368 sieve_result_action_rollback(rexec, aexec);
1369 DLLIST2_REMOVE(&rexec->actions_head, &rexec->actions_tail, aexec);
1370 }
1371
1372 static void
sieve_action_execution_update(struct sieve_result_execution * rexec,struct sieve_action_execution * aexec)1373 sieve_action_execution_update(struct sieve_result_execution *rexec,
1374 struct sieve_action_execution *aexec)
1375 {
1376 const struct sieve_action_exec_env *aenv = &rexec->action_env;
1377 struct sieve_result *result = aenv->result;
1378 struct sieve_result_action *rac;
1379
1380 rac = result->actions_head;
1381 while (rac != NULL) {
1382 if (aexec->action == rac)
1383 break;
1384 rac = rac->next;
1385 }
1386
1387 if (rac == NULL) {
1388 /* Action was removed; abort it. */
1389 sieve_result_action_abort(rexec, aexec);
1390 return;
1391 }
1392
1393 if (aexec->exec_seq != rac->action.exec_seq) {
1394 i_assert(rac->action.keep);
1395
1396 /* Recycled keep */
1397 aexec->exec_seq = rac->action.exec_seq;
1398 aexec->state = SIEVE_ACTION_EXECUTION_STATE_INIT;
1399 }
1400
1401 sieve_action_execution_add_side_effects(rexec, aexec, rac);
1402 }
1403
1404 static void
sieve_result_execution_add_action(struct sieve_result_execution * rexec,struct sieve_result_action * rac)1405 sieve_result_execution_add_action(struct sieve_result_execution *rexec,
1406 struct sieve_result_action *rac)
1407 {
1408 struct sieve_action_execution *aexec;
1409
1410 aexec = rexec->actions_head;
1411 while (aexec != NULL) {
1412 if (aexec->action == rac)
1413 return;
1414 aexec = aexec->next;
1415 }
1416
1417 aexec = p_new(rexec->pool, struct sieve_action_execution, 1);
1418 aexec->action = rac;
1419 aexec->exec_seq = rac->action.exec_seq;
1420 aexec->ehandler = rexec->ehandler;
1421
1422 DLLIST2_APPEND(&rexec->actions_head, &rexec->actions_tail, aexec);
1423
1424 sieve_action_execution_add_side_effects(rexec, aexec, rac);
1425 }
1426
1427 /* Result */
1428
1429 struct sieve_result_execution *
sieve_result_execution_create(struct sieve_result * result,pool_t pool)1430 sieve_result_execution_create(struct sieve_result *result, pool_t pool)
1431 {
1432 struct sieve_result_execution *rexec;
1433
1434 pool_ref(pool);
1435 rexec = p_new(pool, struct sieve_result_execution, 1);
1436 rexec->pool = pool;
1437 rexec->event = result->event;
1438 rexec->action_env.result = result;
1439 rexec->action_env.event = result->event;
1440 rexec->action_env.exec_env = result->exec_env;
1441 rexec->action_env.msgctx = result->msgctx;
1442 rexec->status = SIEVE_EXEC_OK;
1443 rexec->keep_success = TRUE;
1444 rexec->keep_status = SIEVE_EXEC_OK;
1445 rexec->keep_explicit = FALSE;
1446 rexec->keep_implicit = TRUE;
1447
1448 sieve_result_ref(result);
1449 result->exec = rexec;
1450
1451 return rexec;
1452 }
1453
sieve_result_execution_destroy(struct sieve_result_execution ** _rexec)1454 void sieve_result_execution_destroy(struct sieve_result_execution **_rexec)
1455 {
1456 struct sieve_result_execution *rexec = *_rexec;
1457
1458 *_rexec = NULL;
1459
1460 if (rexec == NULL)
1461 return;
1462
1463 rexec->action_env.result->exec = NULL;
1464 sieve_result_unref(&rexec->action_env.result);
1465 pool_unref(&rexec->pool);
1466 }
1467
1468 static void
sieve_result_implicit_keep_execute(struct sieve_result_execution * rexec)1469 sieve_result_implicit_keep_execute(struct sieve_result_execution *rexec)
1470 {
1471 const struct sieve_action_exec_env *aenv = &rexec->action_env;
1472 struct sieve_result *result = aenv->result;
1473 const struct sieve_execute_env *eenv = aenv->exec_env;
1474 struct sieve_action_execution *aexec;
1475 int status = SIEVE_EXEC_OK;
1476 struct sieve_action_execution *aexec_keep = &rexec->keep;
1477 struct sieve_result_action *ract_keep = &rexec->keep_action;
1478 struct sieve_action *act_keep = &ract_keep->action;
1479 bool success = FALSE;
1480
1481 switch (rexec->status) {
1482 case SIEVE_EXEC_OK:
1483 success = TRUE;
1484 break;
1485 case SIEVE_EXEC_TEMP_FAILURE:
1486 case SIEVE_EXEC_RESOURCE_LIMIT:
1487 if (rexec->committed) {
1488 e_debug(rexec->event,
1489 "Temporary failure occurred (status=%s), "
1490 "but other actions were already committed: "
1491 "execute failure implicit keep",
1492 sieve_execution_exitcode_to_str(rexec->status));
1493 break;
1494 }
1495 if (rexec->keep_finalizing)
1496 break;
1497
1498 e_debug(rexec->event,
1499 "Skip implicit keep for temporary failure "
1500 "(state=execute, status=%s)",
1501 sieve_execution_exitcode_to_str(rexec->status));
1502 return;
1503 default:
1504 break;
1505 }
1506
1507 if (rexec->keep_equiv_action != NULL) {
1508 e_debug(rexec->event, "No implicit keep needed "
1509 "(equivalent action already executed)");
1510 return;
1511 }
1512
1513 rexec->keep.action = &rexec->keep_action;
1514 rexec->keep.ehandler = rexec->ehandler;
1515 rexec->keep_success = success;
1516 rexec->keep_status = status;
1517
1518 if ((eenv->flags & SIEVE_EXECUTE_FLAG_DEFER_KEEP) != 0) {
1519 e_debug(rexec->event, "Execution of implicit keep is deferred");
1520 return;
1521 }
1522
1523 if (!success)
1524 *act_keep = result->failure_action;
1525 else
1526 *act_keep = result->keep_action;
1527 act_keep->name = "keep";
1528 act_keep->mail = NULL;
1529 act_keep->keep = TRUE;
1530
1531 /* If keep is a non-action, return right away */
1532 if (act_keep->def == NULL) {
1533 e_debug(rexec->event, "Keep is not defined yet");
1534 return;
1535 }
1536
1537 /* Scan for execution of keep-equal actions */
1538 aexec = rexec->actions_head;
1539 while (aexec != NULL) {
1540 struct sieve_result_action *rac = aexec->action;
1541
1542 if (rac->action.def == act_keep->def &&
1543 act_keep->def->equals != NULL &&
1544 act_keep->def->equals(eenv->scriptenv, NULL,
1545 &rac->action) &&
1546 aexec->state >= SIEVE_ACTION_EXECUTION_STATE_EXECUTED) {
1547 e_debug(rexec->event, "No implicit keep needed "
1548 "(equivalent %s action already executed)",
1549 sieve_action_name(&rac->action));
1550 rexec->keep_equiv_action = aexec;
1551 return;
1552 }
1553
1554 aexec = aexec->next;
1555 }
1556
1557 /* Scan for deferred keep */
1558 aexec = rexec->actions_tail;
1559 while (aexec != NULL) {
1560 struct sieve_result_action *rac = aexec->action;
1561
1562 if (aexec->state < SIEVE_ACTION_EXECUTION_STATE_EXECUTED) {
1563 aexec = NULL;
1564 break;
1565 }
1566 if (rac->action.keep && rac->action.def == NULL)
1567 break;
1568 aexec = aexec->prev;
1569 }
1570
1571 if (aexec == NULL) {
1572 if (success)
1573 act_keep->mail = sieve_message_get_mail(aenv->msgctx);
1574 } else {
1575 e_debug(rexec->event, "Found deferred keep action");
1576
1577 if (success) {
1578 act_keep->location = aexec->action->action.location;
1579 act_keep->mail = aexec->action->action.mail;
1580 ract_keep->seffects = aexec->action->seffects;
1581 }
1582 aexec->state = SIEVE_ACTION_EXECUTION_STATE_FINALIZED;
1583 }
1584
1585 if (ract_keep->seffects == NULL) {
1586 /* Apply any implicit side effects if applicable */
1587 if (success && hash_table_is_created(result->action_contexts)) {
1588 struct sieve_result_action_context *actctx;
1589
1590 /* Check for implicit side effects to keep action */
1591 actctx = hash_table_lookup(result->action_contexts,
1592 act_keep->def);
1593
1594 if (actctx != NULL)
1595 ract_keep->seffects = actctx->seffects;
1596 }
1597 }
1598
1599 e_debug(rexec->event, "Execute implicit keep (status=%s)",
1600 sieve_execution_exitcode_to_str(rexec->status));
1601
1602 /* Initialize side effects */
1603 sieve_action_execution_add_side_effects(rexec, aexec_keep, ract_keep);
1604
1605 /* Initialize keep action event */
1606 sieve_result_init_action_event(result, act_keep, FALSE);
1607
1608 /* Start keep action */
1609 status = sieve_result_action_start(rexec, aexec_keep);
1610
1611 /* Execute keep action */
1612 if (status == SIEVE_EXEC_OK)
1613 status = sieve_result_action_execute(rexec, aexec_keep, status);
1614 if (status == SIEVE_EXEC_OK)
1615 aexec_keep->commit = TRUE;
1616
1617 rexec->executed_delivery = rexec->seen_delivery;
1618 rexec->keep_status = status;
1619 sieve_action_execution_post(rexec);
1620 }
1621
1622 static int
sieve_result_implicit_keep_finalize(struct sieve_result_execution * rexec)1623 sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec)
1624 {
1625 const struct sieve_action_exec_env *aenv = &rexec->action_env;
1626 const struct sieve_execute_env *eenv = aenv->exec_env;
1627 struct sieve_action_execution *aexec_keep = &rexec->keep;
1628 struct sieve_result_action *ract_keep = &rexec->keep_action;
1629 struct sieve_action *act_keep = &ract_keep->action;
1630 int commit_status = SIEVE_EXEC_OK;
1631 bool success = FALSE, temp_failure = FALSE;
1632
1633 switch (rexec->status) {
1634 case SIEVE_EXEC_OK:
1635 success = TRUE;
1636 break;
1637 case SIEVE_EXEC_TEMP_FAILURE:
1638 case SIEVE_EXEC_RESOURCE_LIMIT:
1639 if (rexec->committed) {
1640 e_debug(rexec->event,
1641 "Temporary failure occurred (status=%s), "
1642 "but other actions were already committed: "
1643 "commit failure implicit keep",
1644 sieve_execution_exitcode_to_str(rexec->status));
1645 break;
1646 }
1647
1648 if (aexec_keep->state !=
1649 SIEVE_ACTION_EXECUTION_STATE_EXECUTED) {
1650 e_debug(rexec->event,
1651 "Skip implicit keep for temporary failure "
1652 "(state=commit, status=%s)",
1653 sieve_execution_exitcode_to_str(rexec->status));
1654 return rexec->status;
1655 }
1656 /* Roll back for temporary failure when no other action
1657 is committed. */
1658 commit_status = rexec->status;
1659 temp_failure = TRUE;
1660 break;
1661 default:
1662 break;
1663 }
1664
1665 if (rexec->keep_equiv_action != NULL) {
1666 struct sieve_action_execution *ke_aexec =
1667 rexec->keep_equiv_action;
1668
1669 e_debug(rexec->event, "No implicit keep needed "
1670 "(equivalent %s action already executed)",
1671 sieve_action_name(&ke_aexec->action->action));
1672 return ke_aexec->status;
1673 }
1674 if ((eenv->flags & SIEVE_EXECUTE_FLAG_DEFER_KEEP) != 0) {
1675 e_debug(rexec->event, "Execution of implicit keep is deferred");
1676 return rexec->keep_status;
1677 }
1678
1679 e_debug(rexec->event, "Finalize implicit keep (status=%s)",
1680 sieve_execution_exitcode_to_str(rexec->status));
1681
1682 rexec->keep_finalizing = TRUE;
1683
1684 /* Start keep if necessary */
1685 if (temp_failure) {
1686 rexec->keep_status = rexec->status;
1687 } else if (act_keep->def == NULL ||
1688 aexec_keep->state != SIEVE_ACTION_EXECUTION_STATE_EXECUTED) {
1689 sieve_result_implicit_keep_execute(rexec);
1690 /* Switch to failure keep if necessary. */
1691 } else if (rexec->keep_success && !success){
1692 e_debug(rexec->event, "Switch to failure implicit keep");
1693
1694 /* Failed transaction, rollback success keep action. */
1695 sieve_result_action_rollback(rexec, aexec_keep);
1696
1697 event_unref(&act_keep->event);
1698 i_zero(aexec_keep);
1699
1700 /* Start failure keep action. */
1701 sieve_result_implicit_keep_execute(rexec);
1702 }
1703 if (act_keep->def == NULL)
1704 return rexec->keep_status;
1705
1706 i_assert(aexec_keep->state == SIEVE_ACTION_EXECUTION_STATE_EXECUTED);
1707
1708 /* Finalize keep action */
1709 rexec->keep_status = sieve_result_action_commit_or_rollback(
1710 rexec, aexec_keep, rexec->keep_status, &commit_status);
1711
1712 /* Finish keep action */
1713 sieve_result_action_finish(rexec, aexec_keep,
1714 rexec->keep_status);
1715
1716 sieve_action_execution_post(rexec);
1717 event_unref(&act_keep->event);
1718
1719 if (rexec->keep_status == SIEVE_EXEC_FAILURE)
1720 rexec->keep_status = SIEVE_EXEC_KEEP_FAILED;
1721 return rexec->keep_status;
1722 }
1723
sieve_result_executed(struct sieve_result_execution * rexec)1724 bool sieve_result_executed(struct sieve_result_execution *rexec)
1725 {
1726 return rexec->executed;
1727 }
1728
sieve_result_committed(struct sieve_result_execution * rexec)1729 bool sieve_result_committed(struct sieve_result_execution *rexec)
1730 {
1731 return rexec->committed;
1732 }
1733
sieve_result_executed_delivery(struct sieve_result_execution * rexec)1734 bool sieve_result_executed_delivery(struct sieve_result_execution *rexec)
1735 {
1736 return rexec->executed_delivery;
1737 }
1738
sieve_result_transaction_start(struct sieve_result_execution * rexec)1739 static int sieve_result_transaction_start(struct sieve_result_execution *rexec)
1740 {
1741 struct sieve_action_execution *aexec;
1742 int status = SIEVE_EXEC_OK;
1743
1744 e_debug(rexec->event, "Starting execution of actions");
1745
1746 aexec = rexec->actions_head;
1747 while (status == SIEVE_EXEC_OK && aexec != NULL) {
1748 status = sieve_result_action_start(rexec, aexec);
1749 aexec = aexec->next;
1750 }
1751 sieve_action_execution_post(rexec);
1752
1753 return status;
1754 }
1755
1756 static int
sieve_result_transaction_execute(struct sieve_result_execution * rexec,int start_status)1757 sieve_result_transaction_execute(struct sieve_result_execution *rexec,
1758 int start_status)
1759 {
1760 struct sieve_action_execution *aexec;
1761 int status = SIEVE_EXEC_OK;
1762
1763 e_debug(rexec->event, "Executing actions");
1764
1765 rexec->seen_delivery = FALSE;
1766 aexec = rexec->actions_head;
1767 while (status == SIEVE_EXEC_OK && aexec != NULL) {
1768 status = sieve_result_action_execute(rexec, aexec,
1769 start_status);
1770 aexec = aexec->next;
1771 }
1772 sieve_action_execution_post(rexec);
1773
1774 if (status == SIEVE_EXEC_OK) {
1775 /* Since this execution series is successful so far, mark all
1776 actions in it to be committed. */
1777 aexec = rexec->actions_head;
1778 while (aexec != NULL) {
1779 aexec->commit = TRUE;
1780 aexec = aexec->next;
1781 }
1782
1783 rexec->executed_delivery =
1784 rexec->executed_delivery || rexec->seen_delivery;
1785 }
1786
1787 e_debug(rexec->event, "Finished executing actions "
1788 "(status=%s, keep=%s, executed=%s)",
1789 sieve_execution_exitcode_to_str(status),
1790 (rexec->keep_explicit ? "explicit" :
1791 (rexec->keep_implicit ? "implicit" : "none")),
1792 (rexec->executed ? "yes" : "no"));
1793 return status;
1794 }
1795
1796 static int
sieve_result_transaction_commit_or_rollback(struct sieve_result_execution * rexec,int status)1797 sieve_result_transaction_commit_or_rollback(
1798 struct sieve_result_execution *rexec, int status)
1799 {
1800 struct sieve_action_execution *aexec;
1801 int commit_status = SIEVE_EXEC_OK;
1802
1803 switch (status) {
1804 case SIEVE_EXEC_TEMP_FAILURE:
1805 /* Roll back all actions */
1806 commit_status = status;
1807 break;
1808 default:
1809 break;
1810 }
1811
1812 e_debug(rexec->event, "Finalizing actions");
1813
1814 /* First commit/rollback all storage actions */
1815 aexec = rexec->actions_head;
1816 while (aexec != NULL) {
1817 struct sieve_result_action *rac = aexec->action;
1818 struct sieve_action *act = &rac->action;
1819
1820 if (act->def == NULL ||
1821 (act->def->flags & SIEVE_ACTFLAG_MAIL_STORAGE) == 0) {
1822 aexec = aexec->next;
1823 continue;
1824 }
1825
1826 status = sieve_result_action_commit_or_rollback(
1827 rexec, aexec, status, &commit_status);
1828
1829 aexec = aexec->next;
1830 }
1831
1832 /* Then commit/rollback all other actions */
1833 aexec = rexec->actions_head;
1834 while (aexec != NULL) {
1835 struct sieve_result_action *rac = aexec->action;
1836 struct sieve_action *act = &rac->action;
1837
1838 if (act->def != NULL &&
1839 (act->def->flags & SIEVE_ACTFLAG_MAIL_STORAGE) != 0) {
1840 aexec = aexec->next;
1841 continue;
1842 }
1843
1844 status = sieve_result_action_commit_or_rollback(
1845 rexec, aexec, status, &commit_status);
1846
1847 aexec = aexec->next;
1848 }
1849
1850 e_debug(rexec->event, "Finished finalizing actions "
1851 "(status=%s, keep=%s, committed=%s)",
1852 sieve_execution_exitcode_to_str(status),
1853 (rexec->keep_explicit ? "explicit" :
1854 (rexec->keep_implicit ? "implicit" : "none")),
1855 (rexec->committed ? "yes" : "no"));
1856
1857 return commit_status;
1858 }
1859
1860 static void
sieve_result_transaction_finish(struct sieve_result_execution * rexec,int status)1861 sieve_result_transaction_finish(struct sieve_result_execution *rexec,
1862 int status)
1863 {
1864 struct sieve_action_execution *aexec;
1865
1866 e_debug(rexec->event, "Finishing actions");
1867
1868 aexec = rexec->actions_head;
1869 while (aexec != NULL) {
1870 sieve_result_action_finish(rexec, aexec, status);
1871 aexec = aexec->next;
1872 }
1873 sieve_action_execution_post(rexec);
1874 }
1875
1876 static void
sieve_result_execute_update_status(struct sieve_result_execution * rexec,int status)1877 sieve_result_execute_update_status(struct sieve_result_execution *rexec,
1878 int status)
1879 {
1880 switch (status) {
1881 case SIEVE_EXEC_OK:
1882 break;
1883 case SIEVE_EXEC_TEMP_FAILURE:
1884 rexec->status = status;
1885 break;
1886 case SIEVE_EXEC_BIN_CORRUPT:
1887 i_unreached();
1888 case SIEVE_EXEC_FAILURE:
1889 case SIEVE_EXEC_KEEP_FAILED:
1890 if (rexec->status == SIEVE_EXEC_OK)
1891 rexec->status = status;
1892 break;
1893 case SIEVE_EXEC_RESOURCE_LIMIT:
1894 if (rexec->status != SIEVE_EXEC_TEMP_FAILURE)
1895 rexec->status = status;
1896 break;
1897 }
1898 }
1899
1900 static void
sieve_result_execution_update(struct sieve_result_execution * rexec)1901 sieve_result_execution_update(struct sieve_result_execution *rexec)
1902 {
1903 const struct sieve_action_exec_env *aenv = &rexec->action_env;
1904 struct sieve_result *result = aenv->result;
1905 struct sieve_action_execution *aexec;
1906 struct sieve_result_action *rac;
1907
1908 aexec = rexec->actions_head;
1909 while (aexec != NULL) {
1910 struct sieve_action_execution *aexec_next = aexec->next;
1911
1912 sieve_action_execution_update(rexec, aexec);
1913 aexec = aexec_next;
1914 }
1915
1916 rac = result->actions_head;
1917 while (rac != NULL) {
1918 sieve_result_execution_add_action(rexec, rac);
1919 rac = rac->next;
1920 }
1921 }
1922
sieve_result_execute(struct sieve_result_execution * rexec,int status,bool commit,struct sieve_error_handler * ehandler,bool * keep_r)1923 int sieve_result_execute(struct sieve_result_execution *rexec, int status,
1924 bool commit, struct sieve_error_handler *ehandler,
1925 bool *keep_r)
1926 {
1927 const struct sieve_action_exec_env *aenv = &rexec->action_env;
1928 struct sieve_result *result = aenv->result;
1929 int result_status, ret;
1930
1931 e_debug(rexec->event, "Executing result (status=%s, commit=%s)",
1932 sieve_execution_exitcode_to_str(status),
1933 (commit ? "yes" : "no"));
1934
1935 if (keep_r != NULL)
1936 *keep_r = FALSE;
1937 sieve_result_mark_executed(result);
1938
1939 /* Prepare environment */
1940
1941 rexec->ehandler = ehandler;
1942
1943 /* Update actions in execution from result */
1944
1945 sieve_result_execution_update(rexec);
1946
1947 /* Transaction start and execute */
1948
1949 if (status != SIEVE_EXEC_OK) {
1950 sieve_result_execute_update_status(rexec, status);
1951 } else if (rexec->status == SIEVE_EXEC_OK) {
1952 /* Transaction start */
1953
1954 status = sieve_result_transaction_start(rexec);
1955
1956 /* Transaction execute */
1957
1958 status = sieve_result_transaction_execute(rexec, status);
1959 sieve_result_execute_update_status(rexec, status);
1960 }
1961
1962 if (!commit) {
1963 sieve_action_execution_post(rexec);
1964 rexec->ehandler = NULL;
1965
1966 /* Merge explicit keep status into implicit keep for the next
1967 execution round. */
1968 rexec->keep_implicit = (rexec->keep_explicit ||
1969 rexec->keep_implicit);
1970 rexec->keep_explicit = FALSE;
1971
1972 e_debug(rexec->event, "Finished executing result "
1973 "(no commit, status=%s, keep=%s)",
1974 sieve_execution_exitcode_to_str(rexec->status),
1975 (rexec->keep_implicit ? "yes" : "no"));
1976
1977 if (keep_r != NULL)
1978 *keep_r = rexec->keep_implicit;
1979 return rexec->status;
1980 }
1981
1982 /* Execute implicit keep if the transaction failed or when the
1983 implicit keep was not canceled during transaction.
1984 */
1985 if (rexec->status != SIEVE_EXEC_OK || rexec->keep_implicit)
1986 sieve_result_implicit_keep_execute(rexec);
1987
1988 /* Transaction commit/rollback */
1989
1990 status = sieve_result_transaction_commit_or_rollback(rexec, status);
1991 sieve_result_execute_update_status(rexec, status);
1992
1993 /* Commit implicit keep if necessary */
1994
1995 result_status = rexec->status;
1996
1997 /* Commit implicit keep if the transaction failed or when the
1998 implicit keep was not canceled during transaction.
1999 */
2000 if (rexec->status != SIEVE_EXEC_OK || rexec->keep_implicit) {
2001 ret = sieve_result_implicit_keep_finalize(rexec);
2002 switch (ret) {
2003 case SIEVE_EXEC_OK:
2004 if (result_status == SIEVE_EXEC_TEMP_FAILURE)
2005 result_status = SIEVE_EXEC_FAILURE;
2006 break;
2007 case SIEVE_EXEC_TEMP_FAILURE:
2008 case SIEVE_EXEC_RESOURCE_LIMIT:
2009 if (!rexec->committed) {
2010 result_status = ret;
2011 break;
2012 }
2013 /* fall through */
2014 default:
2015 result_status = SIEVE_EXEC_KEEP_FAILED;
2016 }
2017 }
2018 if (rexec->status == SIEVE_EXEC_OK)
2019 rexec->status = result_status;
2020
2021 /* Finish execution */
2022
2023 sieve_result_transaction_finish(rexec, rexec->status);
2024
2025 sieve_action_execution_post(rexec);
2026 rexec->ehandler = NULL;
2027
2028 rexec->status = result_status;
2029
2030 /* Merge explicit keep status into implicit keep (in this case only for
2031 completeness).
2032 */
2033 rexec->keep_implicit = (rexec->keep_explicit ||
2034 rexec->keep_implicit);
2035 rexec->keep_explicit = FALSE;
2036
2037 e_debug(rexec->event, "Finished executing result "
2038 "(final, status=%s, keep=%s)",
2039 sieve_execution_exitcode_to_str(result_status),
2040 (rexec->keep_implicit ? "yes" : "no"));
2041
2042 if (keep_r != NULL)
2043 *keep_r = rexec->keep_implicit;
2044 return result_status;
2045 }
2046
2047 /*
2048 * Result evaluation
2049 */
2050
2051 struct sieve_result_iterate_context {
2052 struct sieve_result *result;
2053 struct sieve_result_action *current_action;
2054 struct sieve_result_action *next_action;
2055 };
2056
2057 struct sieve_result_iterate_context *
sieve_result_iterate_init(struct sieve_result * result)2058 sieve_result_iterate_init(struct sieve_result *result)
2059 {
2060 struct sieve_result_iterate_context *rictx =
2061 t_new(struct sieve_result_iterate_context, 1);
2062
2063 rictx->result = result;
2064 rictx->current_action = NULL;
2065 rictx->next_action = result->actions_head;
2066
2067 return rictx;
2068 }
2069
2070 const struct sieve_action *
sieve_result_iterate_next(struct sieve_result_iterate_context * rictx,bool * keep)2071 sieve_result_iterate_next(struct sieve_result_iterate_context *rictx,
2072 bool *keep)
2073 {
2074 struct sieve_result_action *rac;
2075
2076 if (rictx == NULL)
2077 return NULL;
2078
2079 rac = rictx->current_action = rictx->next_action;
2080 if (rac != NULL) {
2081 rictx->next_action = rac->next;
2082
2083 if (keep != NULL)
2084 *keep = rac->action.keep;
2085
2086 return &rac->action;
2087 }
2088
2089 return NULL;
2090 }
2091
sieve_result_iterate_delete(struct sieve_result_iterate_context * rictx)2092 void sieve_result_iterate_delete(struct sieve_result_iterate_context *rictx)
2093 {
2094 struct sieve_result *result;
2095 struct sieve_result_action *rac;
2096
2097 if (rictx == NULL || rictx->current_action == NULL)
2098 return;
2099
2100 result = rictx->result;
2101 rac = rictx->current_action;
2102
2103 /* Delete action */
2104
2105 if (rac->prev == NULL)
2106 result->actions_head = rac->next;
2107 else
2108 rac->prev->next = rac->next;
2109
2110 if (rac->next == NULL)
2111 result->actions_tail = rac->prev;
2112 else
2113 rac->next->prev = rac->prev;
2114
2115 sieve_result_action_deinit(rac);
2116
2117 /* Skip to next action in iteration */
2118
2119 rictx->current_action = NULL;
2120 }
2121
2122 /*
2123 * Side effects list
2124 */
2125
2126 struct sieve_side_effects_list *
sieve_side_effects_list_create(struct sieve_result * result)2127 sieve_side_effects_list_create(struct sieve_result *result)
2128 {
2129 struct sieve_side_effects_list *list =
2130 p_new(result->pool, struct sieve_side_effects_list, 1);
2131
2132 list->result = result;
2133 list->first_effect = NULL;
2134 list->last_effect = NULL;
2135
2136 return list;
2137 }
2138
sieve_side_effects_list_add(struct sieve_side_effects_list * list,const struct sieve_side_effect * seffect)2139 void sieve_side_effects_list_add(struct sieve_side_effects_list *list,
2140 const struct sieve_side_effect *seffect)
2141 {
2142 struct sieve_result_side_effect *reffect, *reffect_pos;
2143
2144 /* Prevent duplicates */
2145 reffect = list->first_effect;
2146 reffect_pos = NULL;
2147 while (reffect != NULL) {
2148 const struct sieve_side_effect_def *ref_def = reffect->seffect.def;
2149 const struct sieve_side_effect_def *sef_def = seffect->def;
2150
2151 i_assert(ref_def != NULL);
2152 i_assert(sef_def != NULL);
2153
2154 if (sef_def == ref_def) {
2155 /* already listed */
2156 i_assert(reffect_pos == NULL);
2157 return;
2158 }
2159 if (sef_def->precedence > ref_def->precedence) {
2160 /* insert it before this position */
2161 reffect_pos = reffect;
2162 }
2163
2164 reffect = reffect->next;
2165 }
2166
2167 /* Create new side effect object */
2168 reffect = p_new(list->result->pool, struct sieve_result_side_effect, 1);
2169 reffect->seffect = *seffect;
2170
2171 if (reffect_pos != NULL) {
2172 /* Insert */
2173 reffect->next = reffect_pos;
2174 reffect_pos->prev = reffect;
2175 if (list->first_effect == reffect_pos)
2176 list->first_effect = reffect;
2177 } else {
2178 /* Add */
2179 if ( list->first_effect == NULL ) {
2180 list->first_effect = reffect;
2181 list->last_effect = reffect;
2182 reffect->prev = NULL;
2183 reffect->next = NULL;
2184 } else {
2185 list->last_effect->next = reffect;
2186 reffect->prev = list->last_effect;
2187 list->last_effect = reffect;
2188 reffect->next = NULL;
2189 }
2190 }
2191 }
2192
2193 /*
2194 * Error handling
2195 */
2196
2197 #undef sieve_result_error
sieve_result_error(const struct sieve_action_exec_env * aenv,const char * csrc_filename,unsigned int csrc_linenum,const char * fmt,...)2198 void sieve_result_error(const struct sieve_action_exec_env *aenv,
2199 const char *csrc_filename, unsigned int csrc_linenum,
2200 const char *fmt, ...)
2201 {
2202 struct sieve_error_params params = {
2203 .log_type = LOG_TYPE_ERROR,
2204 .event = aenv->event,
2205 .csrc = {
2206 .filename = csrc_filename,
2207 .linenum = csrc_linenum,
2208 },
2209 };
2210 va_list args;
2211
2212 va_start(args, fmt);
2213 sieve_logv(aenv->ehandler, ¶ms, fmt, args);
2214 va_end(args);
2215 }
2216
2217 #undef sieve_result_global_error
sieve_result_global_error(const struct sieve_action_exec_env * aenv,const char * csrc_filename,unsigned int csrc_linenum,const char * fmt,...)2218 void sieve_result_global_error(const struct sieve_action_exec_env *aenv,
2219 const char *csrc_filename,
2220 unsigned int csrc_linenum, const char *fmt, ...)
2221 {
2222 const struct sieve_execute_env *eenv = aenv->exec_env;
2223 struct sieve_error_params params = {
2224 .log_type = LOG_TYPE_ERROR,
2225 .event = aenv->event,
2226 .csrc = {
2227 .filename = csrc_filename,
2228 .linenum = csrc_linenum,
2229 },
2230 };
2231 va_list args;
2232
2233 va_start(args, fmt);
2234 sieve_global_logv(eenv->svinst, aenv->ehandler, ¶ms, fmt, args);
2235 va_end(args);
2236 }
2237
2238 #undef sieve_result_warning
sieve_result_warning(const struct sieve_action_exec_env * aenv,const char * csrc_filename,unsigned int csrc_linenum,const char * fmt,...)2239 void sieve_result_warning(const struct sieve_action_exec_env *aenv,
2240 const char *csrc_filename, unsigned int csrc_linenum,
2241 const char *fmt, ...)
2242 {
2243 struct sieve_error_params params = {
2244 .log_type = LOG_TYPE_WARNING,
2245 .event = aenv->event,
2246 .csrc = {
2247 .filename = csrc_filename,
2248 .linenum = csrc_linenum,
2249 },
2250 };
2251 va_list args;
2252
2253 va_start(args, fmt);
2254 sieve_logv(aenv->ehandler, ¶ms, fmt, args);
2255 va_end(args);
2256 }
2257
2258 #undef sieve_result_global_warning
sieve_result_global_warning(const struct sieve_action_exec_env * aenv,const char * csrc_filename,unsigned int csrc_linenum,const char * fmt,...)2259 void sieve_result_global_warning(const struct sieve_action_exec_env *aenv,
2260 const char *csrc_filename,
2261 unsigned int csrc_linenum,
2262 const char *fmt, ...)
2263 {
2264 const struct sieve_execute_env *eenv = aenv->exec_env;
2265 struct sieve_error_params params = {
2266 .log_type = LOG_TYPE_WARNING,
2267 .event = aenv->event,
2268 .csrc = {
2269 .filename = csrc_filename,
2270 .linenum = csrc_linenum,
2271 },
2272 };
2273 va_list args;
2274
2275 va_start(args, fmt);
2276 sieve_global_logv(eenv->svinst, aenv->ehandler, ¶ms, fmt, args);
2277 va_end(args);
2278 }
2279
2280 #undef sieve_result_log
sieve_result_log(const struct sieve_action_exec_env * aenv,const char * csrc_filename,unsigned int csrc_linenum,const char * fmt,...)2281 void sieve_result_log(const struct sieve_action_exec_env *aenv,
2282 const char *csrc_filename, unsigned int csrc_linenum,
2283 const char *fmt, ...)
2284 {
2285 const struct sieve_execute_env *eenv = aenv->exec_env;
2286 struct sieve_error_params params = {
2287 .log_type = (HAS_ALL_BITS(eenv->flags,
2288 SIEVE_EXECUTE_FLAG_LOG_RESULT) ?
2289 LOG_TYPE_INFO : LOG_TYPE_DEBUG),
2290 .event = aenv->event,
2291 .csrc = {
2292 .filename = csrc_filename,
2293 .linenum = csrc_linenum,
2294 },
2295 };
2296 va_list args;
2297
2298 va_start(args, fmt);
2299 sieve_logv(aenv->ehandler, ¶ms, fmt, args);
2300 va_end(args);
2301 }
2302
2303 #undef sieve_result_global_log
sieve_result_global_log(const struct sieve_action_exec_env * aenv,const char * csrc_filename,unsigned int csrc_linenum,const char * fmt,...)2304 void sieve_result_global_log(const struct sieve_action_exec_env *aenv,
2305 const char *csrc_filename,
2306 unsigned int csrc_linenum, const char *fmt, ...)
2307 {
2308 const struct sieve_execute_env *eenv = aenv->exec_env;
2309 struct sieve_error_params params = {
2310 .log_type = (HAS_ALL_BITS(eenv->flags,
2311 SIEVE_EXECUTE_FLAG_LOG_RESULT) ?
2312 LOG_TYPE_INFO : LOG_TYPE_DEBUG),
2313 .event = aenv->event,
2314 .csrc = {
2315 .filename = csrc_filename,
2316 .linenum = csrc_linenum,
2317 },
2318 };
2319 va_list args;
2320
2321 va_start(args, fmt);
2322 sieve_global_logv(eenv->svinst, aenv->ehandler, ¶ms, fmt, args);
2323 va_end(args);
2324 }
2325
2326 #undef sieve_result_global_log_error
sieve_result_global_log_error(const struct sieve_action_exec_env * aenv,const char * csrc_filename,unsigned int csrc_linenum,const char * fmt,...)2327 void sieve_result_global_log_error(const struct sieve_action_exec_env *aenv,
2328 const char *csrc_filename,
2329 unsigned int csrc_linenum,
2330 const char *fmt, ...)
2331 {
2332 const struct sieve_execute_env *eenv = aenv->exec_env;
2333 struct sieve_error_params params = {
2334 .log_type = LOG_TYPE_ERROR,
2335 .event = aenv->event,
2336 .csrc = {
2337 .filename = csrc_filename,
2338 .linenum = csrc_linenum,
2339 },
2340 };
2341 va_list args;
2342
2343 va_start(args, fmt);
2344 sieve_global_info_logv(eenv->svinst, aenv->ehandler, ¶ms,
2345 fmt, args);
2346 va_end(args);
2347 }
2348
2349 #undef sieve_result_global_log_warning
sieve_result_global_log_warning(const struct sieve_action_exec_env * aenv,const char * csrc_filename,unsigned int csrc_linenum,const char * fmt,...)2350 void sieve_result_global_log_warning(const struct sieve_action_exec_env *aenv,
2351 const char *csrc_filename,
2352 unsigned int csrc_linenum,
2353 const char *fmt, ...)
2354 {
2355 const struct sieve_execute_env *eenv = aenv->exec_env;
2356 struct sieve_error_params params = {
2357 .log_type = LOG_TYPE_WARNING,
2358 .event = aenv->event,
2359 .csrc = {
2360 .filename = csrc_filename,
2361 .linenum = csrc_linenum,
2362 },
2363 };
2364 va_list args;
2365
2366 va_start(args, fmt);
2367 sieve_global_info_logv(eenv->svinst, aenv->ehandler, ¶ms,
2368 fmt, args);
2369 va_end(args);
2370 }
2371
2372 #undef sieve_result_event_log
sieve_result_event_log(const struct sieve_action_exec_env * aenv,const char * csrc_filename,unsigned int csrc_linenum,struct event * event,const char * fmt,...)2373 void sieve_result_event_log(const struct sieve_action_exec_env *aenv,
2374 const char *csrc_filename,
2375 unsigned int csrc_linenum, struct event *event,
2376 const char *fmt, ...)
2377 {
2378 const struct sieve_execute_env *eenv = aenv->exec_env;
2379 struct sieve_error_params params = {
2380 .log_type = (HAS_ALL_BITS(eenv->flags,
2381 SIEVE_EXECUTE_FLAG_LOG_RESULT) ?
2382 LOG_TYPE_INFO : LOG_TYPE_DEBUG),
2383 .event = event,
2384 .csrc = {
2385 .filename = csrc_filename,
2386 .linenum = csrc_linenum,
2387 },
2388 };
2389 va_list args;
2390
2391 va_start(args, fmt);
2392 sieve_global_logv(eenv->svinst, aenv->ehandler, ¶ms, fmt, args);
2393 va_end(args);
2394 }
2395
2396
2397 #undef sieve_result_critical
sieve_result_critical(const struct sieve_action_exec_env * aenv,const char * csrc_filename,unsigned int csrc_linenum,const char * user_prefix,const char * fmt,...)2398 void sieve_result_critical(const struct sieve_action_exec_env *aenv,
2399 const char *csrc_filename, unsigned int csrc_linenum,
2400 const char *user_prefix, const char *fmt, ...)
2401 {
2402 const struct sieve_execute_env *eenv = aenv->exec_env;
2403 struct sieve_error_params params = {
2404 .log_type = LOG_TYPE_ERROR,
2405 .event = aenv->event,
2406 .csrc = {
2407 .filename = csrc_filename,
2408 .linenum = csrc_linenum,
2409 },
2410 };
2411 va_list args;
2412
2413 va_start(args, fmt);
2414
2415 T_BEGIN {
2416 sieve_criticalv(eenv->svinst, aenv->ehandler, ¶ms,
2417 user_prefix, fmt, args);
2418 } T_END;
2419
2420 va_end(args);
2421 }
2422
2423 #undef sieve_result_mail_error
sieve_result_mail_error(const struct sieve_action_exec_env * aenv,struct mail * mail,const char * csrc_filename,unsigned int csrc_linenum,const char * fmt,...)2424 int sieve_result_mail_error(const struct sieve_action_exec_env *aenv,
2425 struct mail *mail,
2426 const char *csrc_filename,
2427 unsigned int csrc_linenum, const char *fmt, ...)
2428 {
2429 const char *error_msg, *user_prefix;
2430 va_list args;
2431
2432 error_msg = mailbox_get_last_internal_error(mail->box, NULL);
2433
2434 va_start(args, fmt);
2435 user_prefix = t_strdup_vprintf(fmt, args);
2436 sieve_result_critical(aenv, csrc_filename, csrc_linenum,
2437 user_prefix, "%s: %s", user_prefix, error_msg);
2438 va_end(args);
2439
2440 return SIEVE_EXEC_TEMP_FAILURE;
2441 }
2442