1
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
7
* Authors: Stephan Bosch
8
* Specification: RFC5228
10
* Status: experimental, largely untested
15
#include "str-sanitize.h"
18
#include "sieve-common.h"
19
#include "sieve-extensions.h"
20
#include "sieve-commands.h"
21
#include "sieve-code.h"
22
#include "sieve-address.h"
23
#include "sieve-comparators.h"
24
#include "sieve-match-types.h"
25
#include "sieve-address-parts.h"
26
#include "sieve-message.h"
28
#include "sieve-validator.h"
29
#include "sieve-generator.h"
30
#include "sieve-interpreter.h"
31
#include "sieve-dump.h"
32
#include "sieve-match.h"
35
* Forward declarations
38
static const struct sieve_command envelope_test;
39
const struct sieve_operation envelope_operation;
40
const struct sieve_extension envelope_extension;
46
static bool ext_envelope_validator_load(struct sieve_validator *validator);
48
static int ext_my_id = -1;
50
const struct sieve_extension envelope_extension = {
54
ext_envelope_validator_load,
55
NULL, NULL, NULL, NULL, NULL,
56
SIEVE_EXT_DEFINE_OPERATION(envelope_operation),
57
SIEVE_EXT_DEFINE_NO_OPERANDS
60
static bool ext_envelope_validator_load(struct sieve_validator *validator)
62
/* Register new test */
63
sieve_validator_register_command(validator, &envelope_test);
72
* envelope [COMPARATOR] [ADDRESS-PART] [MATCH-TYPE]
73
* <envelope-part: string-list> <key-list: string-list>
76
static bool tst_envelope_registered
77
(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg);
78
static bool tst_envelope_validate
79
(struct sieve_validator *validator, struct sieve_command_context *tst);
80
static bool tst_envelope_generate
81
(const struct sieve_codegen_env *cgenv, struct sieve_command_context *ctx);
83
static const struct sieve_command envelope_test = {
87
tst_envelope_registered,
89
tst_envelope_validate,
90
tst_envelope_generate,
98
static bool ext_envelope_operation_dump
99
(const struct sieve_operation *op,
100
const struct sieve_dumptime_env *denv, sieve_size_t *address);
101
static int ext_envelope_operation_execute
102
(const struct sieve_operation *op,
103
const struct sieve_runtime_env *renv, sieve_size_t *address);
105
const struct sieve_operation envelope_operation = {
109
ext_envelope_operation_dump,
110
ext_envelope_operation_execute
116
* FIXME: not available to extensions
119
struct sieve_envelope_part {
120
const char *identifier;
122
const struct sieve_address *const *(*get_addresses)
123
(const struct sieve_runtime_env *renv);
124
const char * const *(*get_values)
125
(const struct sieve_runtime_env *renv);
128
static const struct sieve_address *const *_from_part_get_addresses
129
(const struct sieve_runtime_env *renv);
130
static const char *const *_from_part_get_values
131
(const struct sieve_runtime_env *renv);
132
static const struct sieve_address *const *_to_part_get_addresses
133
(const struct sieve_runtime_env *renv);
134
static const char *const *_to_part_get_values
135
(const struct sieve_runtime_env *renv);
136
static const char *const *_auth_part_get_values
137
(const struct sieve_runtime_env *renv);
139
static const struct sieve_envelope_part _from_part = {
141
_from_part_get_addresses,
142
_from_part_get_values,
145
static const struct sieve_envelope_part _to_part = {
147
_to_part_get_addresses,
151
static const struct sieve_envelope_part _auth_part = {
154
_auth_part_get_values,
157
static const struct sieve_envelope_part *_envelope_parts[] = {
159
&_from_part, &_to_part,
165
static unsigned int _envelope_part_count = N_ELEMENTS(_envelope_parts);
167
static const struct sieve_envelope_part *_envelope_part_find
168
(const char *identifier)
172
for ( i = 0; i < _envelope_part_count; i++ ) {
173
if ( strcasecmp( _envelope_parts[i]->identifier, identifier ) == 0 ) {
174
return _envelope_parts[i];
183
* Command Registration
186
static bool tst_envelope_registered
187
(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg)
189
/* The order of these is not significant */
190
sieve_comparators_link_tag(validator, cmd_reg, SIEVE_AM_OPT_COMPARATOR);
191
sieve_address_parts_link_tags(validator, cmd_reg, SIEVE_AM_OPT_ADDRESS_PART);
192
sieve_match_types_link_tags(validator, cmd_reg, SIEVE_AM_OPT_MATCH_TYPE);
201
static int _envelope_part_is_supported
202
(void *context, struct sieve_ast_argument *arg)
204
const struct sieve_envelope_part **not_address =
205
(const struct sieve_envelope_part **) context;
207
if ( sieve_argument_is_string_literal(arg) ) {
208
const struct sieve_envelope_part *epart;
210
if ( (epart=_envelope_part_find(sieve_ast_strlist_strc(arg))) != NULL ) {
211
if ( epart->get_addresses == NULL ) {
212
if ( *not_address == NULL )
213
*not_address = epart;
222
return TRUE; /* Can't check at compile time */
225
static bool tst_envelope_validate
226
(struct sieve_validator *validator, struct sieve_command_context *tst)
228
struct sieve_ast_argument *arg = tst->first_positional;
229
struct sieve_ast_argument *epart;
230
const struct sieve_envelope_part *not_address = NULL;
232
if ( !sieve_validate_positional_argument
233
(validator, tst, arg, "envelope part", 1, SAAT_STRING_LIST) ) {
237
if ( !sieve_validator_argument_activate(validator, tst, arg, FALSE) )
240
/* Check whether supplied envelope parts are supported
241
* FIXME: verify dynamic envelope parts at runtime
244
if ( !sieve_ast_stringlist_map(&epart, (void *) ¬_address,
245
_envelope_part_is_supported) ) {
247
sieve_argument_validate_error(validator, epart,
248
"specified envelope part '%s' is not supported by the envelope test",
249
str_sanitize(sieve_ast_strlist_strc(epart), 64));
253
if ( not_address != NULL ) {
254
struct sieve_ast_argument *addrp_arg =
255
sieve_command_find_argument(tst, &address_part_tag);
257
if ( addrp_arg != NULL ) {
258
sieve_argument_validate_error(validator, addrp_arg,
259
"address part ':%s' specified while non-address envelope part '%s' "
260
"is tested with the envelope test",
261
sieve_ast_argument_tag(addrp_arg), not_address->identifier);
266
arg = sieve_ast_argument_next(arg);
268
if ( !sieve_validate_positional_argument
269
(validator, tst, arg, "key list", 2, SAAT_STRING_LIST) ) {
273
if ( !sieve_validator_argument_activate(validator, tst, arg, FALSE) )
276
/* Validate the key argument to a specified match type */
277
return sieve_match_type_validate
278
(validator, tst, arg, &is_match_type, &i_ascii_casemap_comparator);
285
static bool tst_envelope_generate
286
(const struct sieve_codegen_env *cgenv, struct sieve_command_context *ctx)
288
(void)sieve_operation_emit_code(cgenv->sbin, &envelope_operation);
290
/* Generate arguments */
291
if ( !sieve_generate_arguments(cgenv, ctx, NULL) )
301
static bool ext_envelope_operation_dump
302
(const struct sieve_operation *op ATTR_UNUSED,
303
const struct sieve_dumptime_env *denv, sieve_size_t *address)
305
sieve_code_dumpf(denv, "ENVELOPE");
306
sieve_code_descend(denv);
308
/* Handle any optional arguments */
309
if ( !sieve_addrmatch_default_dump_optionals(denv, address) )
313
sieve_opr_stringlist_dump(denv, address, "envelope part") &&
314
sieve_opr_stringlist_dump(denv, address, "key list");
321
static const struct sieve_address *const *_from_part_get_addresses
322
(const struct sieve_runtime_env *renv)
324
ARRAY_DEFINE(envelope_values, const struct sieve_address *);
325
const struct sieve_address *address =
326
sieve_message_get_sender_address(renv->msgctx);
328
if ( address != NULL ) {
329
t_array_init(&envelope_values, 2);
331
array_append(&envelope_values, &address, 1);
333
(void)array_append_space(&envelope_values);
334
return array_idx(&envelope_values, 0);
340
static const char *const *_from_part_get_values
341
(const struct sieve_runtime_env *renv)
343
ARRAY_DEFINE(envelope_values, const char *);
345
t_array_init(&envelope_values, 2);
347
if ( renv->msgdata->return_path != NULL ) {
348
array_append(&envelope_values, &renv->msgdata->return_path, 1);
351
(void)array_append_space(&envelope_values);
353
return array_idx(&envelope_values, 0);
356
static const struct sieve_address *const *_to_part_get_addresses
357
(const struct sieve_runtime_env *renv)
359
ARRAY_DEFINE(envelope_values, const struct sieve_address *);
360
const struct sieve_address *address =
361
sieve_message_get_recipient_address(renv->msgctx);
363
if ( address != NULL && address->local_part != NULL ) {
364
t_array_init(&envelope_values, 2);
366
array_append(&envelope_values, &address, 1);
368
(void)array_append_space(&envelope_values);
369
return array_idx(&envelope_values, 0);
375
static const char *const *_to_part_get_values
376
(const struct sieve_runtime_env *renv)
378
ARRAY_DEFINE(envelope_values, const char *);
380
t_array_init(&envelope_values, 2);
382
if ( renv->msgdata->to_address != NULL ) {
383
array_append(&envelope_values, &renv->msgdata->to_address, 1);
386
(void)array_append_space(&envelope_values);
388
return array_idx(&envelope_values, 0);
392
static const char *const *_auth_part_get_values
393
(const struct sieve_runtime_env *renv)
395
ARRAY_DEFINE(envelope_values, const char *);
397
t_array_init(&envelope_values, 2);
399
if ( renv->msgdata->auth_user != NULL )
400
array_append(&envelope_values, &renv->msgdata->auth_user, 1);
402
(void)array_append_space(&envelope_values);
404
return array_idx(&envelope_values, 0);
407
static int ext_envelope_operation_execute
408
(const struct sieve_operation *op ATTR_UNUSED,
409
const struct sieve_runtime_env *renv, sieve_size_t *address)
412
const struct sieve_comparator *cmp = &i_ascii_casemap_comparator;
413
const struct sieve_match_type *mtch = &is_match_type;
414
const struct sieve_address_part *addrp = &all_address_part;
415
struct sieve_match_context *mctx;
416
struct sieve_coded_stringlist *envp_list;
417
struct sieve_coded_stringlist *key_list;
426
sieve_runtime_trace(renv, "ENVELOPE test");
428
if ( (ret=sieve_addrmatch_default_get_optionals
429
(renv, address, &addrp, &mtch, &cmp)) <= 0 )
432
/* Read envelope-part */
433
if ( (envp_list=sieve_opr_stringlist_read(renv, address)) == NULL ) {
434
sieve_runtime_trace_error(renv, "invalid envelope-part operand");
435
return SIEVE_EXEC_BIN_CORRUPT;
439
if ( (key_list=sieve_opr_stringlist_read(renv, address)) == NULL ) {
440
sieve_runtime_trace_error(renv, "invalid key-list operand");
441
return SIEVE_EXEC_BIN_CORRUPT;
444
/* Initialize match */
445
mctx = sieve_match_begin(renv->interp, mtch, cmp, NULL, key_list);
447
/* Iterate through all requested headers to match */
450
while ( result && !matched &&
451
(result=sieve_coded_stringlist_next_item(envp_list, &envp_item))
452
&& envp_item != NULL ) {
453
const struct sieve_envelope_part *epart;
455
if ( (epart=_envelope_part_find(str_c(envp_item))) != NULL ) {
456
const struct sieve_address * const *addresses = NULL;
459
if ( epart->get_addresses != NULL ) {
460
/* Field contains addresses */
461
addresses = epart->get_addresses(renv);
463
if ( addresses != NULL ) {
464
for ( i = 0; !matched && addresses[i] != NULL; i++ ) {
465
if ( addresses[i]->local_part == NULL ) {
467
ret = sieve_match_value(mctx, "", 0);
469
const char *part = addrp->extract_from(addresses[i]);
472
ret = sieve_match_value(mctx, part, strlen(part));
487
if ( epart->get_values != NULL && addresses == NULL &&
488
addrp == &all_address_part ) {
489
/* Field contains something else */
490
const char *const *values = epart->get_values(renv);
492
if ( values == NULL ) continue;
494
for ( i = 0; !matched && values[i] != NULL; i++ ) {
496
if ( (ret=sieve_match_value
497
(mctx, values[i], strlen(values[i]))) < 0 ) {
509
if ( (ret=sieve_match_end(&mctx)) < 0 )
512
matched = ( ret > 0 || matched );
515
/* Set test result for subsequent conditional jump */
516
sieve_interpreter_set_test_result(renv->interp, matched);
517
return SIEVE_EXEC_OK;
520
sieve_runtime_trace_error(renv, "invalid string-list item");
521
return SIEVE_EXEC_BIN_CORRUPT;