Coverage Report

Created: 2026-07-16 07:09

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