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/mailbox/tst-mailboxexists.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-sanitize.h"
6
#include "mail-storage.h"
7
#include "mail-namespace.h"
8
9
#include "sieve-common.h"
10
#include "sieve-actions.h"
11
#include "sieve-extensions.h"
12
#include "sieve-commands.h"
13
#include "sieve-stringlist.h"
14
#include "sieve-code.h"
15
#include "sieve-validator.h"
16
#include "sieve-generator.h"
17
#include "sieve-interpreter.h"
18
#include "sieve-dump.h"
19
20
#include "ext-mailbox-common.h"
21
22
/*
23
 * Mailboxexists command
24
 *
25
 * Syntax:
26
 *    mailboxexists <mailbox-names: string-list>
27
 */
28
29
static bool
30
tst_mailboxexists_validate(struct sieve_validator *valdtr,
31
         struct sieve_command *tst);
32
static bool
33
tst_mailboxexists_generate(const struct sieve_codegen_env *cgenv,
34
         struct sieve_command *ctx);
35
36
const struct sieve_command_def mailboxexists_test = {
37
  .identifier = "mailboxexists",
38
  .type = SCT_TEST,
39
  .positional_args = 1,
40
  .subtests = 0,
41
  .block_allowed = FALSE,
42
  .block_required = FALSE,
43
  .validate = tst_mailboxexists_validate,
44
  .generate = tst_mailboxexists_generate,
45
};
46
47
/*
48
 * Mailboxexists operation
49
 */
50
51
static bool
52
tst_mailboxexists_operation_dump(const struct sieve_dumptime_env *denv,
53
         sieve_size_t *address);
54
static int
55
tst_mailboxexists_operation_execute(const struct sieve_runtime_env *renv,
56
            sieve_size_t *address);
57
58
const struct sieve_operation_def mailboxexists_operation = {
59
  .mnemonic = "MAILBOXEXISTS",
60
  .ext_def = &mailbox_extension,
61
  .dump = tst_mailboxexists_operation_dump,
62
  .execute = tst_mailboxexists_operation_execute,
63
};
64
65
/*
66
 * Test validation
67
 */
68
69
struct _validate_context {
70
  struct sieve_validator *valdtr;
71
  struct sieve_command *tst;
72
};
73
74
static int
75
tst_mailboxexists_mailbox_validate(void *context,
76
           struct sieve_ast_argument *arg)
77
0
{
78
0
  struct _validate_context *valctx =
79
0
    (struct _validate_context *)context;
80
81
0
  if (sieve_argument_is_string_literal(arg)) {
82
0
    const char *mailbox = sieve_ast_argument_strc(arg), *error;
83
84
0
    if (!sieve_mailbox_check_name(mailbox, &error)) {
85
0
      sieve_argument_validate_warning(
86
0
        valctx->valdtr, arg, "%s test: "
87
0
        "invalid mailbox name '%s' specified: %s",
88
0
        sieve_command_identifier(valctx->tst),
89
0
        str_sanitize(mailbox, 256), error);
90
0
    }
91
0
  }
92
93
0
  return 1;
94
0
}
95
96
static bool
97
tst_mailboxexists_validate(struct sieve_validator *valdtr,
98
         struct sieve_command *tst)
99
0
{
100
0
  struct sieve_ast_argument *arg = tst->first_positional;
101
0
  struct sieve_ast_argument *aarg;
102
0
  struct _validate_context valctx;
103
104
0
  if (!sieve_validate_positional_argument(
105
0
    valdtr, tst, arg, "mailbox-names", 1, SAAT_STRING_LIST))
106
0
    return FALSE;
107
108
0
  if (!sieve_validator_argument_activate(valdtr, tst, arg, FALSE))
109
0
    return FALSE;
110
111
0
  aarg = arg;
112
0
  i_zero(&valctx);
113
0
  valctx.valdtr = valdtr;
114
0
  valctx.tst = tst;
115
116
0
  return (sieve_ast_stringlist_map(
117
0
    &aarg, &valctx,
118
0
    tst_mailboxexists_mailbox_validate) >= 0);
119
0
}
120
121
/*
122
 * Test generation
123
 */
124
125
static bool
126
tst_mailboxexists_generate(const struct sieve_codegen_env *cgenv,
127
         struct sieve_command *tst)
128
0
{
129
0
  sieve_operation_emit(cgenv->sblock, tst->ext, &mailboxexists_operation);
130
131
  /* Generate arguments */
132
0
  return sieve_generate_arguments(cgenv, tst, NULL);
133
0
}
134
135
/*
136
 * Code dump
137
 */
138
139
static bool
140
tst_mailboxexists_operation_dump(const struct sieve_dumptime_env *denv,
141
         sieve_size_t *address)
142
0
{
143
0
  sieve_code_dumpf(denv, "MAILBOXEXISTS");
144
0
  sieve_code_descend(denv);
145
146
0
  return sieve_opr_stringlist_dump(denv, address, "mailbox-names");
147
0
}
148
149
/*
150
 * Code execution
151
 */
