Coverage Report

Created: 2026-04-12 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/ext-envelope.c
Line
Count
Source
1
/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2
 */
3
4
/* Extension envelope
5
 * ------------------
6
 *
7
 * Authors: Stephan Bosch
8
 * Specification: RFC 5228
9
 * Implementation: full
10
 * Status: testing
11
 *
12
 */
13
14
#include "lib.h"
15
#include "str-sanitize.h"
16
#include "array.h"
17
18
#include "sieve-common.h"
19
#include "sieve-extensions.h"
20
#include "sieve-commands.h"
21
#include "sieve-stringlist.h"
22
#include "sieve-code.h"
23
#include "sieve-address.h"
24
#include "sieve-comparators.h"
25
#include "sieve-match-types.h"
26
#include "sieve-address-parts.h"
27
#include "sieve-message.h"
28
29
#include "sieve-validator.h"
30
#include "sieve-generator.h"
31
#include "sieve-interpreter.h"
32
#include "sieve-dump.h"
33
#include "sieve-match.h"
34
35
/*
36
 * Forward declarations
37
 */
38
39
static const struct sieve_command_def envelope_test;
40
const struct sieve_operation_def envelope_operation;
41
const struct sieve_extension_def envelope_extension;
42
43
/*
44
 * Extension
45
 */
46
47
static bool
48
ext_envelope_validator_load(const struct sieve_extension *ext,
49
          struct sieve_validator *valdtr);
50
static bool
51
ext_envelope_interpreter_load(const struct sieve_extension *ext,
52
            const struct sieve_runtime_env *renv,
53
            sieve_size_t *address);
54
55
static bool
56
ext_envelope_validator_validate(const struct sieve_extension *ext,
57
        struct sieve_validator *valdtr, void *context,
58
        struct sieve_ast_argument *require_arg,
59
        bool required);
60
static int
61
ext_envelope_interpreter_run(const struct sieve_extension *this_ext,
62
           const struct sieve_runtime_env *renv,
63
           void *context, bool deferred);
64
65
const struct sieve_extension_def envelope_extension = {
66
  .name = "envelope",
67
  .interpreter_load = ext_envelope_interpreter_load,
68
  .validator_load = ext_envelope_validator_load,
69
  SIEVE_EXT_DEFINE_OPERATION(envelope_operation)
70
};
71
const struct sieve_validator_extension
72
envelope_validator_extension = {
73
  .ext = &envelope_extension,
74
  .validate = ext_envelope_validator_validate
75
};
76
const struct sieve_interpreter_extension
77
envelope_interpreter_extension = {
78
  .ext_def = &envelope_extension,
79
  .run = ext_envelope_interpreter_run
80
};
81
82
static bool
83
ext_envelope_validator_load(const struct sieve_extension *ext,
84
          struct sieve_validator *valdtr)
85
0
{
86
  /* Register new test */
87
0
  sieve_validator_register_command(valdtr, ext, &envelope_test);
88
89
0
  sieve_validator_extension_register(valdtr, ext,
90
0
             &envelope_validator_extension, NULL);
91
0
  return TRUE;
92
0
}
93
94
static bool
95
ext_envelope_interpreter_load(const struct sieve_extension *ext,
96
            const struct sieve_runtime_env *renv,
97
            sieve_size_t *address ATTR_UNUSED)
98
0
{
99
0
  sieve_interpreter_extension_register(renv->interp, ext,
100
0
               &envelope_interpreter_extension,
101
0
               NULL);
102
0
  return TRUE;
103
0
}
104
105
static bool
106
ext_envelope_validator_validate(const struct sieve_extension *ext,
107
        struct sieve_validator *valdtr,
108
        void *context ATTR_UNUSED,
109
        struct sieve_ast_argument *require_arg,
110
        bool required)
111
0
{
112
0
  if (required) {
113
0
    enum sieve_compile_flags flags =
114
0
      sieve_validator_compile_flags(valdtr);
115
116
0
    if ((flags & SIEVE_COMPILE_FLAG_NO_ENVELOPE) != 0) {
117
0
      sieve_argument_validate_error(
118
0
        valdtr, require_arg,
119
0
        "the %s extension cannot be used in this context "
120
0
        "(needs access to message envelope)",
121
0
        sieve_extension_name(ext));
122
0
      return FALSE;
123
0
    }
124
0
  }
125
0
  return TRUE;
126
0
}
127
128
static int
129
ext_envelope_interpreter_run(const struct sieve_extension *ext,
130
           const struct sieve_runtime_env *renv,
131
           void *context ATTR_UNUSED, bool deferred)
