Coverage Report

Created: 2026-08-31 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-binary.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "str.h"
5
6
#include "sieve-common.h"
7
#include "sieve-extensions.h"
8
#include "sieve-error.h"
9
#include "sieve-script.h"
10
#include "sieve-binary.h"
11
#include "sieve-generator.h"
12
#include "sieve-interpreter.h"
13
#include "sieve-dump.h"
14
15
#include "ext-ihave-common.h"
16
#include "ext-ihave-binary.h"
17
18
/*
19
 * Forward declarations
20
 */
21
22
static bool
23
ext_ihave_binary_pre_save(const struct sieve_extension *ext,
24
        struct sieve_binary *sbin, void *context,
25
        enum sieve_error *error_code_r);
26
static bool
27
ext_ihave_binary_open(const struct sieve_extension *ext,
28
          struct sieve_binary *sbin, void *context);
29
static bool
30
ext_ihave_binary_up_to_date(const struct sieve_extension *ext,
31
          struct sieve_binary *sbin, void *context,
32
          enum sieve_compile_flags cpflags);
33
34
/*
35
 * Binary include extension
36
 */
37
38
const struct sieve_binary_extension ihave_binary_ext = {
39
  .extension = &ihave_extension,
40
  .binary_pre_save = ext_ihave_binary_pre_save,
41
  .binary_open = ext_ihave_binary_open,
42
  .binary_up_to_date = ext_ihave_binary_up_to_date,
43
};
44
45
/*
46
 * Binary context management
47
 */
48
49
struct ext_ihave_binary_context {
50
  struct sieve_binary *binary;
51
  struct sieve_binary_block *block;
52
53
  ARRAY(const char *) missing_extensions;
54
};
55
56
static struct ext_ihave_binary_context *
57
ext_ihave_binary_create_context(const struct sieve_extension *this_ext,
58
        struct sieve_binary *sbin)
59
0
{
60
0
  pool_t pool = sieve_binary_pool(sbin);
61
0
  struct ext_ihave_binary_context *ctx =
62
0
    p_new(pool, struct ext_ihave_binary_context, 1);
63
64
0
  ctx->binary = sbin;
65
0
  p_array_init(&ctx->missing_extensions, pool, 64);
66
67
0
  sieve_binary_extension_set(sbin, this_ext, &ihave_binary_ext, ctx);
68
0
  return ctx;
69
0
}
70
71
struct ext_ihave_binary_context *
72
ext_ihave_binary_get_context(const struct sieve_extension *this_ext,
73
           struct sieve_binary *sbin)
74
0
{
75
0
  struct ext_ihave_binary_context *ctx =
76
0
    (struct ext_ihave_binary_context *)
77
0
      sieve_binary_extension_get_context(sbin, this_ext);
78
79
0
  if (ctx == NULL)
80
0
    ctx = ext_ihave_binary_create_context(this_ext, sbin);
81
0
  return ctx;
82
0
}
83
84
struct ext_ihave_binary_context *
85
ext_ihave_binary_init(const struct sieve_extension *this_ext,
86
          struct sieve_binary *sbin, struct sieve_ast *ast)
87
0
{
88
0
  struct ext_ihave_ast_context *ast_ctx =
89
0
    ext_ihave_get_ast_context(this_ext, ast);
90
0
  struct ext_ihave_binary_context *binctx;
91
0
  const char *const *exts;
92
0
  unsigned int i, count;
93
94
0
  binctx = ext_ihave_binary_get_context(this_ext, sbin);
95
96
0
  exts = array_get(&ast_ctx->missing_extensions, &count);
97
0
  if (count > 0) {
98
0
    pool_t pool = sieve_binary_pool(sbin);
99
100
0
    if (binctx->block == NULL) {
101
0
      binctx->block = sieve_binary_extension_create_block(
102
0
        sbin, this_ext);
103
0
    }
104
105
0
    for (i = 0; i < count; i++) {
106
0
      const char *ext_name = p_strdup(pool, exts[i]);
107
108
0
      array_append(&binctx->missing_extensions, &ext_name, 1);
109
0
    }
110
0
  }
111
112
0
  return binctx;
113
0
}
114
115
/*
116
 * Binary extension
117
 */
118
119
static bool
120
ext_ihave_binary_pre_save(const struct sieve_extension *ext,
121
        struct sieve_binary *sbin, void *context,
122
        enum sieve_error *error_code_r ATTR_UNUSED)
