Coverage Report

Created: 2026-07-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/plugins/relational/mcht-count.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
/* Match-type ':count'
4
 */
5
6
#include "lib.h"
7
#include "str.h"
8
#include "str-sanitize.h"
9
10
#include "sieve-common.h"
11
#include "sieve-ast.h"
12
#include "sieve-stringlist.h"
13
#include "sieve-code.h"
14
#include "sieve-extensions.h"
15
#include "sieve-commands.h"
16
#include "sieve-comparators.h"
17
#include "sieve-match-types.h"
18
#include "sieve-validator.h"
19
#include "sieve-generator.h"
20
#include "sieve-interpreter.h"
21
#include "sieve-runtime-trace.h"
22
#include "sieve-match.h"
23
24
#include "ext-relational-common.h"
25
26
/*
27
 * Forward declarations
28
 */
29
30
static int
31
mcht_count_match(struct sieve_match_context *mctx,
32
     struct sieve_stringlist *value_list,
33
     struct sieve_stringlist *key_list);
34
35
/*
36
 * Match-type objects
37
 */
38
39
const struct sieve_match_type_def count_match_type = {
40
  SIEVE_OBJECT("count",
41
    &rel_match_type_operand, RELATIONAL_COUNT),
42
  .validate = mcht_relational_validate,
43
};
44
45
#define COUNT_MATCH_TYPE(name, rel_match)                           \
46
const struct sieve_match_type_def rel_match_count_ ## name = {      \
47
  SIEVE_OBJECT("count-" #name,                                \
48
         &rel_match_type_operand,                       \
49
         REL_MATCH_INDEX(RELATIONAL_COUNT, rel_match)), \
50
  .match = mcht_count_match,                                  \
51
}
52
53
COUNT_MATCH_TYPE(gt, REL_MATCH_GREATER);
54
COUNT_MATCH_TYPE(ge, REL_MATCH_GREATER_EQUAL);
55
COUNT_MATCH_TYPE(lt, REL_MATCH_LESS);
56
COUNT_MATCH_TYPE(le, REL_MATCH_LESS_EQUAL);
57
COUNT_MATCH_TYPE(eq, REL_MATCH_EQUAL);
58
COUNT_MATCH_TYPE(ne, REL_MATCH_NOT_EQUAL);
59
60
/*
61
 * Match-type implementation
62
 */
63
64
static int
65
mcht_count_match(struct sieve_match_context *mctx,
66
     struct sieve_stringlist *value_list,
67
     struct sieve_stringlist *key_list)
68
0
{
69
0
  const struct sieve_runtime_env *renv = mctx->runenv;
70
0
  bool trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING);
71
0
  int count;
72
0
  string_t *key_item;
73
0
  int match, ret;
74
75
0
  count = sieve_stringlist_get_length(value_list);
76
0
  if (count < 0) {
77
0
    mctx->exec_status = value_list->exec_status;
78
0
    return -1;
79
0
  }
80
81
0
  sieve_stringlist_reset(key_list);
82
83
0
  string_t *value = t_str_new(20);
84
0
  str_printfa(value, "%d", count);
85
86
0
  if (trace) {
87
0
    sieve_runtime_trace(renv, 0, "matching count value '%s'",
88
0
            str_sanitize(str_c(value), 80));
89
0
  }
90
91
0
  sieve_runtime_trace_descend(renv);
92
93
  /* Match to all key values */
94
0
  key_item = NULL;
95
0
  match = 0;
96
0
  while (match == 0 &&
97
0
         (ret = sieve_stringlist_next_item(key_list, &key_item)) > 0)
98
0
  {
99
0
    match = mcht_value_match_key(
100
0
      mctx, str_c(value), str_len(value),
101
0
      str_c(key_item), str_len(key_item));
102
103
0
    if (trace) {
104
0
      sieve_runtime_trace(renv, 0, "with key '%s' => %d",
105
0
              str_sanitize(str_c(key_item), 80),
106
0
              ret);
107
0
    }
108
0
  }
109
110
0
  sieve_runtime_trace_ascend(renv);
111
112
0
  if (ret < 0) {
113
0
    mctx->exec_status = key_list->exec_status;
114
0
    match = -1;
115
0
  }
116
0
  return match;
117
0
}