132
0
{
133
0
  const struct sieve_execute_env *eenv = renv->exec_env;
134
135
0
  if ((eenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) != 0) {
136
0
    if (!deferred) {
137
0
      sieve_runtime_error(
138
0
        renv, NULL,
139
0
        "the %s extension cannot be used in this context "
140
0
        "(needs access to message envelope)",
141
0
        sieve_extension_name(ext));
142
0
    }
143
0
    return SIEVE_EXEC_FAILURE;
144
0
  }
145
0
  return SIEVE_EXEC_OK;
146
0
}
147
148
/*
149
 * Envelope test
150
 *
151
 * Syntax
152
 *   envelope [COMPARATOR] [ADDRESS-PART] [MATCH-TYPE]
153
 *     <envelope-part: string-list> <key-list: string-list>
154
 */
155
156
static bool
157
tst_envelope_registered(struct sieve_validator *valdtr,
158
      const struct sieve_extension *ext,
159
      struct sieve_command_registration *cmd_reg);
160
static bool
161
tst_envelope_validate(struct sieve_validator *valdtr,
162
          struct sieve_command *tst);
163
static bool
164
tst_envelope_generate(const struct sieve_codegen_env *cgenv,
165
          struct sieve_command *ctx);
166
167
static const struct sieve_command_def envelope_test = {
168
  .identifier = "envelope",
169
  .type = SCT_TEST,
170
  .positional_args= 2,
171
  .subtests = 0,
172
  .block_allowed = FALSE,
173
  .block_required = FALSE,
174
  .registered = tst_envelope_registered,
175
  .validate = tst_envelope_validate,
176
  .generate = tst_envelope_generate
177
};
178
179
/*
180
 * Envelope operation
181
 */
182
183
static bool
184
ext_envelope_operation_dump(const struct sieve_dumptime_env *denv,
185
          sieve_size_t *address);
186
static int
187
ext_envelope_operation_execute(const struct sieve_runtime_env *renv,
188
             sieve_size_t *address);
189
190
const struct sieve_operation_def envelope_operation = {
191
  .mnemonic = "ENVELOPE",
192
  .ext_def = &envelope_extension,
193
  .dump = ext_envelope_operation_dump,
194
  .execute = ext_envelope_operation_execute
195
};
196
197
/*
198
 * Envelope parts
199
 *
200
 * FIXME: not available to extensions
201
 */
