Coverage Report

Created: 2026-08-08 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/sieve-comparators.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "str-sanitize.h"
5
#include "hash.h"
6
#include "array.h"
7
8
#include "sieve-extensions.h"
9
#include "sieve-code.h"
10
#include "sieve-commands.h"
11
#include "sieve-binary.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-comparators.h"
18
19
#include <string.h>
20
#include <stdio.h>
21
22
/*
23
 * Core comparators
24
 */
25
26
const struct sieve_comparator_def *sieve_core_comparators[] = {
27
  &i_octet_comparator, &i_ascii_casemap_comparator,
28
  &i_unicode_casemap_comparator
29
};
30
31
const unsigned int sieve_core_comparators_count =
32
  N_ELEMENTS(sieve_core_comparators);
33
34
/*
35
 * Comparator 'extension'
36
 */
37
38
static bool
39
cmp_validator_load(const struct sieve_extension *ext,
40
       struct sieve_validator *valdtr);
41
42
const struct sieve_extension_def comparator_extension = {
43
  .name = "@comparators",
44
  .validator_load = cmp_validator_load
45
};
46
47
/*
48
 * Validator context:
49
 *   name-based comparator registry.
50
 */
51
52
static struct sieve_validator_object_registry *
53
_get_object_registry(struct sieve_validator *valdtr)
54
0
{
55
0
  struct sieve_instance *svinst;
56
0
  const struct sieve_extension *mcht_ext;
57
58
0
  svinst = sieve_validator_svinst(valdtr);
59
0
  mcht_ext = sieve_get_comparator_extension(svinst);
60
0
  return sieve_validator_object_registry_get(valdtr, mcht_ext);
61
0
}
62
63
void sieve_comparator_register(struct sieve_validator *valdtr,
64
             const struct sieve_extension *ext,
65
             const struct sieve_comparator_def *cmp)
66
0
{
67
0
  struct sieve_validator_object_registry *regs =
68
0
    _get_object_registry(valdtr);
69
70
0
  sieve_validator_object_registry_add(regs, ext, &cmp->obj_def);
71
0
}
72
73
static struct sieve_comparator *
74
sieve_comparator_create(struct sieve_validator *valdtr,
75
      struct sieve_command *cmd, const char *identifier)
76
0
{
77
0
  struct sieve_validator_object_registry *regs =
78
0
    _get_object_registry(valdtr);
79
0
  struct sieve_object object;
80
0
  struct sieve_comparator *cmp;
81
82
0
  if (!sieve_validator_object_registry_find(regs, identifier, &object))
83
0
    return NULL;
84
85
0
  cmp = p_new(sieve_command_pool(cmd), struct sieve_comparator, 1);
86
0
  cmp->object = object;
87
0
  cmp->def = (const struct sieve_comparator_def *) object.def;
88
89
0
  return cmp;
90
0
}
91
92
bool cmp_validator_load(const struct sieve_extension *ext,
93
      struct sieve_validator *valdtr)
94
0
{
95
0
  struct sieve_validator_object_registry *regs =
96
0
    sieve_validator_object_registry_init(valdtr, ext);
97
0
  unsigned int i;
98
99
  /* Register core comparators */
100
0
  for (i = 0; i < sieve_core_comparators_count; i++) {
101
0
    sieve_validator_object_registry_add(
102
0
      regs, NULL, &(sieve_core_comparators[i]->obj_def));
103
0
  }
104
0
  return TRUE;
105
0
}
106
107
/*
108
 * Comparator tagged argument
109
 */
110
111
/* Forward declarations */
112
113
static bool
114
tag_comparator_validate(struct sieve_validator *valdtr,
115
      struct sieve_ast_argument **arg,
116
      struct sieve_command *cmd);
117
static bool
118
tag_comparator_generate(const struct sieve_codegen_env *cgenv,
119
      struct sieve_ast_argument *arg,
120
      struct sieve_command *cmd);
121
122
/* Argument object */
123
124
const struct sieve_argument_def comparator_tag = {
125
  .identifier = "comparator",
126
  .validate = tag_comparator_validate,
127
  .generate = tag_comparator_generate
128
};
129
130
/* Argument implementation */
131
132
static bool
133
tag_comparator_validate(struct sieve_validator *valdtr,
134
      struct sieve_ast_argument **arg,
135
      struct sieve_command *cmd)
