Coverage Report

Created: 2026-06-15 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/testsuite/cmd-test-config.c
Line
Count
Source
1
/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2
 */
3
4
#include "sieve-common.h"
5
#include "sieve-extensions.h"
6
#include "sieve-commands.h"
7
#include "sieve-validator.h"
8
#include "sieve-generator.h"
9
#include "sieve-interpreter.h"
10
#include "sieve-code.h"
11
#include "sieve-binary.h"
12
#include "sieve-dump.h"
13
14
#include "testsuite-common.h"
15
#include "testsuite-settings.h"
16
17
/*
18
 * Commands
19
 */
20
21
static bool
22
cmd_test_config_generate(const struct sieve_codegen_env *cgenv,
23
       struct sieve_command *ctx);
24
25
/* Test_config_set command
26
 *
27
 * Syntax:
28
 *   test_config_set <setting: string> <value: string>
29
 */
30
31
static bool
32
cmd_test_config_set_validate(struct sieve_validator *valdtr,
33
           struct sieve_command *cmd);
34
35
const struct sieve_command_def cmd_test_config_set = {
36
  .identifier = "test_config_set",
37
  .type = SCT_COMMAND,
38
  .positional_args = 2,
39
  .subtests = 0,
40
  .block_allowed = FALSE,
41
  .block_required = FALSE,
42
  .validate = cmd_test_config_set_validate,
43
  .generate = cmd_test_config_generate,
44
};
45
46
/* Test_config_unset command
47
 *
48
 * Syntax:
49
 *   test_config_unset <setting: string>
50
 */
51
52
static bool
53
cmd_test_config_unset_validate(struct sieve_validator *valdtr,
54
             struct sieve_command *cmd);
55
56
const struct sieve_command_def cmd_test_config_unset = {
57
  .identifier = "test_config_unset",
58
  .type = SCT_COMMAND,
59
  .positional_args = 1,
60
  .subtests = 0,
61
  .block_allowed = FALSE,
62
  .block_required = FALSE,
63
  .validate = cmd_test_config_unset_validate,
64
  .generate = cmd_test_config_generate,
65
};
66
67
/* Test_config_reload command
68
 *
69
 * Syntax:
70
 *   test_config_reload [:extension <extension: string>]
71
 */
72
73
static bool
74
cmd_test_config_reload_registered(struct sieve_validator *valdtr,
75
          const struct sieve_extension *ext,
76
          struct sieve_command_registration *cmd_reg);
77
78
const struct sieve_command_def cmd_test_config_reload = {
79
  .identifier = "test_config_reload",
80
  .type = SCT_COMMAND,
81
  .positional_args = 0,
82
  .subtests = 0,
83
  .block_allowed = FALSE,
84
  .block_required = FALSE,
85
  .registered = cmd_test_config_reload_registered,
86
  .generate = cmd_test_config_generate,
87
};
88
89
/*
90
 * Command tags
91
 */
92
93
/* Forward declarations */
94
95
static bool
96
cmd_test_config_reload_validate_tag(struct sieve_validator *valdtr,
97
            struct sieve_ast_argument **arg,
98
            struct sieve_command *cmd);
99
100
/* Argument objects */
101
102
static const struct sieve_argument_def test_config_reload_extension_tag = {
103
  .identifier = "extension",
104
  .validate = cmd_test_config_reload_validate_tag,
105
};
106
107
/* Codes for optional arguments */
108
109
enum cmd_test_config_optional {
110
  OPT_END,
111
  OPT_EXTENSION,
112
};
113
114
/*
115
 * Operations
116
 */
117
118
/* Test_config_set operation */
119
120
static bool
121
cmd_test_config_set_operation_dump(const struct sieve_dumptime_env *denv,
122
           sieve_size_t *address);
123
static int
124
cmd_test_config_set_operation_execute(const struct sieve_runtime_env *renv,
125
              sieve_size_t *address);
126
127
const struct sieve_operation_def test_config_set_operation = {
128
  .mnemonic = "TEST_CONFIG_SET",
129
  .ext_def = &testsuite_extension,
130
  .code = TESTSUITE_OPERATION_TEST_CONFIG_SET,
131
  .dump = cmd_test_config_set_operation_dump,
132
  .execute = cmd_test_config_set_operation_execute,
133
};
134
135
/* Test_config_unset operation */
136
137
static bool
138
cmd_test_config_unset_operation_dump(const struct sieve_dumptime_env *denv,
139
             sieve_size_t *address);