202
203
struct sieve_envelope_part {
204
  const char *identifier;
205
206
  const struct smtp_address *const *(*get_addresses)
207
    (const struct sieve_runtime_env *renv);
208
  const char *const *(*get_values)
209
    (const struct sieve_runtime_env *renv);
210
};
211
212
static const struct smtp_address *const *
213
_from_part_get_addresses(const struct sieve_runtime_env *renv);
214
static const char *const *
215
_from_part_get_values(const struct sieve_runtime_env *renv);
216
static const struct smtp_address *const *
217
_to_part_get_addresses(const struct sieve_runtime_env *renv);
218
static const char *const *
219
_to_part_get_values(const struct sieve_runtime_env *renv);
220
static const char *const *
221
_auth_part_get_values(const struct sieve_runtime_env *renv);
222
223
static const struct sieve_envelope_part _from_part = {
224
  "from",
225
  _from_part_get_addresses,
226
  _from_part_get_values,
227
};
228
229
static const struct sieve_envelope_part _to_part = {
230
  "to",
231
  _to_part_get_addresses,
232
  _to_part_get_values,
233
};
234
235
static const struct sieve_envelope_part _auth_part = {
236
  "auth",
237
  NULL,
238
  _auth_part_get_values,
239
};
240
241
static const struct sieve_envelope_part *_envelope_parts[] = {
242
  /* Required */
243
  &_from_part, &_to_part,
244
245
  /* Non-standard */
246
  &_auth_part
247
};
248
249
static unsigned int _envelope_part_count = N_ELEMENTS(_envelope_parts);
250
251
static const struct sieve_envelope_part *
252
_envelope_part_find(const char *identifier)
253
0
{
254
0
  unsigned int i;
255
256
0
  for (i = 0; i < _envelope_part_count; i++) {
257
0
    if (strcasecmp(_envelope_parts[i]->identifier,
258
0
             identifier) == 0)
259
0
      return _envelope_parts[i];
260
0
  }
261
262
0
  return NULL;
263
0
}
264
265
/* Envelope parts implementation */
266
267
static const struct smtp_address *const *
268
_from_part_get_addresses(const struct sieve_runtime_env *renv)
269
0
{
270
0
  ARRAY(const struct smtp_address *) envelope_values;
271
0
  const struct smtp_address *address =
272
0
    sieve_message_get_sender(renv->msgctx);
273
274
0
  t_array_init(&envelope_values, 2);
275
276
0
  if (address == NULL)
277
0
    address = smtp_address_create_temp(NULL, NULL);
278
0
  array_append(&envelope_values, &address, 1);
279
280
0
  (void)array_append_space(&envelope_values);
281
0
  return array_idx(&envelope_values, 0);
282
0
}
283
284
static const char *const *
285
_from_part_get_values(const struct sieve_runtime_env *renv)
286
0
{
287
0
  ARRAY(const char *)envelope_values;
288
0
  const struct smtp_address *address =
289
0
    sieve_message_get_sender(renv->msgctx);
290
0
  const char *value;
291
292
0
  t_array_init(&envelope_values, 2);
293
294
0
  value = "";
295
0
  if (!smtp_address_isnull(address))
296
0
    value = smtp_address_encode(address);
297
0
  array_append(&envelope_values, &value, 1);
298
299
0
  (void)array_append_space(&envelope_values);
300
301
0
  return array_idx(&envelope_values, 0);
302
0
}
303
304
static const struct smtp_address *const *
305
_to_part_get_addresses(const struct sieve_runtime_env *renv)
306
0
{
307
0
  ARRAY(const struct smtp_address *) envelope_values;
308
0
  const struct smtp_address *address =
309
0
    sieve_message_get_orig_recipient(renv->msgctx);
310
311
0
  if (address != NULL && address->localpart != NULL) {
312
0
    t_array_init(&envelope_values, 2);
313
314
0
    array_append(&envelope_values, &address, 1);
315
316
0
    (void)array_append_space(&envelope_values);
317
0
    return array_idx(&envelope_values, 0);
318
0
  }
319
0
  return NULL;
320
0
}
321
322
static const char *const *
323
_to_part_get_values(const struct sieve_runtime_env *renv)
324
0
{
325
0
  ARRAY(const char *) envelope_values;
326
0
  const struct smtp_address *address =
327
0
    sieve_message_get_orig_recipient(renv->msgctx);
328
329
0
  t_array_init(&envelope_values, 2);
330
331
0
  if (address != NULL && address->localpart != NULL) {
332
0
    const char *value = smtp_address_encode(address);
333
0
    array_append(&envelope_values, &value, 1);
334
0
  }
335
336
0
  (void)array_append_space(&envelope_values);
337
338
0
  return array_idx(&envelope_values, 0);
339
0
}
340
341
static const char *const *
342
_auth_part_get_values(const struct sieve_runtime_env *renv)
343
0
{
344
0
  const struct sieve_execute_env *eenv = renv->exec_env;
345
0
  ARRAY(const char *) envelope_values;
346
347
0
  t_array_init(&envelope_values, 2);
348
349
0
  if (eenv->msgdata->auth_user != NULL)
350
0
    array_append(&envelope_values, &eenv->msgdata->auth_user, 1);
351
352
0
  (void)array_append_space(&envelope_values);
353
354
0
  return array_idx(&envelope_values, 0);
355
0
}
356
357
/*
358
 * Envelope address list
359
 */
360
361
/* Forward declarations */
362
363
static int
364
sieve_envelope_address_list_next_string_item(struct sieve_stringlist *_strlist,
365
               string_t **str_r);
366
static int
367
sieve_envelope_address_list_next_item(struct sieve_address_list *_addrlist,
368
              struct smtp_address *addr_r,
369
              string_t **unparsed_r);
370
static void
371
sieve_envelope_address_list_reset(struct sieve_stringlist *_strlist);
372
373
/* Stringlist object */
374
375
struct sieve_envelope_address_list {
376
  struct sieve_address_list addrlist;
377
378
  struct sieve_stringlist *env_parts;
379
380
  const struct smtp_address *const *cur_addresses;
381
  const char *const *cur_values;
382
383
  int value_index;
384
};
385
386
static struct sieve_address_list *
387
sieve_envelope_address_list_create(const struct sieve_runtime_env *renv,
388
           struct sieve_stringlist *env_parts)
