Coverage Report

Created: 2026-04-27 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/plugins/variables/cmd-set.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.h"
6
#include "array.h"
7
8
#include "sieve-common.h"
9
#include "sieve-extensions.h"
10
11
#include "sieve-code.h"
12
#include "sieve-ast.h"
13
#include "sieve-commands.h"
14
#include "sieve-binary.h"
15
16
#include "sieve-validator.h"
17
#include "sieve-generator.h"
18
#include "sieve-interpreter.h"
19
#include "sieve-dump.h"
20
21
#include "ext-variables-common.h"
22
23
/*
24
 * Set command
25
 *
26
 * Syntax:
27
 *    set [MODIFIER] <name: string> <value: string>
28
 */
29
30
static bool
31
cmd_set_registered(struct sieve_validator *valdtr,
32
       const struct sieve_extension *ext,
33
       struct sieve_command_registration *cmd_reg);
34
static bool
35
cmd_set_validate(struct sieve_validator *valdtr, struct sieve_command *cmd);
36
static bool
37
cmd_set_generate(const struct sieve_codegen_env *cgenv,
38
     struct sieve_command *ctx);
39
40
const struct sieve_command_def cmd_set = {
41
  .identifier = "set",
42
  .type = SCT_COMMAND,
43
  .positional_args = 2,
44
  .subtests = 0,
45
  .block_allowed = FALSE,
46
  .block_required = FALSE,
47
  .registered = cmd_set_registered,
48
  .validate = cmd_set_validate,
49
  .generate = cmd_set_generate,
50
};
51
52
/*
53
 * Set operation
54
 */
55
56
static bool
57
cmd_set_operation_dump(const struct sieve_dumptime_env *denv,
58
           sieve_size_t *address);
59
static int
60
cmd_set_operation_execute(const struct sieve_runtime_env *renv,
61
        sieve_size_t *address);
62
63
const struct sieve_operation_def cmd_set_operation = {
64
  .mnemonic = "SET",
65
  .ext_def = &variables_extension,
66
  .code = EXT_VARIABLES_OPERATION_SET,
67
  .dump = cmd_set_operation_dump,
68
  .execute = cmd_set_operation_execute,
69
};
70
71
/*
72
 * Compiler context
73
 */
74
75
struct cmd_set_context {
76
  ARRAY_TYPE(sieve_variables_modifier) modifiers;
77
};
78
79
/* Command registration */
80
81
static bool
82
cmd_set_registered(struct sieve_validator *valdtr,
83
       const struct sieve_extension *ext,
84
       struct sieve_command_registration *cmd_reg)
85
0
{
86
0
  sieve_variables_modifiers_link_tag(valdtr, ext, cmd_reg);
87
88
0
  return TRUE;
89
0
}
90
91
/*
92
 * Command validation
93
 */
94
95
static bool
96
cmd_set_validate(struct sieve_validator *valdtr, struct sieve_command *cmd)
97
0
{
98
0
  const struct sieve_extension *this_ext = cmd->ext;
99
0
  struct sieve_ast_argument *arg = cmd->first_positional;
100
0
  pool_t pool = sieve_command_pool(cmd);
101
0
  struct cmd_set_context *sctx;
102
103
  /* Create command context */
104
0
  sctx = p_new(pool, struct cmd_set_context, 1);
105
0
  p_array_init(&sctx->modifiers, pool, 4);
106
0
  cmd->data = sctx;
107
108
  /* Validate modifiers */
109
0
  if (!sieve_variables_modifiers_validate(valdtr, cmd, &sctx->modifiers))
110
0
    return FALSE;
111
112
  /* Validate name argument */
113
0
  if (!sieve_validate_positional_argument(valdtr, cmd, arg, "name",
114
0
            1, SAAT_STRING))
115
0
    return FALSE;
116
0
  if (!sieve_variable_argument_activate(this_ext, this_ext, valdtr,
117
0
                cmd, arg, TRUE))
118
0
    return FALSE;
119
0
  arg = sieve_ast_argument_next(arg);
120
121
  /* Validate value argument */
122
0
  if (!sieve_validate_positional_argument(valdtr, cmd, arg, "value",
123
0
            2, SAAT_STRING))
124
0
    return FALSE;
125
0
  return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE);
