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/plugins/editheader/ext-editheader-common.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "mempool.h"
5
#include "array.h"
6
#include "settings.h"
7
8
#include "rfc2822.h"
9
10
#include "sieve-common.h"
11
#include "sieve-error.h"
12
#include "sieve-extensions.h"
13
14
#include "ext-editheader-limits.h"
15
#include "ext-editheader-settings.h"
16
#include "ext-editheader-common.h"
17
18
/*
19
 * Extension configuration
20
 */
21
22
struct ext_editheader_header {
23
  const char *name;
24
25
  bool forbid_add:1;
26
  bool forbid_delete:1;
27
};
28
29
struct ext_editheader_context {
30
  pool_t pool;
31
  const struct ext_editheader_settings *set;
32
33
  ARRAY(struct ext_editheader_header) headers;
34
35
  size_t max_header_size;
36
};
37
38
static const struct ext_editheader_header *
39
ext_editheader_header_find(struct ext_editheader_context *extctx,
40
         const char *hname)
41
0
{
42
0
  const struct ext_editheader_header *header;
43
44
0
  if (extctx == NULL)
45
0
    return NULL;
46
47
0
  array_foreach(&extctx->headers, header) {
48
0
    if (strcasecmp(hname, header->name) == 0)
49
0
      return header;
50
0
  }
51
0
  return NULL;
52
0
}
53
54
static int
55
ext_editheader_header_add(struct sieve_instance *svinst,
56
        struct ext_editheader_context *extctx,
57
        const char *hname)
58
0
{
59
0
  struct ext_editheader_header *header;
60
0
  const struct ext_editheader_header_settings *set;
61
0
  const char *error;
62
63
0
  if (settings_get_filter(svinst->event, "sieve_editheader_header", hname,
64
0
        &ext_editheader_header_setting_parser_info, 0,
65
0
        &set, &error) < 0) {
66
0
    e_error(svinst->event, "%s", error);
67
0
    return -1;
68
0
  }
69
70
0
  i_assert(ext_editheader_header_find(extctx, hname) == NULL);
71
72
0
  header = array_append_space(&extctx->headers);
73
0
  header->name = p_strdup(extctx->pool, hname);
74
0
  header->forbid_add = set->forbid_add;
75
0
  header->forbid_delete = set->forbid_delete;
76
77
0
  settings_free(set);
78
0
  return 0;
79
0
}
80
81
static int
82
ext_editheader_config_headers(struct sieve_instance *svinst,
83
            struct ext_editheader_context *extctx)
84
0
{
85
0
  const char *hname;
86
87
0
  if (!array_is_created(&extctx->set->headers))
88
0
    return 0;
89
90
0
  array_foreach_elem(&extctx->set->headers, hname) {
91
0
    if (ext_editheader_header_add(svinst, extctx, hname) < 0)
92
0
      return -1;
93
0
  }
94
0
  return 0;
95
0
}
96
97
int ext_editheader_load(const struct sieve_extension *ext, void **context_r)
98
0
{
99
0
  struct sieve_instance *svinst = ext->svinst;
100
0
  const struct ext_editheader_settings *set;
101
0
  struct ext_editheader_context *extctx;
102
0
  const char *error;
103
0
  pool_t pool;
104
105
0
  if (settings_get(svinst->event, &ext_editheader_setting_parser_info, 0,
106
0
       &set, &error) < 0) {
107
0
    e_error(svinst->event, "%s", error);
108
0
    return -1;
109
0
  }
110
111
0
  pool = pool_alloconly_create("editheader_config", 1024);
112
0
  extctx = p_new(pool, struct ext_editheader_context, 1);
113
0
  extctx->pool = pool;
114
0
  extctx->set = set;
115
0
  p_array_init(&extctx->headers, pool, 16);
116
117
0
  if (ext_editheader_config_headers(svinst, extctx) < 0) {
118
0
    settings_free(set);
119
0
    pool_unref(&pool);
120
0
    return -1;
121
0
  }
122
123
0
  *context_r = extctx;
124
0
  return 0;
125
0
}
126
127
void ext_editheader_unload(const struct sieve_extension *ext)
128
0
{
129
0
  struct ext_editheader_context *extctx = ext->context;
130
131
0
  if (extctx == NULL)
132
0
    return;
133
0
  settings_free(extctx->set);
134
0
  pool_unref(&extctx->pool);
135
0
}
136
137
/*
138
 * Protected headers
139
 */
140
141
bool ext_editheader_header_allow_add(const struct sieve_extension *ext,
142
             const char *hname)
143
0
{
144
0
  struct ext_editheader_context *extctx = ext->context;
145
0
  const struct ext_editheader_header *header;
146
147
0
  if (strcasecmp(hname, "subject") == 0)
148
0
    return TRUE;
149
0
  if (strcasecmp(hname, "x-sieve-redirected-from") == 0)
150
0
    return FALSE;
151
152
0
  header = ext_editheader_header_find(extctx, hname);
153
0
  if (header == NULL)
154
0
    return TRUE;
155
156
0
  return !header->forbid_add;
157
0
}
158
159
bool ext_editheader_header_allow_delete(const struct sieve_extension *ext,
160
          const char *hname)
161
0
{
162
0
  struct ext_editheader_context *extctx = ext->context;
163
0
  const struct ext_editheader_header *header;
164
165
0
  if (strcasecmp(hname, "received") == 0 ||
166
0
      strcasecmp(hname, "auto-submitted") == 0)
167
0
    return FALSE;
168
0
  if (strcasecmp(hname, "x-sieve-redirected-from") == 0)
169
0
    return FALSE;
170
0
  if (strcasecmp(hname, "subject") == 0)
171
0
    return TRUE;
172
173
0
  header = ext_editheader_header_find(extctx, hname);
174
0
  if (header == NULL)
175
0
    return TRUE;
176
177
0
  return !header->forbid_delete;
178
0
}
179
180
/*
181
 * Limits
182
 */
183
184
bool ext_editheader_header_too_large(const struct sieve_extension *ext,
185
             size_t size)
186
0
{
187
0
  struct ext_editheader_context *extctx = ext->context;
188
189
0
  if (extctx == NULL)
190
0
    return size > EXT_EDITHEADER_DEFAULT_MAX_HEADER_SIZE;
191
192
0
  return (size > extctx->set->max_header_size);
193
0
}