Coverage Report

Created: 2026-06-15 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c
Line
Count
Source
1
/* Copyright (c) 2015-2018 Pigeonhole authors, see the included COPYING file
2
 */
3
4
#include "lib.h"
5
#include "str.h"
6
7
#include "sieve-common.h"
8
#include "sieve-ast.h"
9
#include "sieve-binary.h"
10
#include "sieve-code.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-vnd-environment-common.h"
20
21
static bool
22
vnspc_vnd_environment_validate(struct sieve_validator *valdtr,
23
             const struct sieve_variables_namespace *nspc,
24
             struct sieve_ast_argument *arg,
25
             struct sieve_command *cmd,
26
             ARRAY_TYPE(sieve_variable_name) *var_name,
27
             void **var_data, bool assignment);
28
static bool
29
vnspc_vnd_environment_generate(const struct sieve_codegen_env *cgenv,
30
             const struct sieve_variables_namespace *nspc,
31
             struct sieve_ast_argument *arg,
32
             struct sieve_command *cmd, void *var_data);
33
static bool
34
vnspc_vnd_environment_dump_variable(
35
  const struct sieve_dumptime_env *denv,
36
  const struct sieve_variables_namespace *nspc,
37
  const struct sieve_operand *oprnd, sieve_size_t *address);
38
static int
39
vnspc_vnd_environment_read_variable(
40
  const struct sieve_runtime_env *renv,
41
  const struct sieve_variables_namespace *nspc,
42
  const struct sieve_operand *oprnd,
43
  sieve_size_t *address, string_t **str_r);
44
45
static const struct sieve_variables_namespace_def
46
environment_namespace = {
47
  SIEVE_OBJECT("env", &environment_namespace_operand, 0),
48
  .validate = vnspc_vnd_environment_validate,
49
  .generate = vnspc_vnd_environment_generate,
50
  .dump_variable = vnspc_vnd_environment_dump_variable,
51
  .read_variable = vnspc_vnd_environment_read_variable,
52
};
53
54
static bool
55
vnspc_vnd_environment_validate(
56
  struct sieve_validator *valdtr,
57
  const struct sieve_variables_namespace *nspc ATTR_UNUSED,
58
  struct sieve_ast_argument *arg, struct sieve_command *cmd ATTR_UNUSED,
59
  ARRAY_TYPE(sieve_variable_name) *var_name, void **var_data,
60
  bool assignment)
61
0
{
62
0
  struct sieve_ast *ast = arg->ast;
63
0
  const struct sieve_variable_name *name_elements;
64
0
  unsigned int i, count;
65
0
  const char *variable;
66
0
  string_t *name;
67
68
  /* Compose environment name from parsed variable name */
69
0
  name = t_str_new(64);
70
0
  name_elements = array_get(var_name, &count);
71
0
  i_assert(count > 1);
72
0
  for (i = 1; i < count; i++) {
73
0
    if (name_elements[i].num_variable >= 0) {
74
0
      sieve_argument_validate_error(
75
0
        valdtr, arg, "vnd.dovecot.environment: "
76
0
        "invalid variable name within env namespace 'env.%d': "
77
0
        "encountered numeric variable name",
78
0
        name_elements[i].num_variable);
79
0
      return FALSE;
80
0
    }
81
0
    if (str_len(name) > 0)
82
0
      str_append_c(name, '.');
83
0
    str_append_str(name, name_elements[i].identifier);
84
0
  }
85
86
0
  variable = str_c(name);
87
88
0
  if (assignment) {
89
0
    sieve_argument_validate_error(
90
0
      valdtr, arg, "vnd.dovecot.environment: "
91
0
      "cannot assign to environment variable 'env.%s'",
92
0
      variable);
93
0
    return FALSE;
94
0
  }
95
96
0
  *var_data = p_strdup(sieve_ast_pool(ast), variable);
97
0
  return TRUE;
98
0
}
99
100
static bool
101
vnspc_vnd_environment_generate(const struct sieve_codegen_env *cgenv,
102
             const struct sieve_variables_namespace *nspc,
103
             struct sieve_ast_argument *arg ATTR_UNUSED,
104
             struct sieve_command *cmd ATTR_UNUSED,
105
             void *var_data)