123
0
{
124
0
  struct ext_ihave_binary_context *binctx =
125
0
    (struct ext_ihave_binary_context *)context;
126
0
  const char *const *exts;
127
0
  unsigned int count, i;
128
129
0
  exts = array_get(&binctx->missing_extensions, &count);
130
131
0
  if (binctx->block != NULL)
132
0
    sieve_binary_block_clear(binctx->block);
133
134
0
  if (count > 0) {
135
0
    if (binctx->block == NULL) {
136
0
      binctx->block =
137
0
        sieve_binary_extension_create_block(sbin, ext);
138
0
    }
139
140
0
    sieve_binary_emit_unsigned(binctx->block, count);
141
142
0
    for (i = 0; i < count; i++)
143
0
      sieve_binary_emit_cstring(binctx->block, exts[i]);
144
0
  }
145
0
  return TRUE;
146
0
}
147
148
static bool
149
ext_ihave_binary_open(const struct sieve_extension *ext,
150
          struct sieve_binary *sbin, void *context)
151
0
{
152
0
  struct sieve_instance *svinst = ext->svinst;
153
0
  struct ext_ihave_binary_context *binctx =
154
0
    (struct ext_ihave_binary_context *)context;
155
0
  struct sieve_binary_block *sblock;
156
0
  unsigned int i, count, block_id;
157
0
  sieve_size_t offset;
158
159
0
  sblock = sieve_binary_extension_get_block(sbin, ext);
160
161
0
  if (sblock != NULL) {
162
0
    binctx->block = sblock;
163
0
    block_id = sieve_binary_block_get_id(sblock);
164
165
0
    offset = 0;
166
167
    /* Read number of missing extensions to read subsequently */
168
0
    if (!sieve_binary_read_unsigned(sblock, &offset, &count)) {
169
0
      e_error(svinst->event, "ihave: "
170
0
        "failed to read missing extension count "
171
0
        "from block %d of binary %s",
172
0
        block_id, sieve_binary_path(sbin));
173
0
      return FALSE;
174
0
    }
175
176
    /* Read dependencies */
177
0
    for (i = 0; i < count; i++) {
178
0
      string_t *ext_name;
179
0
      const char *name;
180
181
0
      if (!sieve_binary_read_string(sblock, &offset,
182
0
                  &ext_name)) {
183
        /* Binary is corrupt, recompile */
184
0
        e_error(svinst->event, "ihave: "
185
0
          "failed to read missing extension name "
186
0
          "from block %d of binary %s",
187
0
          block_id, sieve_binary_path(sbin));
188
0
        return FALSE;
189
0
      }
190
191
0
      name = str_c(ext_name);
192
0
      array_append(&binctx->missing_extensions, &name, 1);
193
0
    }
194
0
  }
195
196
0
  return TRUE;
197
0
}
198
199
static bool
200
ext_ihave_binary_up_to_date(const struct sieve_extension *ext,
201
          struct sieve_binary *sbin ATTR_UNUSED,
202
          void *context, enum sieve_compile_flags cpflags)
203
0
{
204
0
  struct ext_ihave_binary_context *binctx =
205
0
    (struct ext_ihave_binary_context *)context;
206
0
  const struct sieve_extension *mext;
207
0
  const char *const *mexts;
208
0
  unsigned int count, i;
209
210
0
  mexts = array_get(&binctx->missing_extensions, &count);
211
0
  for (i = 0; i < count; i++) {
212
0
    mext = sieve_extension_get_by_name(ext->svinst, mexts[i]);
213
0
    if (mext != NULL &&
214
0
        ((cpflags & SIEVE_COMPILE_FLAG_NOGLOBAL) == 0 ||
215
0
         !mext->global))
216
0
      return FALSE;
217
0
  }
218
0
  return TRUE;
219
0
}
220
221
/*
222
 * Main extension interface
223
 */
224
225
bool ext_ihave_binary_load(const struct sieve_extension *ext,
226
         struct sieve_binary *sbin)
227
0
{
228
0
  (void)ext_ihave_binary_get_context(ext, sbin);
229
230
0
  return TRUE;
231
0
}
232
233
bool ext_ihave_binary_dump(const struct sieve_extension *ext,
234
         struct sieve_dumptime_env *denv)
235
0
{
236
0
  struct sieve_binary *sbin = denv->sbin;
237
0
  struct ext_ihave_binary_context *binctx =
238
0
    ext_ihave_binary_get_context(ext, sbin);
239
0
  const char *const *exts;
240
0
  unsigned int count, i;
241
242
0
  exts = array_get(&binctx->missing_extensions, &count);
243
244
0
  if (count > 0) {
245
0
    sieve_binary_dump_sectionf(
246
0
      denv, "Extensions missing at compile (block: %d)",
247
0
      sieve_binary_block_get_id(binctx->block));
248
249
0
    for (i = 0; i < count; i++)
250
0
      sieve_binary_dumpf(denv, "  -  %s\n", exts[i]);
251
0
  }
252
253
0
  return TRUE;
254
0
}