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