389
0
{
390
0
  struct sieve_envelope_address_list *addrlist;
391
392
0
  addrlist = t_new(struct sieve_envelope_address_list, 1);
393
0
  addrlist->addrlist.strlist.runenv = renv;
394
0
  addrlist->addrlist.strlist.exec_status = SIEVE_EXEC_OK;
395
0
  addrlist->addrlist.strlist.next_item =
396
0
    sieve_envelope_address_list_next_string_item;
397
0
  addrlist->addrlist.strlist.reset = sieve_envelope_address_list_reset;
398
0
  addrlist->addrlist.next_item = sieve_envelope_address_list_next_item;
399
0
  addrlist->env_parts = env_parts;
400
401
0
  return &addrlist->addrlist;
402
0
}
403
404
static int
405
sieve_envelope_address_list_next_item(struct sieve_address_list *_addrlist,
406
              struct smtp_address *addr_r,
407
              string_t **unparsed_r)
408
0
{
409
0
  struct sieve_envelope_address_list *addrlist =
410
0
    (struct sieve_envelope_address_list *)_addrlist;
411
0
  const struct sieve_runtime_env *renv = _addrlist->strlist.runenv;
412
413
0
  if (addr_r != NULL)
414
0
    smtp_address_init(addr_r, NULL, NULL);
415
0
  if (unparsed_r != NULL) *unparsed_r = NULL;
416
417
0
  while (addrlist->cur_addresses == NULL &&
418
0
         addrlist->cur_values == NULL) {
419
0
    const struct sieve_envelope_part *epart;
420
0
    string_t *envp_item = NULL;
421
0
    int ret;
422
423
    /* Read next header value from source list */
424
0
    if ((ret = sieve_stringlist_next_item(addrlist->env_parts,
425
0
                  &envp_item)) <= 0)
426
0
      return ret;
427
428
0
    if (_addrlist->strlist.trace) {
429
0
      sieve_runtime_trace(
430
0
        _addrlist->strlist.runenv, 0,
431
0
        "getting '%s' part from message envelope",
432
0
        str_sanitize(str_c(envp_item), 80));
433
0
    }
434
435
0
    if ((epart=_envelope_part_find(str_c(envp_item))) != NULL) {
436
0
      addrlist->value_index = 0;
437
438
0
      if (epart->get_addresses != NULL) {
439
        /* Field contains addresses */
440
0
        addrlist->cur_addresses =
441
0
          epart->get_addresses(renv);
442
443
        /* Drop empty list */
444
0
        if (addrlist->cur_addresses != NULL &&
445
0
            addrlist->cur_addresses[0] == NULL)
446
0
          addrlist->cur_addresses = NULL;
447
0
      }
448
449
0
      if (addrlist->cur_addresses == NULL &&
450
0
          epart->get_values != NULL) {
451
        /* Field contains something else */
452
0
        addrlist->cur_values = epart->get_values(renv);
453
454
        /* Drop empty list */
455
0
        if (addrlist->cur_values != NULL &&
456
0
            addrlist->cur_values[0] == NULL)
457
0
          addrlist->cur_values = NULL;
458
0
      }
459
0
    }
460
0
  }
461
462
  /* Return next item */
463
0
  if (addrlist->cur_addresses != NULL) {
464
0
    const struct smtp_address *addr =
465
0
      addrlist->cur_addresses[addrlist->value_index];
466
467
0
    if (addr->localpart == NULL) {
468
      /* Null path <> */
469
0
      if (unparsed_r != NULL)
470
0
        *unparsed_r = t_str_new_const("", 0);
471
0
    } else {
472
0
      if (addr_r != NULL)
473
0
        *addr_r = *addr;
474
0
    }
475
476
    /* Advance to next value */
477
0
    addrlist->value_index++;
478
0
    if (addrlist->cur_addresses[addrlist->value_index] == NULL) {
479
0
      addrlist->cur_addresses = NULL;
480
0
      addrlist->value_index = 0;
481
0
    }
482
0
  } else {
483
0
    if (unparsed_r != NULL) {
484
0
      const char *value =
485
0
        addrlist->cur_values[addrlist->value_index];
486
487
0
      *unparsed_r = t_str_new_const(value, strlen(value));
488
0
    }
489
490
    /* Advance to next value */
491
0
    addrlist->value_index++;
492
0
    if (addrlist->cur_values[addrlist->value_index] == NULL) {
493
0
      addrlist->cur_values = NULL;
494
0
      addrlist->value_index = 0;
495
0
    }
496
0
  }
497
498
0
  return 1;
499
0
}
500
501
static int
502
sieve_envelope_address_list_next_string_item(struct sieve_stringlist *_strlist,
503
               string_t **str_r)