140
static int
141
cmd_test_config_unset_operation_execute(const struct sieve_runtime_env *renv,
142
          sieve_size_t *address);
143
144
const struct sieve_operation_def test_config_unset_operation = {
145
  .mnemonic = "TEST_CONFIG_UNSET",
146
  .ext_def = &testsuite_extension,
147
  .code = TESTSUITE_OPERATION_TEST_CONFIG_UNSET,
148
  .dump = cmd_test_config_unset_operation_dump,
149
  .execute = cmd_test_config_unset_operation_execute,
150
};
151
152
/* Test_config_read operation */
153
154
static bool
155
cmd_test_config_reload_operation_dump(const struct sieve_dumptime_env *denv,
156
              sieve_size_t *address);
157
static int
158
cmd_test_config_reload_operation_execute(const struct sieve_runtime_env *renv,
159
           sieve_size_t *address);
160
161
const struct sieve_operation_def test_config_reload_operation = {
162
  .mnemonic = "TEST_CONFIG_RELOAD",
163
  .ext_def = &testsuite_extension,
164
  .code = TESTSUITE_OPERATION_TEST_CONFIG_RELOAD,
165
  .dump = cmd_test_config_reload_operation_dump,
166
  .execute = cmd_test_config_reload_operation_execute,
167
};
168
169
/*
170
 * Tag validation
171
 */
172
173
static bool
174
cmd_test_config_reload_validate_tag(struct sieve_validator *valdtr,
175
            struct sieve_ast_argument **arg,
176
            struct sieve_command *cmd)
177
0
{
178
0
  struct sieve_ast_argument *tag = *arg;
179
180
  /* Detach the tag itself */
181
0
  *arg = sieve_ast_arguments_detach(*arg,1);
182
183
  /* Check syntax:
184
   *   :extension <extension: string>
185
   */
186
0
  if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
187
0
            SAAT_STRING, TRUE))
188
0
    return FALSE;
189
190
  /* Skip parameter */
191
0
  *arg = sieve_ast_argument_next(*arg);
192
193
0
  return TRUE;
194
0
}
195
196
/*
197
 * Command registration
198
 */
199
200
static bool
201
cmd_test_config_reload_registered(struct sieve_validator *valdtr,
202
          const struct sieve_extension *ext,
203
          struct sieve_command_registration *cmd_reg)
204
0
{
205
0
  sieve_validator_register_tag(valdtr, cmd_reg, ext,
206
0
             &test_config_reload_extension_tag,
207
0
             OPT_EXTENSION);
208
0
  return TRUE;
209
0
}
210
211
/*
212
 * Command validation
213
 */
214
215
static bool
216
cmd_test_config_set_validate(struct sieve_validator *valdtr,
217
           struct sieve_command *cmd)
218
0
{
219
0
  struct sieve_ast_argument *arg = cmd->first_positional;
220
221
  /* Check syntax:
222
   *   <setting: string> <value: string>
223
   */
224
225
0
  if (!sieve_validate_positional_argument(valdtr, cmd, arg, "setting",
226
0
            1, SAAT_STRING))
227
0
    return FALSE;
228
0
  if (!sieve_validator_argument_activate(valdtr, cmd, arg, FALSE))
229
0
    return FALSE;
230
231
0
  arg = sieve_ast_argument_next(arg);
232
233
0
  if (!sieve_validate_positional_argument(valdtr, cmd, arg, "value", 2,
234
0
            SAAT_STRING))
235
0
    return FALSE;
236
0
  return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE);
237
0
}
238
239
static bool
240
cmd_test_config_unset_validate(struct sieve_validator *valdtr,
241
             struct sieve_command *cmd)
242
0
{
243
0
  struct sieve_ast_argument *arg = cmd->first_positional;
244
245
  /* Check syntax:
246
   *   <setting: string>
247
   */
248
0
  if (!sieve_validate_positional_argument(valdtr, cmd, arg, "setting", 1,
249
0
            SAAT_STRING))
250
0
    return FALSE;
251
0
  return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE);