152
153
static int
154
tst_mailboxexists_test_mailbox(const struct sieve_runtime_env *renv,
155
             const char *mailbox, bool trace,
156
             bool *all_exist_r)
157
0
{
158
0
  const struct sieve_execute_env *eenv = renv->exec_env;
159
0
  struct mailbox *box;
160
0
  const char *error;
161
162
  /* Check validity of mailbox name */
163
0
  if (!sieve_mailbox_check_name(mailbox, &error)) {
164
0
    sieve_runtime_warning(
165
0
      renv, NULL, "mailboxexists test: "
166
0
      "invalid mailbox name '%s' specified: %s",
167
0
      str_sanitize(mailbox, 256), error);
168
0
    *all_exist_r = FALSE;
169
0
    return SIEVE_EXEC_OK;
170
0
  }
171
172
  /* Open the box */
173
0
  box = mailbox_alloc_for_user(eenv->scriptenv->user,
174
0
             mailbox,
175
0
             MAILBOX_FLAG_POST_SESSION);
176
177
0
  if (mailbox_open(box) < 0) {
178
0
    if (trace) {
179
0
      sieve_runtime_trace(
180
0
        renv, 0,
181
0
        "mailbox '%s' cannot be opened",
182
0
        str_sanitize(mailbox, 80));
183
0
    }
184
0
    mailbox_free(&box);
185
0
    *all_exist_r = FALSE;
186
0
    return SIEVE_EXEC_OK;
187
0
  }
188
189
  /* Also fail when it is readonly */
190
0
  if (mailbox_is_readonly(box)) {
191
0
    if (trace) {
192
0
      sieve_runtime_trace(
193
0
        renv, 0,
194
0
        "mailbox '%s' is read-only",
195
0
        str_sanitize(mailbox, 80));
196
0
    }
197
0
    mailbox_free(&box);
198
0
    *all_exist_r = FALSE;
199
0
    return SIEVE_EXEC_OK;
200
0
  }
201
202
  /* FIXME: check acl for 'p' or 'i' ACL permissions as
203
     required by RFC */
204
205
0
  if (trace) {
206
0
    sieve_runtime_trace(
207
0
      renv, 0, "mailbox '%s' exists",
208
0
      str_sanitize(mailbox, 80));
209
0
  }
210
211
  /* Close mailbox */
212
0
  mailbox_free(&box);
213
0
  return SIEVE_EXEC_OK;
214
0
}
215
216
static int
217
tst_mailboxexists_operation_execute(const struct sieve_runtime_env *renv,
218
            sieve_size_t *address)
219
0
{
220
0
  const struct sieve_execute_env *eenv = renv->exec_env;
221
0
  struct sieve_stringlist *mailbox_names;
222
0
  string_t *mailbox_item;
223
0
  bool trace = FALSE;
224
0
  bool all_exist = TRUE;
225
0
  int ret;
226
227
  /*
228
   * Read operands
229
   */
230
231
  /* Read notify uris */
232
0
  ret = sieve_opr_stringlist_read(renv, address, "mailbox-names",
233
0
          &mailbox_names);
234
0
  if (ret <= 0)
235
0
    return ret;
236
237
  /*
238
   * Perform operation
239
   */
240
241
0
  if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS)) {
242
0
    sieve_runtime_trace(renv, 0, "mailboxexists test");
243
0
    sieve_runtime_trace_descend(renv);
244
245
0
    trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING);
246
0
  }
247
248
0
  if (eenv->scriptenv->user == NULL) {
249
0
    sieve_runtime_trace(renv, 0, "no mail user; yield true");
250
0
    sieve_interpreter_set_test_result(renv->interp, TRUE);
251
0
    return SIEVE_EXEC_OK;
252
0
  }
253
254
0
  mailbox_item = NULL;
255
0
  while (all_exist &&
256
0
         (ret = sieve_stringlist_next_item(mailbox_names,
257
0
             &mailbox_item)) > 0) {
258
0
    const char *mailbox = str_c(mailbox_item);
259
260
0
    ret = tst_mailboxexists_test_mailbox(renv, mailbox,
261
0
                 trace, &all_exist);
262
0
    if (ret <= 0)
263
0
      return ret;
264
0
  }
265
266
0
  if (ret < 0) {
267
0
    sieve_runtime_trace_error(
268
0
      renv, "invalid mailbox name item");
269
0
    return SIEVE_EXEC_BIN_CORRUPT;
270
0
  }
271
272
0
  if (trace) {
273
0
    if (all_exist) {
274
0
      sieve_runtime_trace(renv, 0,
275
0
              "all mailboxes are available");
276
0
    } else {
277
0
      sieve_runtime_trace(renv, 0,
278
0
              "some mailboxes are unavailable");
279
0
    }
280
0
  }
281
282
0
  sieve_interpreter_set_test_result(renv->interp, all_exist);
283
0
  return SIEVE_EXEC_OK;
284
0
}