504
0
{
505
0
  struct sieve_address_list *addrlist =
506
0
    (struct sieve_address_list *)_strlist;
507
0
  struct smtp_address addr;
508
0
  int ret;
509
510
0
  if ((ret=sieve_envelope_address_list_next_item(addrlist, &addr,
511
0
                   str_r)) <= 0)
512
0
    return ret;
513
514
0
  if (addr.localpart != NULL) {
515
0
    const char *addr_str = smtp_address_encode(&addr);
516
0
    if (str_r != NULL)
517
0
      *str_r = t_str_new_const(addr_str, strlen(addr_str));
518
0
  }
519
0
  return 1;
520
0
}
521
522
static void
523
sieve_envelope_address_list_reset(struct sieve_stringlist *_strlist)
524
0
{
525
0
  struct sieve_envelope_address_list *addrlist =
526
0
    (struct sieve_envelope_address_list *)_strlist;
527
528
0
  sieve_stringlist_reset(addrlist->env_parts);
529
0
  addrlist->cur_addresses = NULL;
530
0
  addrlist->cur_values = NULL;
531
0
  addrlist->value_index = 0;
532
0
}
533
534
/*
535
 * Command Registration
536
 */
537
538
static bool
539
tst_envelope_registered(struct sieve_validator *valdtr,
540
      const struct sieve_extension *ext ATTR_UNUSED,
541
      struct sieve_command_registration *cmd_reg)