136
0
{
137
0
  struct sieve_ast_argument *tag = *arg;
138
0
  const struct sieve_comparator *cmp;
139
140
  /* Skip tag */
141
0
  *arg = sieve_ast_argument_next(*arg);
142
143
  /* Check syntax:
144
   *   ":comparator" <comparator-name: string>
145
   */
146
0
  if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0,
147
0
            SAAT_STRING, FALSE) ) {
148
0
    return FALSE;
149
0
  }
150
151
  /* FIXME: We can currently only handle string literal argument, so
152
   * variables are not allowed.
153
   */
154
0
  if (!sieve_argument_is_string_literal(*arg)) {
155
0
    sieve_argument_validate_error(
156
0
      valdtr, *arg,
157
0
      "this Sieve implementation currently only supports "
158
0
      "a literal string argument for the :comparator tag");
159
0
    return FALSE;
160
0
  }
161
162
  /* Get comparator from registry */
163
0
  cmp = sieve_comparator_create(valdtr, cmd,
164
0
              sieve_ast_argument_strc(*arg));
165
0
  if (cmp == NULL) {
166
0
    sieve_argument_validate_error(
167
0
      valdtr, *arg, "unknown comparator '%s'",
168
0
      str_sanitize(sieve_ast_argument_strc(*arg),80));
169
0
    return FALSE;
170
0
  }
171
172
  /* String argument not needed during code generation, so detach it from
173
   * argument list
174
   */
175
0
  *arg = sieve_ast_arguments_detach(*arg, 1);
176
177
  /* Store comparator in context */
178
0
  tag->argument->data = (void *)cmp;
179
180
0
  return TRUE;
181
0
}
182
183
static bool
184
tag_comparator_generate(const struct sieve_codegen_env *cgenv,
185
      struct sieve_ast_argument *arg,
186
      struct sieve_command *cmd ATTR_UNUSED)
187
0
{
188
0
  const struct sieve_comparator *cmp =
189
0
    (const struct sieve_comparator *)arg->argument->data;
190
191
0
  sieve_opr_comparator_emit(cgenv->sblock, cmp);
192
0
  return TRUE;
193
0
}
194
195
/* Functions to enable and evaluate comparator tag for commands */
196
197
void sieve_comparators_link_tag(struct sieve_validator *valdtr,
198
        struct sieve_command_registration *cmd_reg,
199
        int id_code)
200
0
{
201
0
  struct sieve_instance *svinst;
202
0
  const struct sieve_extension *mcht_ext;
203
204
0
  svinst = sieve_validator_svinst(valdtr);
205
0
  mcht_ext = sieve_get_comparator_extension(svinst);
206
207
0
  sieve_validator_register_tag(valdtr, cmd_reg, mcht_ext,
208
0
             &comparator_tag, id_code);
209
0
}
210
211
bool sieve_comparator_tag_is(struct sieve_ast_argument *tag,
212
           const struct sieve_comparator_def *cmp_def)
213
0
{
214
0
  const struct sieve_comparator *cmp;
215
216
0
  if (!sieve_argument_is(tag, comparator_tag))
217
0
    return FALSE;
218
219
0
  cmp = (const struct sieve_comparator *)tag->argument->data;
220
221
0
  return (cmp->def == cmp_def);
222
0
}
223
224
const struct sieve_comparator *
225
sieve_comparator_tag_get(struct sieve_ast_argument *tag)
226
0
{
227
0
  if (!sieve_argument_is(tag, comparator_tag))
228
0
    return NULL;
229
230
0
  return (const struct sieve_comparator *)tag->argument->data;
231
0
}
232
233
/*
234
 * Comparator coding
235
 */
236
237
const struct sieve_operand_class sieve_comparator_operand_class =
238
  { "comparator" };
239
240
static const struct sieve_extension_objects core_comparators =
241
  SIEVE_EXT_DEFINE_COMPARATORS(sieve_core_comparators);
242
243
const struct sieve_operand_def comparator_operand = {
244
  .name = "comparator",
245
  .code = SIEVE_OPERAND_COMPARATOR,
246
  .class = &sieve_comparator_operand_class,
247
  .interface = &core_comparators
248
};
249
250
/*
251
 * Trivial/Common comparator method implementations
252
 */
253
254
bool sieve_comparator_octet_skip(const struct sieve_comparator *cmp ATTR_UNUSED,
255
         const char **val, const char *val_end)
256
0
{
257
0
  if (*val < val_end) {
258
0
    (*val)++;
259
0
    return TRUE;
260
0
  }
261
0
  return FALSE;
262
0
}