106
0
{
107
0
  const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc);
108
0
  const char *variable = (const char *) var_data;
109
0
  struct ext_vnd_environment_context *extctx;
110
111
0
  if (this_ext == NULL)
112
0
    return FALSE;
113
114
0
  extctx = (struct ext_vnd_environment_context *)this_ext->context;
115
116
0
  sieve_variables_opr_namespace_variable_emit(
117
0
    cgenv->sblock, extctx->var_ext, this_ext,
118
0
    &environment_namespace);
119
0
  sieve_binary_emit_cstring(cgenv->sblock, variable);
120
0
  return TRUE;
121
0
}
122
123
static bool
124
vnspc_vnd_environment_dump_variable(
125
  const struct sieve_dumptime_env *denv,
126
  const struct sieve_variables_namespace *nspc ATTR_UNUSED,
127
  const struct sieve_operand *oprnd, sieve_size_t *address)
128
0
{
129
0
  string_t *var_name;
130
131
0
  if (!sieve_binary_read_string(denv->sblock, address, &var_name))
132
0
    return FALSE;
133
134
0
  if (oprnd->field_name != NULL) {
135
0
    sieve_code_dumpf(denv, "%s: VAR ${env.%s}",
136
0
         oprnd->field_name, str_c(var_name));
137
0
  } else {
138
0
    sieve_code_dumpf(denv, "VAR ${env.%s}", str_c(var_name));
139
0
  }
140
0
  return TRUE;
141
0
}
142
143
static int
144
vnspc_vnd_environment_read_variable(
145
  const struct sieve_runtime_env *renv,
146
  const struct sieve_variables_namespace *nspc,
147
  const struct sieve_operand *oprnd, sieve_size_t *address,
148
  string_t **str_r)
149
0
{
150
0
  const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc);
151
0
  struct ext_vnd_environment_context *extctx = this_ext->context;
152
0
  string_t *var_name;
153
0
  const char *ext_value;
154
155
0
  if (!sieve_binary_read_string(renv->sblock, address, &var_name)) {
156
0
    sieve_runtime_trace_operand_error(
157
0
      renv, oprnd, "environment variable operand corrupt: "
158
0
      "invalid name");
159
0
    return SIEVE_EXEC_BIN_CORRUPT;
160
0
  }
161
162
0
  if (str_r !=  NULL) {
163
0
    const char *vname = str_c(var_name);
164
165
0
    ext_value = ext_environment_item_get_value(extctx->env_ext,
166
0
                 renv, vname);
167
0
    if (ext_value == NULL && strchr(vname, '_') != NULL) {
168
0
      char *p, *aname;
169
170
      /* Try again with '_' replaced with '-' */
171
0
      aname = t_strdup_noconst(vname);
172
0
      for (p = aname; *p != '\0'; p++) {
173
0
        if (*p == '_')
174
0
          *p = '-';
175
0
      }
176
0
      ext_value = ext_environment_item_get_value(
177
0
        extctx->env_ext, renv, aname);
178
0
    }
179
180
0
    if (ext_value == NULL) {
181
0
      *str_r = t_str_new_const("", 0);
182
0
      return SIEVE_EXEC_OK;
183
0
    }
184
185
0
    *str_r = t_str_new_const(ext_value, strlen(ext_value));
186
0
  }
187
0
  return SIEVE_EXEC_OK;
188
0
}
189
190
/*
191
 * Namespace registration
192
 */
193
194
static const struct sieve_extension_objects environment_namespaces =
195
  SIEVE_VARIABLES_DEFINE_NAMESPACE(environment_namespace);
196
197
const struct sieve_operand_def environment_namespace_operand = {
198
  .name = "env-namespace",
199
  .ext_def = &vnd_environment_extension,
200
  .class = &sieve_variables_namespace_operand_class,
201
  .interface = &environment_namespaces,
202
};
203
204
void ext_environment_variables_init(const struct sieve_extension *this_ext,
205
            struct sieve_validator *valdtr)
206
0
{
207
0
  struct ext_vnd_environment_context *extctx = this_ext->context;
208
209
0
  sieve_variables_namespace_register(extctx->var_ext, valdtr, this_ext,
210
0
             &environment_namespace);
211
0
}