542
0
{
543
  /* The order of these is not significant */
544
0
  sieve_comparators_link_tag(valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
545
0
  sieve_match_types_link_tags(valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
546
0
  sieve_address_parts_link_tags(valdtr, cmd_reg, SIEVE_AM_OPT_ADDRESS_PART);
547
0
  return TRUE;
548
0
}
549
550
/*
551
 * Validation
552
 */
553
554
static int
555
_envelope_part_is_supported(void *context, struct sieve_ast_argument *arg)
556
0
{
557
0
  const struct sieve_envelope_part **not_address =
558
0
    (const struct sieve_envelope_part **) context;
559
560
0
  if (sieve_argument_is_string_literal(arg)) {
561
0
    const struct sieve_envelope_part *epart;
562
563
0
    if ((epart=_envelope_part_find(
564
0
      sieve_ast_strlist_strc(arg))) != NULL) {
565
0
      if (epart->get_addresses == NULL) {
566
0
        if (*not_address == NULL)
567
0
          *not_address = epart;
568
0
      }
569
0
      return 1;
570
0
    }
571
0
    return 0;
572
0
  }
573
0
  return 1; /* Can't check at compile time */
574
0
}
575
576
static bool
577
tst_envelope_validate(struct sieve_validator *valdtr, struct sieve_command *tst)
578
0
{
579
0
  struct sieve_ast_argument *arg = tst->first_positional;
580
0
  struct sieve_ast_argument *epart;
581
0
  struct sieve_comparator cmp_default =
582
0
    SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
583
0
  struct sieve_match_type mcht_default =
584
0
    SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
585
0
  const struct sieve_envelope_part *not_address = NULL;
586
587
0
  if (!sieve_validate_positional_argument(valdtr, tst, arg,
588
0
            "envelope part", 1,
589
0
            SAAT_STRING_LIST)) {
590
0
    return FALSE;
591
0
  }
592
593
0
  if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
594
0
    return FALSE;
595
596
  /* Check whether supplied envelope parts are supported
597
   *   FIXME: verify dynamic envelope parts at runtime
598
   */
599
0
  epart = arg;
600
0
  if (sieve_ast_stringlist_map(&epart, &not_address,
601
0
             _envelope_part_is_supported) <= 0) {
602
0
    i_assert(epart != NULL);
603
0
    sieve_argument_validate_error(
604
0
      valdtr, epart,
605
0
      "specified envelope part '%s' is not supported by the envelope test",
606
0
      str_sanitize(sieve_ast_strlist_strc(epart), 64));
607
0
    return FALSE;
608
0
  }
609
610
0
  if (not_address != NULL) {
611
0
    struct sieve_ast_argument *addrp_arg =
612
0
      sieve_command_find_argument(tst, &address_part_tag);
613
614
0
    if (addrp_arg != NULL) {
615
0
      sieve_argument_validate_error(
616
0
        valdtr, addrp_arg,
617
0
        "address part ':%s' specified while non-address envelope part '%s' "
618
0
        "is tested with the envelope test",
619
0
      sieve_ast_argument_tag(addrp_arg),
620
0
                 not_address->identifier);
621
0
      return FALSE;
622
0
    }
623
0
  }
624
625
0
  arg = sieve_ast_argument_next(arg);
626
627
0
  if (!sieve_validate_positional_argument(valdtr, tst, arg, "key list", 2,
628
0
            SAAT_STRING_LIST))
629
0
    return FALSE;
630
631
0
  if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
632
0
    return FALSE;
633
634
  /* Validate the key argument to a specified match type */
635
0
  return sieve_match_type_validate(valdtr, tst, arg,
636
0
           &mcht_default, &cmp_default);
637
0
}
638
639
/*
640
 * Code generation
641
 */
642
643
static bool
644
tst_envelope_generate(const struct sieve_codegen_env *cgenv,
645
          struct sieve_command *cmd)
646
0
{
647
0
  (void)sieve_operation_emit(cgenv->sblock, cmd->ext,
648
0
           &envelope_operation);
649
650
  /* Generate arguments */
651
0
  if (!sieve_generate_arguments(cgenv, cmd, NULL))
652
0
    return FALSE;
653
0
  return TRUE;
654
0
}
655
656
/*
657
 * Code dump
658
 */
659
660
static bool
661
ext_envelope_operation_dump(const struct sieve_dumptime_env *denv,
662
          sieve_size_t *address)
663
0
{
664
0
  sieve_code_dumpf(denv, "ENVELOPE");
665
0
  sieve_code_descend(denv);
666
667
  /* Handle any optional arguments */
668
0
  if (sieve_addrmatch_opr_optional_dump(denv, address, NULL) != 0)
669
0
    return FALSE;
670
671
0
  return (sieve_opr_stringlist_dump(denv, address, "envelope part") &&
672
0
    sieve_opr_stringlist_dump(denv, address, "key list"));
673
0
}
674
675
/*
676
 * Interpretation
677
 */
678
679
static int
680
ext_envelope_operation_execute(const struct sieve_runtime_env *renv,
681
             sieve_size_t *address)
682
0
{
683
0
  struct sieve_comparator cmp =
684
0
    SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
685
0
  struct sieve_match_type mcht =
686
0
    SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
687
0
  struct sieve_address_part addrp =
688
0
    SIEVE_ADDRESS_PART_DEFAULT(all_address_part);
689
0
  struct sieve_stringlist *env_part_list, *value_list, *key_list;
690
0
  struct sieve_address_list *addr_list;
691
0
  int match, ret;
692
693
  /*
694
   * Read operands
695
   */
696
697
  /* Read optional operands */
698
0
  if (sieve_addrmatch_opr_optional_read(renv, address, NULL, &ret,
699
0
                &addrp, &mcht, &cmp) < 0)
700
0
    return ret;
701
702
  /* Read envelope-part */
703
0
  if ((ret = sieve_opr_stringlist_read(renv, address, "envelope-part",
704
0
               &env_part_list)) <= 0)
705
0
    return ret;
706
707
  /* Read key-list */
708
0
  if ((ret = sieve_opr_stringlist_read(renv, address, "key-list",
709
0
               &key_list)) <= 0)
710
0
    return ret;
711
712
  /*
713
   * Perform test
714
   */
715
716
0
  sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "envelope test");
717
718
  /* Create value stringlist */
719
0
  addr_list = sieve_envelope_address_list_create(renv, env_part_list);
720
0
  value_list = sieve_address_part_stringlist_create(renv, &addrp,
721
0
                addr_list);
722
723
  /* Perform match */
724
0
  if ((match = sieve_match(renv, &mcht, &cmp,
725
0
         value_list, key_list, &ret)) < 0)
726
0
    return ret;
727
728
  /* Set test result for subsequent conditional jump */
729
0
  sieve_interpreter_set_test_result(renv->interp, match > 0);
730
0
  return SIEVE_EXEC_OK;
731
0
}
732