Coverage Report

Created: 2026-07-30 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/plugins/subaddress/ext-subaddress.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
/* Extension subaddress
4
 * --------------------
5
 *
6
 * Author: Stephan Bosch
7
 * Specification: RFC 3598
8
 * Implementation: full
9
 * Status: testing
10
 *
11
 */
12
13
#include "lib.h"
14
#include "settings.h"
15
16
#include "sieve-common.h"
17
#include "sieve-code.h"
18
#include "sieve-address.h"
19
#include "sieve-extensions.h"
20
#include "sieve-commands.h"
21
#include "sieve-address-parts.h"
22
#include "sieve-validator.h"
23
#include "sieve-generator.h"
24
#include "sieve-interpreter.h"
25
26
#include "ext-subaddress-settings.h"
27
28
#include <string.h>
29
30
/*
31
 * Configuration
32
 */
33
34
struct ext_subaddress_context {
35
  const struct ext_subaddress_settings *set;
36
};
37
38
/*
39
 * Forward declarations
40
 */
41
42
const struct sieve_address_part_def user_address_part;
43
const struct sieve_address_part_def detail_address_part;
44
45
static struct sieve_operand_def subaddress_operand;
46
47
/*
48
 * Extension
49
 */
50
51
static int
52
ext_subaddress_load(const struct sieve_extension *ext, void **context);
53
static void ext_subaddress_unload(const struct sieve_extension *ext);
54
static bool
55
ext_subaddress_validator_load(const struct sieve_extension *ext,
56
            struct sieve_validator *validator);
57
58
const struct sieve_extension_def subaddress_extension = {
59
  .name = "subaddress",
60
  .load = ext_subaddress_load,
61
  .unload = ext_subaddress_unload,
62
  .validator_load = ext_subaddress_validator_load,
63
  SIEVE_EXT_DEFINE_OPERAND(subaddress_operand),
64
};
65
66
static int
67
ext_subaddress_load(const struct sieve_extension *ext, void **context_r)
68
0
{
69
0
  struct sieve_instance *svinst = ext->svinst;
70
0
  const struct ext_subaddress_settings *set;
71
0
  struct ext_subaddress_context *extctx;
72
0
  const char *error;
73
74
0
  if (settings_get(svinst->event, &ext_subaddress_setting_parser_info, 0,
75
0
       &set, &error) < 0) {
76
0
    e_error(svinst->event, "%s", error);
77
0
    return -1;
78
0
  }
79
80
0
  extctx = i_new(struct ext_subaddress_context, 1);
81
0
  extctx->set = set;
82
83
0
  *context_r = extctx;
84
0
  return 0;
85
0
}
86
87
static void ext_subaddress_unload(const struct sieve_extension *ext)
88
0
{
89
0
  struct ext_subaddress_context *extctx = ext->context;
90
91
0
  if (extctx == NULL)
92
0
    return;
93
0
  settings_free(extctx->set);
94
0
  i_free(extctx);
95
0
}
96
97
static bool
98
ext_subaddress_validator_load(const struct sieve_extension *ext,
99
            struct sieve_validator *validator)
100
0
{
101
0
  sieve_address_part_register(validator, ext, &user_address_part);
102
0
  sieve_address_part_register(validator, ext, &detail_address_part);
103
104
0
  return TRUE;
105
0
}
106
107
/*
108
 * Address parts
109
 */
110
111
enum ext_subaddress_address_part {
112
  SUBADDRESS_USER,
113
  SUBADDRESS_DETAIL
114
};
115
116
/* Forward declarations */
117
118
static const char *
119
subaddress_user_extract_from(const struct sieve_address_part *addrp,
120
           const struct smtp_address *address);
121
static const char *
122
subaddress_detail_extract_from(const struct sieve_address_part *addrp,
123
             const struct smtp_address *address);
124
125
/* Address part objects */
126
127
const struct sieve_address_part_def user_address_part = {
128
  SIEVE_OBJECT("user", &subaddress_operand, SUBADDRESS_USER),
129
  subaddress_user_extract_from,
130
};
131
132
const struct sieve_address_part_def detail_address_part = {
133
  SIEVE_OBJECT("detail", &subaddress_operand, SUBADDRESS_DETAIL),
134
  .extract_from = subaddress_detail_extract_from,
135
};
136
137
/* Address part implementation */
138
139
static const char *
140
subaddress_user_extract_from(const struct sieve_address_part *addrp,
141
           const struct smtp_address *address)
142
0
{
143
0
  struct ext_subaddress_context *extctx = addrp->object.ext->context;
144
0
  const char *delim;
145
0
  size_t idx;
146
147
0
  idx = strcspn(address->localpart, extctx->set->recipient_delimiter);
148
0
  delim = (address->localpart[idx] != '\0' ?
149
0
     address->localpart + idx : NULL);
150
151
0
  if (delim == NULL)
152
0
    return address->localpart;
153
154
0
  return t_strdup_until(address->localpart, delim);
155
0
}
156
157
static const char *
158
subaddress_detail_extract_from(const struct sieve_address_part *addrp,
159
             const struct smtp_address *address)
160
0
{
161
0
  struct ext_subaddress_context *extctx = addrp->object.ext->context;
162
0
  const char *delim;
163
0
  size_t idx;
164
165
0
  idx = strcspn(address->localpart, extctx->set->recipient_delimiter);
166
0
  delim = (address->localpart[idx] != '\0' ?
167
0
     address->localpart + idx + 1: NULL);
168
169
  /* Just to be sure */
170
0
  if (delim == NULL ||
171
0
      delim > (address->localpart + strlen(address->localpart)))
172
0
    return NULL;
173
0
  return delim;
174
0
}
175
176
/*
177
 * Operand
178
 */
179
180
const struct sieve_address_part_def *ext_subaddress_parts[] = {
181
  &user_address_part,
182
  &detail_address_part,
183
};
184
185
static const struct sieve_extension_objects ext_address_parts =
186
  SIEVE_EXT_DEFINE_ADDRESS_PARTS(ext_subaddress_parts);
187
188
static struct sieve_operand_def subaddress_operand = {
189
  .name = "address-part",
190
  .ext_def = &subaddress_extension,
191
  .class = &sieve_address_part_operand_class,
192
  .interface = &ext_address_parts,
193
};