252
0
}
253
254
/*
255
 * Code generation
256
 */
257
258
static bool
259
cmd_test_config_generate(const struct sieve_codegen_env *cgenv,
260
       struct sieve_command *cmd)
261
0
{
262
0
  if (sieve_command_is(cmd, cmd_test_config_set)) {
263
0
    sieve_operation_emit(cgenv->sblock, cmd->ext,
264
0
             &test_config_set_operation);
265
0
  } else if (sieve_command_is(cmd, cmd_test_config_unset)) {
266
0
    sieve_operation_emit(cgenv->sblock, cmd->ext,
267
0
             &test_config_unset_operation);
268
0
  } else if (sieve_command_is(cmd, cmd_test_config_reload)) {
269
0
    sieve_operation_emit(cgenv->sblock, cmd->ext,
270
0
             &test_config_reload_operation);
271
0
  } else {
272
0
    i_unreached();
273
0
  }
274
275
  /* Generate arguments */
276
0
  if (!sieve_generate_arguments(cgenv, cmd, NULL))
277
0
    return FALSE;
278
0
  return TRUE;
279
0
}
280
281
/*
282
 * Code dump
283
 */
284
285
static bool
286
cmd_test_config_set_operation_dump(const struct sieve_dumptime_env *denv,
287
           sieve_size_t *address)
288
0
{
289
0
  sieve_code_dumpf(denv, "TEST_CONFIG_SET:");
290
291
0
  sieve_code_descend(denv);
292
293
0
  return (sieve_opr_string_dump(denv, address, "setting") &&
294
0
    sieve_opr_string_dump(denv, address, "value"));
295
0
}
296
297
static bool
298
cmd_test_config_unset_operation_dump(const struct sieve_dumptime_env *denv,
299
             sieve_size_t *address)
300
0
{
301
0
  sieve_code_dumpf(denv, "TEST_CONFIG_UNSET:");
302
303
0
  sieve_code_descend(denv);
304
305
0
  return sieve_opr_string_dump(denv, address, "setting");
306
0
}
307
308
static bool
309
cmd_test_config_reload_operation_dump(const struct sieve_dumptime_env *denv,
310
              sieve_size_t *address)
311
0
{
312
0
  int opt_code = 0;
313
314
0
  sieve_code_dumpf(denv, "TEST_CONFIG_RELOAD:");
315
0
  sieve_code_descend(denv);
316
317
  /* Dump optional operands */
318
319
0
  for (;;) {
320
0
    int opt;
321
0
    bool opok = TRUE;
322
323
0
    opt = sieve_opr_optional_dump(denv, address, &opt_code);
324
0
    if (opt < 0)
325
0
      return FALSE;
326
0
    if (opt == 0)
327
0
      break;
328
329
0
    switch (opt_code) {
330
0
    case OPT_EXTENSION:
331
0
      opok = sieve_opr_string_dump(denv, address,
332
0
                 "extensions");
333
0
      break;
334
0
    default:
335
0
      opok = FALSE;
336
0
      break;
337
0
    }
338
339
0
    if (!opok)
340
0
      return FALSE;
341
0
  }
342
343
0
  return TRUE;
344
0
}
345
346
/*
347
 * Interpretation
348
 */
349
350
static int
351
cmd_test_config_set_operation_execute(const struct sieve_runtime_env *renv,
352
              sieve_size_t *address)
353
0
{
354
0
  string_t *setting;
355
0
  string_t *value;
356
0
  int ret;
357
358
  /*
359
   * Read operands
360
   */
361
362
  /* Setting */
363
0
  ret = sieve_opr_string_read(renv, address, "setting", &setting);
364
0
  if (ret <= 0)
365
0
    return ret;
366
367
  /* Value */
368
0
  ret = sieve_opr_string_read(renv, address, "value", &value);
369
0
  if (ret <= 0)
370
0
    return ret;
371
372
  /*
373
   * Perform operation
374
   */
375
376
0
  if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
377
0
    sieve_runtime_trace(
378
0
      renv, 0, "testsuite: test_config_set command");
379
0
    sieve_runtime_trace_descend(renv);
380
0
    sieve_runtime_trace(
381
0
      renv, 0, "set config '%s' = '%s'",
382
0
      str_c(setting), str_c(value));
383
0
  }
