Coverage Report

Created: 2026-09-01 06:28

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