Coverage Report

Created: 2026-04-27 06:39

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