Coverage Report

Created: 2026-04-12 07:00

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