Coverage Report

Created: 2026-06-09 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/tst-header.c
Line
Count
Source
1
/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2
 */
3
4
#include "lib.h"
5
#include "str-sanitize.h"
6
7
#include "sieve-common.h"
8
#include "sieve-commands.h"
9
#include "sieve-code.h"
10
#include "sieve-message.h"
11
#include "sieve-comparators.h"
12
#include "sieve-match-types.h"
13
#include "sieve-validator.h"
14
#include "sieve-generator.h"
15
#include "sieve-interpreter.h"
16
#include "sieve-dump.h"
17
#include "sieve-match.h"
18
19
/*
20
 * Header test
21
 *
22
 * Syntax:
23
 *   header [COMPARATOR] [MATCH-TYPE]
24
 *     <header-names: string-list> <key-list: string-list>
25
 */
26
27
static bool tst_header_registered
28
  (struct sieve_validator *valdtr, const struct sieve_extension *ext,
29
    struct sieve_command_registration *cmd_reg);
30
static bool tst_header_validate
31
  (struct sieve_validator *valdtr, struct sieve_command *tst);
32
static bool tst_header_generate
33
  (const struct sieve_codegen_env *cgenv, struct sieve_command *tst);
34
35
const struct sieve_command_def tst_header = {
36
  .identifier = "header",
37
  .type = SCT_TEST,
38
  .positional_args = 2,
39
  .subtests = 0,
40
  .block_allowed = FALSE,
41
  .block_required = FALSE,
42
  .registered = tst_header_registered,
43
  .validate = tst_header_validate,
44
  .generate = tst_header_generate
45
};
46
47
/*
48
 * Header operation
49
 */
50
51
static bool tst_header_operation_dump
52
  (const struct sieve_dumptime_env *denv, sieve_size_t *address);
53
static int tst_header_operation_execute
54
  (const struct sieve_runtime_env *renv, sieve_size_t *address);
55
56
const struct sieve_operation_def tst_header_operation = {
57
  .mnemonic = "HEADER",
58
  .code = SIEVE_OPERATION_HEADER,
59
  .dump = tst_header_operation_dump,
60
  .execute = tst_header_operation_execute
61
};
62
63
/*
64
 * Test registration
65
 */
66
67
static bool tst_header_registered
68
(struct sieve_validator *valdtr, const struct sieve_extension *ext ATTR_UNUSED,
69
  struct sieve_command_registration *cmd_reg)
70
0
{
71
  /* The order of these is not significant */
72
0
  sieve_comparators_link_tag(valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
73
0
  sieve_match_types_link_tags(valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
74
75
0
  return TRUE;
76
0
}
77
78
/*
79
 * Validation
80
 */
81
82
static bool tst_header_validate
83
(struct sieve_validator *valdtr, struct sieve_command *tst)
84
0
{
85
0
  struct sieve_ast_argument *arg = tst->first_positional;
86
0
  struct sieve_comparator cmp_default =
87
0
    SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
88
0
  struct sieve_match_type mcht_default =
89
0
    SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
90
91
0
  if ( !sieve_validate_positional_argument
92
0
    (valdtr, tst, arg, "header names", 1, SAAT_STRING_LIST) ) {
93
0
    return FALSE;
94
0
  }
95
96
0
  if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
97
0
    return FALSE;
98
99
0
  if ( !sieve_command_verify_headers_argument(valdtr, arg) )
100
0
    return FALSE;
101
102
0
  arg = sieve_ast_argument_next(arg);
103
104
0
  if ( !sieve_validate_positional_argument
105
0
    (valdtr, tst, arg, "key list", 2, SAAT_STRING_LIST) ) {
106
0
    return FALSE;
107
0
  }
108
109
0
  if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
110
0
    return FALSE;
111
112
  /* Validate the key argument to a specified match type */
113
0
  return sieve_match_type_validate
114
0
    (valdtr, tst, arg, &mcht_default, &cmp_default);
115
0
}
116
117
/*
118
 * Code generation
119
 */
120
121
static bool tst_header_generate
122
(const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
123
0
{
124
0
  sieve_operation_emit(cgenv->sblock, NULL, &tst_header_operation);
125
126
  /* Generate arguments */
127
0
  return sieve_generate_arguments(cgenv, tst, NULL);
128
0
}
129
130
/*
131
 * Code dump
132
 */
133
134
static bool tst_header_operation_dump
135
(const struct sieve_dumptime_env *denv, sieve_size_t *address)
136
0
{
137
0
  sieve_code_dumpf(denv, "HEADER");
138
0
  sieve_code_descend(denv);
139
140
  /* Optional operands */
141
0
  if ( sieve_message_opr_optional_dump(denv, address, NULL) != 0 )
142
0
    return FALSE;
143
144
0
  return
145
0
    sieve_opr_stringlist_dump(denv, address, "header names") &&
146
0
    sieve_opr_stringlist_dump(denv, address, "key list");
147
0
}
148
149
/*
150
 * Code execution
151
 */
152
153
static int tst_header_operation_execute
154
(const struct sieve_runtime_env *renv, sieve_size_t *address)
155
0
{
156
0
  struct sieve_comparator cmp =
157
0
    SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
158
0
  struct sieve_match_type mcht =
159
0
    SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
160
0
  struct sieve_stringlist *hdr_list, *key_list, *value_list;
161
0
  ARRAY_TYPE(sieve_message_override) svmos;
162
0
  int match, ret;
163
164
  /*
165
   * Read operands
166
   */
167
168
  /* Optional operands */
169
0
  i_zero(&svmos);
170
0
  if ( sieve_message_opr_optional_read
171
0
    (renv, address, NULL, &ret, NULL, &mcht, &cmp, &svmos) < 0 )
172
0
    return ret;
173
174
  /* Read header-list */
175
0
  if ( (ret=sieve_opr_stringlist_read(renv, address, "header-list", &hdr_list))
176
0
    <= 0 )
177
0
    return ret;
178
179
  /* Read key-list */
180
0
  if ( (ret=sieve_opr_stringlist_read(renv, address, "key-list", &key_list))
181
0
    <= 0 )
182
0
    return ret;
183
184
  /*
185
   * Perform test
186
   */
187
188
0
  sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "header test");
189
190
  /* Get header */
191
0
  sieve_runtime_trace_descend(renv);
192
0
  if ( (ret=sieve_message_get_header_fields
193
0
    (renv, hdr_list, &svmos, TRUE, &value_list)) <= 0 )
194
0
    return ret;
195
0
  sieve_runtime_trace_ascend(renv);
196
197
  /* Perform match */
198
0
  if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) < 0 )
199
0
    return ret;
200
201
  /* Set test result for subsequent conditional jump */
202
0
  sieve_interpreter_set_test_result(renv->interp, match > 0);
203
0
  return SIEVE_EXEC_OK;
204
0
}