Coverage Report

Created: 2026-07-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/plugins/include/ext-include-variables.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-error.h"
8
#include "sieve-script.h"
9
#include "sieve-ast.h"
10
#include "sieve-binary.h"
11
#include "sieve-commands.h"
12
#include "sieve-validator.h"
13
#include "sieve-generator.h"
14
#include "sieve-interpreter.h"
15
#include "sieve-dump.h"
16
17
#include "sieve-ext-variables.h"
18
19
#include "ext-include-common.h"
20
#include "ext-include-binary.h"
21
#include "ext-include-variables.h"
22
23
/*
24
 * Variable import-export
25
 */
26
27
struct sieve_variable *
28
ext_include_variable_import_global(struct sieve_validator *valdtr,
29
           struct sieve_command *cmd,
30
           const char *variable)
31
0
{
32
0
  const struct sieve_extension *this_ext = cmd->ext;
33
0
  struct sieve_ast *ast = cmd->ast_node->ast;
34
0
  struct ext_include_ast_context *ctx =
35
0
    ext_include_get_ast_context(this_ext, ast);
36
0
  struct ext_include_context *extctx = ext_include_get_context(this_ext);
37
0
  struct sieve_variable_scope *local_scope;
38
0
  struct sieve_variable_scope *global_scope = ctx->global_vars;
39
0
  struct sieve_variable *global_var = NULL, *local_var;
40
41
  /* Sanity safeguard */
42
0
  i_assert (ctx->global_vars != NULL);
43
44
0
  if (!sieve_variable_identifier_is_valid(variable)) {
45
0
    sieve_command_validate_error(
46
0
      valdtr, cmd, "invalid variable identifier '%s'",
47
0
      str_sanitize(variable,80));
48
0
    return NULL;
49
0
  }
50
51
  /* Get/Declare the variable in the global scope */
52
0
  global_var = sieve_variable_scope_declare(global_scope, variable);
53
54
  /* Check whether scope is over its size limit */
55
0
  if (global_var == NULL) {
56
0
    sieve_command_validate_error(
57
0
      valdtr, cmd,
58
0
      "declaration of new global variable '%s' exceeds the limit "
59
0
      "(max variables: %u)", variable,
60
0
      sieve_variables_get_max_scope_count(extctx->var_ext));
61
0
    return NULL;
62
0
  }
63
64
  /* Import the global variable into the local script scope */
65
0
  local_scope = sieve_ext_variables_get_local_scope(
66
0
    extctx->var_ext, valdtr);
67
68
0
  local_var = sieve_variable_scope_get_variable(local_scope, variable);
69
0
  if (local_var != NULL && local_var->ext != this_ext) {
70
    /* FIXME: indicate location of conflicting set statement */
71
0
    sieve_command_validate_error(
72
0
      valdtr, cmd,
73
0
      "declaration of new global variable '%s' "
74
0
      "conflicts with earlier local use", variable);
75
0
    return NULL;
76
0
  }
77
78
0
  return sieve_variable_scope_import(local_scope, global_var);
79
0
}
80
81
/*
82
 * Binary symbol table
83
 */
84
85
bool ext_include_variables_save(struct sieve_binary_block *sblock,
86
        struct sieve_variable_scope_binary *global_vars,
87
        enum sieve_error *error_code_r ATTR_UNUSED)
88
0
{
89
0
  struct sieve_variable_scope *global_scope =
90
0
    sieve_variable_scope_binary_get(global_vars);
91
0
  unsigned int count = sieve_variable_scope_size(global_scope);
92
0
  sieve_size_t jump;
93
94
0
  sieve_binary_emit_unsigned(sblock, count);
95
96
0
  jump = sieve_binary_emit_offset(sblock, 0);
97
98
0
  if (count > 0) {
99
0
    unsigned int size, i;
100
0
    struct sieve_variable *const *vars =
101
0
      sieve_variable_scope_get_variables(global_scope, &size);
102
103
0
    for (i = 0; i < size; i++) {
104
0
      sieve_binary_emit_cstring(sblock, vars[i]->identifier);
105
0
    }
106
0
  }
107
108
0
  sieve_binary_resolve_offset(sblock, jump);
109
110
0
  return TRUE;
111
0
}
112
113
bool ext_include_variables_load(
114
  const struct sieve_extension *this_ext,
115
  struct sieve_binary_block *sblock, sieve_size_t *offset,
116
  struct sieve_variable_scope_binary **global_vars_r)
117
0
{
118
0
  struct ext_include_context *extctx = ext_include_get_context(this_ext);
119
120
  /* Sanity assert */
121
0
  i_assert(*global_vars_r == NULL);
122
123
0
  *global_vars_r = sieve_variable_scope_binary_read(
124
0
    this_ext->svinst, extctx->var_ext, this_ext, sblock, offset);
125
126
0
  return (*global_vars_r != NULL);
127
0
}
128
129
bool ext_include_variables_dump(struct sieve_dumptime_env *denv,
130
        struct sieve_variable_scope_binary *global_vars)
