Coverage Report

Created: 2026-10-28 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-namespaces.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
#include "sieve-common.h"
4
#include "sieve-commands.h"
5
#include "sieve-code.h"
6
#include "sieve-binary.h"
7
#include "sieve-dump.h"
8
9
#include "ext-variables-common.h"
10
#include "ext-variables-namespaces.h"
11
12
#include <ctype.h>
13
14
/*
15
 * Namespace registry
16
 */
17
18
void sieve_variables_namespace_register(
19
  const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
20
  const struct sieve_extension *ext,
21
  const struct sieve_variables_namespace_def *nspc_def)
22
0
{
23
0
  struct ext_variables_validator_context *ctx =
24
0
    ext_variables_validator_context_get(var_ext, valdtr);
25
26
0
  sieve_validator_object_registry_add(ctx->namespaces, ext,
27
0
              &nspc_def->obj_def);
28
0
}
29
30
bool ext_variables_namespace_exists(const struct sieve_extension *var_ext,
31
            struct sieve_validator *valdtr,
32
            const char *identifier)
33
0
{
34
0
  struct ext_variables_validator_context *ctx =
35
0
    ext_variables_validator_context_get(var_ext, valdtr);
36
37
0
  return sieve_validator_object_registry_find(ctx->namespaces, identifier,
38
0
                NULL);
39
0
}
40
41
const struct sieve_variables_namespace *
42
ext_variables_namespace_create_instance(const struct sieve_extension *var_ext,
43
          struct sieve_validator *valdtr,
44
          struct sieve_command *cmd,
45
          const char *identifier)
46
0
{
47
0
  struct ext_variables_validator_context *ctx =
48
0
    ext_variables_validator_context_get(var_ext, valdtr);
49
0
  struct sieve_object object;
50
0
  struct sieve_variables_namespace *nspc;
51
0
  pool_t pool;
52
53
0
  if (!sieve_validator_object_registry_find(ctx->namespaces, identifier,
54
0
              &object))
55
0
    return NULL;
56
57
0
  pool = sieve_command_pool(cmd);
58
0
  nspc = p_new(pool, struct sieve_variables_namespace, 1);
59
0
  nspc->object = object;
60
0
  nspc->def = (const struct sieve_variables_namespace_def *) object.def;
61
62
0
  return nspc;
63
0
}
64
65
/*
66
 * Namespace variable argument
67
 */
68
69
struct arg_namespace_variable {
70
  const struct sieve_variables_namespace *namespace;
71
72
  void *data;
73
};
74
75
static bool
76
arg_namespace_generate(const struct sieve_codegen_env *cgenv,
77
           struct sieve_ast_argument *arg,
78
           struct sieve_command *context ATTR_UNUSED);
79
80
const struct sieve_argument_def namespace_argument = {
81
  .identifier = "@namespace",
82
  .generate = arg_namespace_generate,
83
};
84
85
bool ext_variables_namespace_argument_activate(
86
  const struct sieve_extension *this_ext, struct sieve_validator *valdtr,
87
  struct sieve_ast_argument *arg, struct sieve_command *cmd,
88
  ARRAY_TYPE(sieve_variable_name) *var_name, bool assignment)
89
0
{
90
0
  pool_t pool = sieve_command_pool(cmd);
91
0
  struct sieve_ast *ast = arg->ast;
92
0
  const struct sieve_variables_namespace *nspc;
93
0
  struct arg_namespace_variable *var;
94
0
  const struct sieve_variable_name *name_element = array_idx(var_name, 0);
95
0
  void *var_data = NULL;
96
97
0
  nspc = ext_variables_namespace_create_instance(
98
0
    this_ext, valdtr, cmd, str_c(name_element->identifier));
99
0
  if (nspc == NULL) {
100
0
    sieve_argument_validate_error(
101
0
      valdtr, arg,
102
0
      "referring to variable in unknown namespace '%s'",
103
0
      str_c(name_element->identifier));
104
0
    return FALSE;
105
0
  }
106
107
0
  if (nspc->def != NULL && nspc->def->validate != NULL &&
108
0
      !nspc->def->validate(valdtr, nspc, arg, cmd, var_name, &var_data,
109
0
         assignment))
110
0
    return FALSE;
111
112
0
  var = p_new(pool, struct arg_namespace_variable, 1);
113
0
  var->namespace = nspc;
114
0
  var->data = var_data;
115
116
0
  arg->argument = sieve_argument_create(ast, &namespace_argument,
117
0
                this_ext, 0);
118
0
  arg->argument->data = var;
119
120
0
  return TRUE;
121
0
}
122
123
struct sieve_ast_argument *
124
ext_variables_namespace_argument_create(
125
  const struct sieve_extension *this_ext, struct sieve_validator *valdtr,
126
  struct sieve_ast_argument *parent_arg, struct sieve_command *cmd,
127
  ARRAY_TYPE(sieve_variable_name) *var_name)
