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