131
0
{
132
0
  struct sieve_variable_scope *global_scope =
133
0
    sieve_variable_scope_binary_get(global_vars);
134
0
  unsigned int size;
135
0
  struct sieve_variable *const *vars;
136
137
0
  i_assert(global_scope != NULL);
138
139
0
  vars = sieve_variable_scope_get_variables(global_scope, &size);
140
141
0
  if (size > 0) {
142
0
    unsigned int i;
143
144
0
    sieve_binary_dump_sectionf(denv, "Global variables");
145
146
0
    for (i = 0; i < size; i++) {
147
0
      sieve_binary_dumpf(denv, "%3d: '%s' \n",
148
0
             i, vars[i]->identifier);
149
0
    }
150
0
  }
151
0
  return TRUE;
152
0
}
153
154
/*
155
 * Global variables namespace
156
 */
157
158
static bool
159
vnspc_global_variables_validate(struct sieve_validator *valdtr,
160
        const struct sieve_variables_namespace *nspc,
161
        struct sieve_ast_argument *arg,
162
        struct sieve_command *cmd,
163
        ARRAY_TYPE(sieve_variable_name) *var_name,
164
        void **var_data, bool assignment);
165
static bool
166
vnspc_global_variables_generate(const struct sieve_codegen_env *cgenv,
167
        const struct sieve_variables_namespace *nspc,
168
        struct sieve_ast_argument *arg,
169
        struct sieve_command *cmd, void *var_data);
170
171
static const struct sieve_variables_namespace_def
172
global_variables_namespace = {
173
  SIEVE_OBJECT("global", NULL, 0),
174
  .validate = vnspc_global_variables_validate,
175
  .generate = vnspc_global_variables_generate
176
};
177
178
static bool
179
vnspc_global_variables_validate(struct sieve_validator *valdtr,
180
        const struct sieve_variables_namespace *nspc,
181
        struct sieve_ast_argument *arg,
182
        struct sieve_command *cmd ATTR_UNUSED,
183
        ARRAY_TYPE(sieve_variable_name) *var_name,
184
        void **var_data, bool assignment ATTR_UNUSED)
185
0
{
186
0
  const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc);
187
0
  struct sieve_ast *ast = arg->ast;
188
0
  struct ext_include_context *extctx = ext_include_get_context(this_ext);
189
0
  struct ext_include_ast_context *ctx =
190
0
    ext_include_get_ast_context(this_ext, ast);
191
0
  struct sieve_variable *var = NULL;
192
0
  const struct sieve_variable_name *name_element;
193
0
  const char *variable;
194
195
  /* Sanity safeguard */
196
0
  i_assert (ctx->global_vars != NULL);
197
198
  /* Check variable name */
199
200
0
  if (array_count(var_name) != 2) {
201
0
    sieve_argument_validate_error(
202
0
      valdtr, arg,
203
0
      "invalid variable name within global namespace: "
204
0
      "encountered sub-namespace");
205
0
    return FALSE;
206
0
  }
207
208
0
  name_element = array_idx(var_name, 1);
209
0
  if (name_element->num_variable >= 0) {
210
0
    sieve_argument_validate_error(
211
0
      valdtr, arg,
212
0
      "invalid variable name within global namespace: "
213
0
      "encountered numeric variable name");
214
0
    return FALSE;
215
0
  }
216
217
0
  variable = str_c(name_element->identifier);
218
219
  /* Get/Declare the variable in the global scope */
220
221
0
  var = sieve_variable_scope_declare(ctx->global_vars, variable);
222
0
  if (var == NULL) {
223
0
    sieve_argument_validate_error(
224
0
      valdtr, arg,
225
0
      "(implicit) declaration of new global variable '%s' "
226
0
      "exceeds the limit (max variables: %u)", variable,
227
0
      sieve_variables_get_max_scope_count(extctx->var_ext));
228
0
    return FALSE;
229
0
  }
230
231
0
  *var_data = var;
232
0
  return TRUE;
233
0
}
234
235
bool vnspc_global_variables_generate(
236
  const struct sieve_codegen_env *cgenv,
237
  const struct sieve_variables_namespace *nspc,
238
  struct sieve_ast_argument *arg ATTR_UNUSED,
239
  struct sieve_command *cmd ATTR_UNUSED, void *var_data)
240
0
{
241
0
  const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc);
242
0
  struct ext_include_context *extctx = ext_include_get_context(this_ext);
243
0
  struct sieve_variable *var = (struct sieve_variable *)var_data;
244
245
0
  sieve_variables_opr_variable_emit(cgenv->sblock, extctx->var_ext, var);
246
0
  return TRUE;
247
0
}
248
249
void ext_include_variables_global_namespace_init(
250
  const struct sieve_extension *this_ext, struct sieve_validator *valdtr)
251
0
{
252
0
  struct ext_include_context *extctx = ext_include_get_context(this_ext);
253
254
0
  sieve_variables_namespace_register(extctx->var_ext, valdtr, this_ext,
255
0
             &global_variables_namespace);
256
0
}