Coverage Report

Created: 2026-10-28 07:22

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