126
0
}
127
128
/*
129
 * Code generation
130
 */
131
132
static bool
133
cmd_set_generate(const struct sieve_codegen_env *cgenv,
134
     struct sieve_command *cmd)
135
0
{
136
0
  const struct sieve_extension *this_ext = cmd->ext;
137
0
  struct sieve_binary_block *sblock = cgenv->sblock;
138
0
  struct cmd_set_context *sctx = (struct cmd_set_context *) cmd->data;
139
140
0
  sieve_operation_emit(sblock, this_ext, &cmd_set_operation);
141
142
  /* Generate arguments */
143
0
  if (!sieve_generate_arguments(cgenv, cmd, NULL))
144
0
    return FALSE;
145
146
  /* Generate modifiers */
147
0
  if (!sieve_variables_modifiers_generate(cgenv, &sctx->modifiers))
148
0
    return FALSE;
149
0
  return TRUE;
150
0
}
151
152
/*
153
 * Code dump
154
 */
155
156
static bool
157
cmd_set_operation_dump(const struct sieve_dumptime_env *denv,
158
           sieve_size_t *address)
159
0
{
160
0
  sieve_code_dumpf(denv, "SET");
161
0
  sieve_code_descend(denv);
162
163
  /* Print both variable name and string value */
164
0
  if (!sieve_opr_string_dump(denv, address, "variable") ||
165
0
      !sieve_opr_string_dump(denv, address, "value"))
166
0
    return FALSE;
167
168
0
  return sieve_variables_modifiers_code_dump(denv, address);
169
0
}
170
171
/*
172
 * Code execution
173
 */
174
175
static int
176
cmd_set_operation_execute(const struct sieve_runtime_env *renv,
177
        sieve_size_t *address)
178
0
{
179
0
  const struct sieve_extension *this_ext = renv->oprtn->ext;
180
0
  struct sieve_variable_storage *storage;
181
0
  ARRAY_TYPE(sieve_variables_modifier) modifiers;
182
0
  unsigned int var_index;
183
0
  string_t *value;
184
0
  int ret = SIEVE_EXEC_OK;
185
186
  /*
187
   * Read the normal operands
188
   */
189
190
0
  ret = sieve_variable_operand_read(renv, address, "variable",
191
0
            &storage, &var_index);
192
0
  if (ret <= 0)
193
0
    return ret;
194
195
0
  ret = sieve_opr_string_read(renv, address, "string", &value);
196
0
  if (ret <= 0)
197
0
    return ret;
198
199
0
  ret = sieve_variables_modifiers_code_read(renv, this_ext,
200
0
              address, &modifiers);
201
0
  if (ret <= 0)
202
0
    return ret;
203
204
  /*
205
   * Determine and assign the value
206
   */
207
208
0
  sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "set command");
209
0
  sieve_runtime_trace_descend(renv);
210
211
  /* Apply modifiers */
212
0
  ret = sieve_variables_modifiers_apply(renv, this_ext, &modifiers,
213
0
                &value);
214
0
  if (ret <= 0)
215
0
    return ret;
216
217
  /* Actually assign the value if all is well */
218
0
  i_assert (value != NULL);
219
0
  if (!sieve_variable_assign(storage, var_index, value))
220
0
    return SIEVE_EXEC_BIN_CORRUPT;
221
222
  /* Trace */
223
0
  if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
224
0
    const char *var_name, *var_id;
225
226
0
    (void)sieve_variable_get_identifier(storage, var_index,
227
0
                &var_name);
228
0
    var_id = sieve_variable_get_varid(storage, var_index);
229
230
0
    sieve_runtime_trace_here(renv, 0, "assign '%s' [%s] = \"%s\"",
231
0
           var_name, var_id, str_c(value));
232
0
  }
233
234
0
  return SIEVE_EXEC_OK;
235
0
}