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, &params, 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, &params, 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, &params, 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, &params, 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, &params, 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, &params, 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, &params,
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, &params,
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, &params, 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, &params,
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