Coverage Report

Created: 2026-06-15 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/plugins/relational/ext-relational-common.c
Line
Count
Source
1
/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2
 */
3
4
/* Syntax:
5
6
     MATCH-TYPE =/ COUNT / VALUE
7
     COUNT = ":count" relational-match
8
     VALUE = ":value" relational-match
9
     relational-match = DQUOTE ( "gt" / "ge" / "lt"
10
                               / "le" / "eq" / "ne" ) DQUOTE
11
 */
12
13
#include "lib.h"
14
#include "str.h"
15
#include "str-sanitize.h"
16
17
#include "sieve-common.h"
18
#include "sieve-ast.h"
19
#include "sieve-code.h"
20
#include "sieve-extensions.h"
21
#include "sieve-commands.h"
22
#include "sieve-comparators.h"
23
#include "sieve-match-types.h"
24
#include "sieve-validator.h"
25
#include "sieve-generator.h"
26
#include "sieve-interpreter.h"
27
28
#include "ext-relational-common.h"
29
30
/*
31
 * Forward declarations
32
 */
33
34
const struct sieve_match_type_def *rel_match_types[];
35
36
/*
37
 * Validation
38
 */
39
40
bool mcht_relational_validate(struct sieve_validator *valdtr,
41
            struct sieve_ast_argument **arg,
42
            struct sieve_match_type_context *ctx)
43
0
{
44
0
  struct sieve_match_type *mcht;
45
0
  enum relational_match rel_match = REL_MATCH_INVALID;
46
0
  pool_t pool = sieve_ast_argument_pool(ctx->argument);
47
0
  string_t *rel_match_ident;
48
49
  /* Check syntax:
50
       relational-match = DQUOTE ( "gt" / "ge" / "lt"
51
                                 / "le" / "eq" / "ne" ) DQUOTE
52
53
     So, actually this must be a constant string and it is implemented as
54
     such.
55
   */
56
57
  /* Did we get a string in the first place? */
58
0
  if (*arg == NULL || (*arg)->type != SAAT_STRING) {
59
0
    sieve_argument_validate_error(
60
0
      valdtr, (*arg == NULL ? ctx->argument : *arg),
61
0
      "the :%s match-type requires a constant string argument being "
62
0
      "one of \"gt\", \"ge\", \"lt\", \"le\", \"eq\" or \"ne\", "
63
0
      "but %s was found",
64
0
      sieve_match_type_name(ctx->match_type),
65
0
      (*arg == NULL ?
66
0
       "none" : sieve_ast_argument_name(*arg)));
67
0
    return FALSE;
68
0
  }
69
70
  /* Check the relational match id */
71
72
0
  rel_match_ident = sieve_ast_argument_str(*arg);
73
0
  if (str_len(rel_match_ident) == 2) {
74
0
    const char *rel_match_id = str_c(rel_match_ident);
75
76
0
    switch (rel_match_id[0]) {
77
    /* "gt" or "ge" */
78
0
    case 'g':
79
0
      switch (rel_match_id[1]) {
80
0
      case 't':
81
0
        rel_match = REL_MATCH_GREATER;
82
0
        break;
83
0
      case 'e':
84
0
        rel_match = REL_MATCH_GREATER_EQUAL;
85
0
        break;
86
0
      default:
87
0
        rel_match = REL_MATCH_INVALID;
88
0
      }
89
0
      break;
90
    /* "lt" or "le" */
91
0
    case 'l':
92
0
      switch (rel_match_id[1]) {
93
0
      case 't':
94
0
        rel_match = REL_MATCH_LESS;
95
0
        break;
96
0
      case 'e':
97
0
        rel_match = REL_MATCH_LESS_EQUAL;
98
0
        break;
99
0
      default:
100
0
        rel_match = REL_MATCH_INVALID;
101
0
      }
102
0
      break;
103
    /* "eq" */
104
0
    case 'e':
105
0
      if (rel_match_id[1] == 'q')
106
0
        rel_match = REL_MATCH_EQUAL;
107
0
      else
108
0
        rel_match = REL_MATCH_INVALID;
109
0
      break;
110
    /* "ne" */
111
0
    case 'n':
112
0
      if (rel_match_id[1] == 'e')
113
0
        rel_match = REL_MATCH_NOT_EQUAL;
114
0
      else
115
0
        rel_match = REL_MATCH_INVALID;
116
0
      break;
117
    /* invalid */
118
0
    default:
119
0
      rel_match = REL_MATCH_INVALID;
120
0
    }
121
0
  }
122
123
0
  if (rel_match >= REL_MATCH_INVALID) {
124
0
    sieve_argument_validate_error(
125
0
      valdtr, *arg,
126
0
      "the :%s match-type requires a constant string argument being "
127
0
      "one of \"gt\", \"ge\", \"lt\", \"le\", \"eq\" or \"ne\", "
128
0
      "but \"%s\" was found",
129
0
      sieve_match_type_name(ctx->match_type),
130
0
      str_sanitize(str_c(rel_match_ident), 32));
131
0
    return FALSE;
132
0
  }
133
134
  /* Delete argument */
135
0
  *arg = sieve_ast_arguments_detach(*arg, 1);
136
137
  /* Not used just yet */
138
0
  ctx->ctx_data = (void *)rel_match;
139
140
  /* Override the actual match type with a parameter-specific one
141
   * FIXME: ugly!
142
   */
143
0
  mcht = p_new(pool, struct sieve_match_type, 1);
144
0
  mcht->object.ext = ctx->match_type->object.ext;
145
0
  SIEVE_OBJECT_SET_DEF(mcht, rel_match_types[
146
0
    REL_MATCH_INDEX(ctx->match_type->object.def->code, rel_match)]);
147
0
  ctx->match_type = mcht;
148
149
0
  return TRUE;
150
0
}
151
152
/*
153
 * Relational match-type operand
154
 */
155
156
const struct sieve_match_type_def *rel_match_types[] = {
157
  &rel_match_value_gt, &rel_match_value_ge, &rel_match_value_lt,
158
  &rel_match_value_le, &rel_match_value_eq, &rel_match_value_ne,
159
  &rel_match_count_gt, &rel_match_count_ge, &rel_match_count_lt,
160
  &rel_match_count_le, &rel_match_count_eq, &rel_match_count_ne,
161
};
162
163
static const struct sieve_extension_objects ext_match_types =
164
  SIEVE_EXT_DEFINE_MATCH_TYPES(rel_match_types);
165
166
const struct sieve_operand_def rel_match_type_operand = {
167
  .name = "relational match",
168
  .ext_def = &relational_extension,
169
  .class = &sieve_match_type_operand_class,
170
  .interface = &ext_match_types,
171
};