Coverage Report

Created: 2026-08-13 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/plugins/environment/tst-environment.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-stringlist.h"
9
#include "sieve-code.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
#include "ext-environment-common.h"
19
20
/*
21
 * Environment test
22
 *
23
 * Syntax:
24
 *   environment [COMPARATOR] [MATCH-TYPE]
25
 *      <name: string> <key-list: string-list>
26
 */
27
28
static bool
29
tst_environment_registered(struct sieve_validator *valdtr,
30
         const struct sieve_extension *ext,
31
         struct sieve_command_registration *cmd_reg);
32
static bool
33
tst_environment_validate(struct sieve_validator *valdtr,
34
       struct sieve_command *tst);
35
static bool
36
tst_environment_generate(const struct sieve_codegen_env *cgenv,
37
       struct sieve_command *cmd);
38
39
const struct sieve_command_def tst_environment = {
40
  .identifier = "environment",
41
  .type = SCT_TEST,
42
  .positional_args = 2,
43
  .subtests = 0,
44
  .block_allowed = FALSE,
45
  .block_required = FALSE,
46
  .registered = tst_environment_registered,
47
  .validate = tst_environment_validate,
48
  .generate = tst_environment_generate,
49
};
50
51
/*
52
 * Environment operation
53
 */
54
55
static bool
56
tst_environment_operation_dump(const struct sieve_dumptime_env *denv,
57
             sieve_size_t *address);
58
static int
59
tst_environment_operation_execute(const struct sieve_runtime_env *renv,
60
          sieve_size_t *address);
61
62
const struct sieve_operation_def tst_environment_operation = {
63
  .mnemonic = "ENVIRONMENT",
64
  .ext_def = &environment_extension,
65
  .dump = tst_environment_operation_dump,
66
  .execute = tst_environment_operation_execute,
67
};
68
69
/*
70
 * Test registration
71
 */
72
73
static bool
74
tst_environment_registered(struct sieve_validator *valdtr,
75
         const struct sieve_extension *ext ATTR_UNUSED,
76
         struct sieve_command_registration *cmd_reg)
77
0
{
78
  /* The order of these is not significant */
79
0
  sieve_comparators_link_tag(valdtr, cmd_reg,
80
0
           SIEVE_MATCH_OPT_COMPARATOR);
81
0
  sieve_match_types_link_tags(valdtr, cmd_reg,
82
0
            SIEVE_MATCH_OPT_MATCH_TYPE);
83
84
0
  return TRUE;
85
0
}
86
87
/*
88
 * Test validation
89
 */
90
91
static bool
92
tst_environment_validate(struct sieve_validator *valdtr,
93
       struct sieve_command *tst)
94
0
{
95
0
  struct sieve_ast_argument *arg = tst->first_positional;
96
0
  const struct sieve_match_type mcht_default =
97
0
    SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
98
0
  const struct sieve_comparator cmp_default =
99
0
    SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
100
101
0
  if (!sieve_validate_positional_argument(valdtr, tst, arg,
102
0
            "name", 1, SAAT_STRING))
103
0
    return FALSE;
104
0
  if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
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
0
  if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
113
0
    return FALSE;
114
115
  /* Validate the key argument to a specified match type */
116
0
  return sieve_match_type_validate(valdtr, tst, arg,
117
0
           &mcht_default, &cmp_default);
118
0
}
119
120
/*
121
 * Test generation
122
 */
123
124
static bool
125
tst_environment_generate(const struct sieve_codegen_env *cgenv,
126
       struct sieve_command *cmd)
127
0
{
128
0
  sieve_operation_emit(cgenv->sblock, cmd->ext,
129
0
           &tst_environment_operation);
130
131
  /* Generate arguments */
132
0
  return sieve_generate_arguments(cgenv, cmd, NULL);
133
0
}
134
135
/*
136
 * Code dump
137
 */
138
139
static bool
140
tst_environment_operation_dump(const struct sieve_dumptime_env *denv,
141
             sieve_size_t *address)
142
0
{
143
0
  sieve_code_dumpf(denv, "ENVIRONMENT");
144
0
  sieve_code_descend(denv);
145
146
  /* Optional operands */
147
0
  if (sieve_match_opr_optional_dump(denv, address, NULL) != 0)
148
0
    return FALSE;
149
150
0
  return (sieve_opr_string_dump(denv, address, "name") &&
151
0
    sieve_opr_stringlist_dump(denv, address, "key list"));
152
0
}
153
154
/*
155
 * Code execution
156
 */
157
158
static int
159
tst_environment_operation_execute(const struct sieve_runtime_env *renv,
160
          sieve_size_t *address)
161
0
{
162
0
  const struct sieve_extension *this_ext = renv->oprtn->ext;
163
0
  struct sieve_match_type mcht =
164
0
    SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
165
0
  struct sieve_comparator cmp =
166
0
    SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
167
0
  string_t *name;
168
0
  struct sieve_stringlist *value_list, *key_list;
169
0
  const char *env_item;
170
0
  int match, ret;
171
172
  /*
173
   * Read operands
174
   */
175
176
  /* Handle match-type and comparator operands */
177
0
  if (sieve_match_opr_optional_read(renv, address, NULL,
178
0
            &ret, &cmp, &mcht) < 0)
179
0
    return ret;
180
181
  /* Read source */
182
0
  ret = sieve_opr_string_read(renv, address, "name", &name);
183
0
  if (ret <= 0)
184
0
    return ret;
185
186
  /* Read key-list */
187
0
  ret = sieve_opr_stringlist_read(renv, address, "key-list", &key_list);
188
0
  if (ret <= 0)
189
0
    return ret;
190
191
  /*
192
   * Perform operation
193
   */
194
195
0
  sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "environment test");
196
197
0
  env_item = ext_environment_item_get_value(this_ext, renv, str_c(name));
198
199
0
  if (env_item != NULL) {
200
    /* Construct value list */
201
0
    value_list = sieve_single_stringlist_create_cstr(
202
0
      renv, env_item, FALSE);
203
204
    /* Perform match */
205
0
    match = sieve_match(renv, &mcht, &cmp, value_list, key_list,
206
0
            &ret);
207
0
    if (ret < 0)
208
0
      return ret;
209
0
  } else {
210
0
    match = 0;
211
212
0
    sieve_runtime_trace_descend(renv);
213
0
    sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
214
0
            "environment item '%s' not found",
215
0
            str_sanitize(str_c(name), 128));
216
0
  }
217
218
  /* Set test result for subsequent conditional jump */
219
0
  sieve_interpreter_set_test_result(renv->interp, match > 0);
220
0
  return SIEVE_EXEC_OK;
221
0
}