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