128
0
{
129
0
  struct sieve_ast *ast = parent_arg->ast;
130
0
  struct sieve_ast_argument *new_arg;
131
132
0
  new_arg = sieve_ast_argument_create(
133
0
    ast, sieve_ast_argument_line(parent_arg));
134
0
  new_arg->type = SAAT_STRING;
135
136
0
  if (!ext_variables_namespace_argument_activate(
137
0
    this_ext, valdtr, new_arg, cmd, var_name, FALSE))
138
0
    return NULL;
139
140
0
  return new_arg;
141
0
}
142
143
static bool
144
arg_namespace_generate(const struct sieve_codegen_env *cgenv,
145
           struct sieve_ast_argument *arg,
146
           struct sieve_command *cmd)
147
0
{
148
0
  struct sieve_argument *argument = arg->argument;
149
0
  struct arg_namespace_variable *var =
150
0
    (struct arg_namespace_variable *)argument->data;
151
0
  const struct sieve_variables_namespace *nspc = var->namespace;
152
153
0
  if (nspc->def != NULL && nspc->def->generate != NULL)
154
0
    return nspc->def->generate(cgenv, nspc, arg, cmd, var->data);
155
156
0
  return TRUE;
157
0
}
158
159
/*
160
 * Namespace variable operands
161
 */
162
163
const struct sieve_operand_class sieve_variables_namespace_operand_class =
164
  { "variable-namespace" };
165
166
static bool
167
opr_namespace_variable_dump(const struct sieve_dumptime_env *denv,
168
          const struct sieve_operand *oprnd,
169
          sieve_size_t *address);
170
static int
171
opr_namespace_variable_read(const struct sieve_runtime_env *renv,
172
          const struct sieve_operand *oprnd,
173
          sieve_size_t *address, string_t **str_r);
174
175
static const struct sieve_opr_string_interface namespace_variable_interface = {
176
  opr_namespace_variable_dump,
177
  opr_namespace_variable_read,
178
};
179
180
const struct sieve_operand_def namespace_variable_operand = {
181
  .name = "namespace",
182
  .ext_def = &variables_extension,
183
  .code = EXT_VARIABLES_OPERAND_NAMESPACE_VARIABLE,
184
  .class = &string_class,
185
  .interface = &namespace_variable_interface,
186
};
187
188
void sieve_variables_opr_namespace_variable_emit(
189
  struct sieve_binary_block *sblock,
190
  const struct sieve_extension *var_ext,
191
  const struct sieve_extension *ext,
192
  const struct sieve_variables_namespace_def *nspc_def)
193
0
{
194
0
  i_assert(sieve_extension_is(var_ext, variables_extension));
195
0
  sieve_operand_emit(sblock, var_ext, &namespace_variable_operand);
196
0
  sieve_opr_object_emit(sblock, ext, &nspc_def->obj_def);
197
0
}
198
199
static bool
200
opr_namespace_variable_dump(const struct sieve_dumptime_env *denv,
201
          const struct sieve_operand *oprnd,
202
          sieve_size_t *address)
203
0
{
204
0
  struct sieve_variables_namespace nspc;
205
0
  struct sieve_operand nsoprnd;
206
207
0
  if (!sieve_operand_read(denv->sblock, address, NULL, &nsoprnd))
208
0
    return FALSE;
209
0
  if (!sieve_opr_object_read_data(
210
0
    denv->sblock, &nsoprnd,
211
0
    &sieve_variables_namespace_operand_class, address,
212
0
    &nspc.object))
213
0
    return FALSE;
214
215
0
  nspc.def = (const struct sieve_variables_namespace_def *)
216
0
    nspc.object.def;
217
218
0
  if (nspc.def == NULL || nspc.def->dump_variable == NULL)
219
0
    return FALSE;
220
221
0
  return nspc.def->dump_variable(denv, &nspc, oprnd, address);
222
0
}
223
224
static int
225
opr_namespace_variable_read(const struct sieve_runtime_env *renv,
226
          const struct sieve_operand *oprnd,
227
          sieve_size_t *address, string_t **str_r)
228
0
{
229
0
  struct sieve_variables_namespace nspc;
230
231
0
  if (!sieve_opr_object_read(
232
0
    renv, &sieve_variables_namespace_operand_class, address,
233
0
    &nspc.object)) {
234
0
    sieve_runtime_trace_operand_error(renv, oprnd,
235
0
      "variable namespace operand corrupt: failed to read");
236
0
    return SIEVE_EXEC_BIN_CORRUPT;
237
0
  }
238
239
0
  nspc.def = (const struct sieve_variables_namespace_def *)
240
0
    nspc.object.def;
241
242
0
  if (nspc.def == NULL || nspc.def->read_variable == NULL)
243
0
    return SIEVE_EXEC_FAILURE;
244
245
0
  return nspc.def->read_variable(renv, &nspc, oprnd, address, str_r);
246
0
}