384
385
0
  testsuite_setting_set(str_c(setting), str_c(value));
386
387
0
  return SIEVE_EXEC_OK;
388
0
}
389
390
static int
391
cmd_test_config_unset_operation_execute(const struct sieve_runtime_env *renv,
392
          sieve_size_t *address)
393
0
{
394
0
  string_t *setting;
395
0
  int ret;
396
397
  /*
398
   * Read operands
399
   */
400
401
  /* Setting */
402
0
  ret = sieve_opr_string_read(renv, address, "setting", &setting);
403
0
  if (ret <= 0)
404
0
    return ret;
405
406
  /*
407
   * Perform operation
408
   */
409
410
0
  if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
411
0
    sieve_runtime_trace(
412
0
      renv, 0, "testsuite: test_config_unset command");
413
0
    sieve_runtime_trace_descend(renv);
414
0
    sieve_runtime_trace(
415
0
      renv, 0, "unset config '%s'", str_c(setting));
416
0
  }
417
418
0
  testsuite_setting_unset(str_c(setting));
419
420
0
  return SIEVE_EXEC_OK;
421
0
}
422
423
static int
424
cmd_test_config_reload_operation_execute(const struct sieve_runtime_env *renv,
425
           sieve_size_t *address)
426
0
{
427
0
  const struct sieve_execute_env *eenv = renv->exec_env;
428
0
  const struct sieve_extension *ext;
429
0
  int opt_code = 0;
430
0
  string_t *extension = NULL;
431
0
  int ret;
432
433
  /*
434
   * Read operands
435
   */
436
437
  /* Optional operands */
438
0
  for (;;) {
439
0
    int opt;
440
441
0
    opt = sieve_opr_optional_read(renv, address, &opt_code);
442
0
    if (opt < 0)
443
0
      return SIEVE_EXEC_BIN_CORRUPT;
444
0
    if (opt == 0)
445
0
      break;
446
447
0
    switch (opt_code) {
448
0
    case OPT_EXTENSION:
449
0
      ret = sieve_opr_string_read(renv, address, "extension",
450
0
                &extension);
451
0
      break;
452
0
    default:
453
0
      sieve_runtime_trace_error(
454
0
        renv, "unknown optional operand");
455
0
      ret = SIEVE_EXEC_BIN_CORRUPT;
456
0
    }
457
458
0
    if (ret <= 0)
459
0
      return ret;
460
0
  }
461
462
  /*
463
   * Perform operation
464
   */
465
466
0
  if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
467
0
    sieve_runtime_trace(
468
0
      renv, 0, "testsuite: test_config_reload command");
469
0
    sieve_runtime_trace_descend(renv);
470
0
  }
471
472
0
  if (extension == NULL) {
473
0
    if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
474
0
      sieve_runtime_trace(
475
0
        renv, 0,
476
0
        "reload configuration for sieve engine");
477
0
    }
478
479
0
    if (sieve_settings_reload(eenv->svinst) < 0) {
480
0
      if (!testsuite_silent) {
481
0
        printf("ERROR: "
482
0
               "Failed to reload sieve engine settings\n");
483
0
      }
484
0
      return SIEVE_EXEC_FAILURE;
485
0
    }
486
0
  } else {
487
0
    if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
488
0
      sieve_runtime_trace(
489
0
        renv, 0,
490
0
        "reload configuration for extension '%s'",
491
0
        str_c(extension));
492
0
    }
493
494
0
    ext = sieve_extension_get_by_name(eenv->svinst,
495
0
              str_c(extension));
496
0
    if (ext == NULL) {
497
0
      if (!testsuite_silent) {
498
0
        printf("ERROR: Unknown extension '%s'\n",
499
0
               str_c(extension));
500
0
      }
501
0
      return SIEVE_EXEC_FAILURE;
502
0
    }
503
0
    if (sieve_extension_reload(ext) < 0) {
504
0
      if (!testsuite_silent) {
505
0
        printf("ERROR: Failed to load extension '%s'\n",
506
0
               str_c(extension));
507
0
      }
508
0
      return SIEVE_EXEC_FAILURE;
509
0
    }
510
0
  }
511
0
  return SIEVE_EXEC_OK;
512
0
}