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/sieve-storage-settings.c
Line
Count
Source
1
/* Copyright (c) 2024 Pigeonhole authors, see the included COPYING file
2
 */
3
4
#include "lib.h"
5
#include "str-sanitize.h"
6
#include "array.h"
7
#include "sort.h"
8
#include "settings.h"
9
#include "settings-parser.h"
10
11
#include "sieve-script.h"
12
#include "sieve-storage.h"
13
#include "sieve-storage-settings.h"
14
15
static bool
16
sieve_storage_settings_check(void *_set, pool_t pool, const char **error_r);
17
18
#undef DEF
19
#define DEF(type, name) SETTING_DEFINE_STRUCT_##type( \
20
  "sieve_"#name, name, \
21
  struct sieve_storage_settings)
22
23
static const struct setting_filter_array_order sieve_storage_order_precedence = {
24
  .info = &sieve_storage_setting_parser_info,
25
  .field_name = "sieve_script_precedence",
26
};
27
28
static const struct setting_define sieve_storage_setting_defines[] = {
29
  DEF(STR, script_storage),
30
  DEF(UINT, script_precedence),
31
32
  DEF(STR, script_type),
33
  DEF(BOOLLIST, script_cause),
34
  DEF(STR, script_driver),
35
  DEF(STR, script_name),
36
  DEF(STR, script_bin_path),
37
38
  DEF(SIZE, quota_storage_size),
39
  DEF(UINT, quota_script_count),
40
41
  { .type = SET_FILTER_ARRAY, .key = "sieve_script",
42
     .offset = offsetof(struct sieve_storage_settings, storages),
43
     .filter_array_field_name = "sieve_script_storage",
44
     .filter_array_order = &sieve_storage_order_precedence },
45
46
  SETTING_DEFINE_LIST_END,
47
};
48
49
static const struct sieve_storage_settings sieve_storage_default_settings = {
50
  .script_storage = "",
51
  .script_precedence = UINT_MAX,
52
53
  .script_type = SIEVE_STORAGE_TYPE_PERSONAL,
54
  .script_cause = ARRAY_INIT,
55
56
  .script_driver = "file",
57
  .script_name = "",
58
  .script_bin_path = "",
59
60
  .quota_storage_size = SET_SIZE_UNLIMITED,
61
  .quota_script_count = SET_UINT_UNLIMITED,
62
63
  .storages = ARRAY_INIT,
64
};
65
66
const struct setting_parser_info sieve_storage_setting_parser_info = {
67
  .name = "sieve_storage",
68
69
  .defines = sieve_storage_setting_defines,
70
  .defaults = &sieve_storage_default_settings,
71
72
  .struct_size = sizeof(struct sieve_storage_settings),
73
74
  .pool_offset1 = 1 + offsetof(struct sieve_storage_settings, pool),
75
76
  .check_func = sieve_storage_settings_check,
77
};
78
79
/* <settings checks> */
80
static bool
81
sieve_storage_settings_check(void *_set, pool_t pool ATTR_UNUSED,
82
           const char **error_r)
83
0
{
84
0
  struct sieve_storage_settings *set = _set;
85
86
0
  if (*set->script_storage != '\0' &&
87
0
      !sieve_storage_name_is_valid(set->script_storage)) {
88
0
    *error_r = t_strdup_printf(
89
0
      "Invalid script storage name '%s'",
90
0
      str_sanitize(set->script_storage, 128));
91
0
    return FALSE;
92
0
  }
93
0
  if (*set->script_name != '\0' &&
94
0
      !sieve_script_name_is_valid(set->script_name)) {
95
0
    *error_r = t_strdup_printf(
96
0
      "Invalid script name '%s'",
97
0
      str_sanitize(set->script_name, 128));
98
0
    return FALSE;
99
0
  }
100
101
0
  if (set->quota_storage_size == 0) {
102
0
    *error_r = "quota_storage_size must not be 0";
103
0
    return FALSE;
104
0
  }
105
0
  if (set->quota_script_count == 0) {
106
0
    *error_r = "quota_script_count must not be 0";
107
0
    return FALSE;
108
0
  }
109
110
0
  if (array_is_created(&set->script_cause))
111
0
    array_sort(&set->script_cause, i_strcmp_p);
112
113
0
  return TRUE;
114
0
}
115
/* </settings checks> */
116
117
bool sieve_storage_settings_match_script_type(
118
  const struct sieve_storage_settings *set, const char *type)
119
0
{
120
0
  if (strcasecmp(type, SIEVE_STORAGE_TYPE_ANY) == 0)
121
0
    return TRUE;
122
0
  if (strcasecmp(type, set->script_type) == 0)
123
0
    return TRUE;
124
0
  return FALSE;
125
0
}
126
127
bool sieve_storage_settings_match_script_cause(
128
  const struct sieve_storage_settings *set, const char *cause)
129
0
{
130
0
  if (strcasecmp(cause, SIEVE_SCRIPT_CAUSE_ANY) == 0) {
131
    /* Any cause will match */
132
0
    return TRUE;
133
0
  }
134
0
  if (!array_is_created(&set->script_cause)) {
135
    /* Causes are not configured for this storage */
136
0
    if (strcasecmp(set->script_type,
137
0
             SIEVE_STORAGE_TYPE_PERSONAL) == 0) {
138
      /* For personal storages the default is to match any
139
         cause. */
140
0
      return TRUE;
141
0
    }
142
0
    if (strcasecmp(cause, SIEVE_SCRIPT_CAUSE_DELIVERY) == 0) {
143
      /* The default cause is delivery */
144
0
      return TRUE;
145
0
    }
146
0
    return FALSE;
147
0
  }
148
149
  /* Causes are configured for this storage: perform lookup */
150
151
0
  unsigned int set_cause_count;
152
0
  const char *const *set_cause;
153
154
0
  set_cause = array_get(&set->script_cause, &set_cause_count);
155
0
  return (i_bsearch(cause, set_cause, set_cause_count,
156
       sizeof(const char *), search_strcasecmp) != NULL);
157
0
}